Bullet Physics: Body moves after fall (shakes and moves to the side) - c++

I have a problem that I'm strugling to solve for a few days.
I'm trying to make a bowling game using bullet physics, but the pin shakes, jiggles and moves to the side after I position it and it falls to the floor.
Here is a GIF of what happens:
http://imgur.com/7Mg41sf
Here is how I create a Pin:
btCollisionShape* shape = createShape(pinVertices);
btScalar bodyMass = 1.6f;
btVector3 bodyInertia(0,0,0);
shape->calculateLocalInertia(bodyMass, bodyInertia);
btRigidBody::btRigidBodyConstructionInfo bodyCI = btRigidBody::btRigidBodyConstructionInfo(bodyMass, nullptr, shape, bodyInertia);
bodyCI.m_restitution = 0.7;
bodyCI.m_friction = 0.9f;
_physicsBody = std::unique_ptr<btRigidBody>(new btRigidBody(bodyCI));
_physicsBody->setUserPointer(this);
And here is how I create a floor:
btCollisionShape* shape = createShape(laneVertices);
btScalar bodyMass = 0.0f;
btVector3 bodyInertia(0,0,0);
shape->calculateLocalInertia(bodyMass, bodyInertia);
btRigidBody::btRigidBodyConstructionInfo bodyCI = btRigidBody::btRigidBodyConstructionInfo(bodyMass, nullptr, shape, bodyInertia);
bodyCI.m_restitution = 0.6;
bodyCI.m_friction = 0.5;
_physicsBody = std::unique_ptr<btRigidBody>(new btRigidBody(bodyCI));
_physicsBody->setUserPointer(this);
Right now the floor is a btBoxShape and a pin is a btConvexHullShape, but I've tried using cylinder or cone and they also slide.
Been struggling for few days especially taking into account Bullet Physics website and forum are down.

Looks entirely reasonable to me. A rigid body isn't exactly going to bounce back up, nor is it going to shatter.
You have further issues with the imperfect approximation of reality. The bottom of your pin is probably flat, which means it theoretically hits the floor instantly over multiple points. Furthermore, due to the limited FP accuracy, the pin won't be exactly round, but then that part is realistic.
So the horizontal movements are probably because the small bit of freefall introduced a minor deviation from pure vertical fall. When hitting the ground this component wasn't cancelled, but the friction on moving did eventually bring the pin to a halt. Since the pin had only a small horizontal speed, the friction was not enough to topple the pin.

Perhaps you should set the restitution (bounce) of the pin and floor to something lower (try first with 0.0) This should solve it if the pin is bouncing.
Another thing you could try is to deactivate the pin after creating it. I don't know in Bullet, but in JBullet it's done like this:
body.setActivationState( CollisionObject.WANTS_DEACTIVATION );
This will stop your pin until some other object like the ball or other pin hits it.

Related

Scaling rolling ball controls with it's size

I am editing the rollingball example map from Unreal (in Unreal Engine). I changed it so my ball you grow and melt (it's a snowball), gaining and losing size and mass.
My problem is the control of it. The example map moves the ball by adding torque. My problem is that my mass changes a lot, so I need a torque the changes depending on the size of my ball (not 1:1 as a bigger snowball should still moves slower).
My problem is that my ball seems to accumulate torque and spins a lot (I added a lot of friction to the ball, it did not helped, it just moved the problem a bit). As an example, if I press left for a while, it's gonna go left. Then if I press right, it goes right. But when I stop pressing right, it spins and goes left again.
This is my current code:
void ASnowballBall::MoveRight(float Val)
{
const FVector Torque = FVector(-1.f * getNewTorque(Val), 0.f, 0.f);
Ball->AddTorque(SpringArm->GetComponentRotation().RotateVector(Torque));
}
void ASnowballBall::MoveForward(float Val)
{
const FVector Torque = FVector(0.f, getNewTorque(Val), 0.f);
Ball->AddTorque(SpringArm->GetComponentRotation().RotateVector(Torque));
}
float ASnowballBall::getNewTorque(float Val)
{
return (Val * RollTorque * (log2(Ball->GetMass()))) / 10000;
}
Note: The log was a test to increase the torque slowly with the mass. It's not working well at all. Right now I am using return Val * RollTorque instead, but it's almost as bad.
The control is horrible and I would like to get an idea on how to fix it. If removing the torque would be better, I will change it. I simply want a responsive control that is fun, and where the player still have a sense of the size of the ball (slower when big compared to small).
PS: My original mass is about 500 kg and can go up to 20 000 kg (it's a puzzle game). I did not set the original mass, it's set by Unreal relative to it's size. I could change the mass scale though.
You could try using AddForce instead of AddTorque.
So the speed of the ball is modified every tick like this:
void APlayerBallBearing::Tick(float deltaSeconds)
{
Super::Tick(deltaSeconds);
BallMesh->AddForce(FVector(InputLongitude, InputLatitude, 0.0f) * ControllerForce * BallMesh->GetMass());
}
InputLongitude and InputLatitude are the values that are put in by the user in the current frame for movement in cardinal directions, they correspond to your MoveForward and MoveRight values I reckon.
The controller force is something you need to tweak in order to find the right value for your ball movement. With a value of at least 600.0f I started getting "decent" behaviour.
I cannot help you with the mass though you would need to try that out yourself, the default mass of the ball mesh I used was ~110.

Calculate Torque Required To Align Two 3D Vectors with Constant Acceleration?

I'm currently building a simplified Reaction Control System for a Satellite game, and need a way to use the system to align the satellite to a given unit direction in world-space coordinates. Because this is a game simulation, I am faking the system and just applying a torque force around the objects epicenter.
This is difficult because in my case, the Torque cannot be varied in strength, it is either on or off. It's either full force or no force. Calculating the direction that the torque needs to be applied in is relatively easy, but I'm having trouble getting it to align perfectly without spinning out of control and getting stuck in a logical loop. it needs to apply the opposing force at precisely the right 'time' to land on the target orientation with zero angular velocity.
What I've determined so far is that I need to calculate the 'time' it will take to reach zero velocity based on my current angular velocity and the angle between the two vectors. If that exceeds the time until I reach angle zero, then it needs to apply the opposing torque. In theory this will also prevent it from 'bouncing' around the axis too much. I almost have it working, but in some cases it seems to get stuck applying force in one direction, so I'm hoping somebody can check the logic. My simulation does NOT take mass into account at the moment, so you can ignore the Inertia Tensor (unless it makes the calculation easier!)
For one axis, I'm currently doing it this way, but I figure someone will have a far more elegant solution that can actually compute both Yaw and Pitch axes at once (Roll is invalid).
Omega = Angular Velocity in Local-Space (Degrees Per Second)
Force = Strength of the Thrusters
// Calculate Time Variables
float Angle = AcosD(DotProduct(ForwardVector, DirectionVector));
float Time1 = Abs(Angle / Omega.Z); // Time taken to reach angle 0 at current velocity
float Time2 = Abs(DeltaTime * (Omega.Z / Force); // Time it will take to reach Zero velocity based on force strength.
// Calculate Direction we need to apply the force to rotate toward the target direction. Note that if we are at perfect opposites, this will be zero!
float AngleSign = Sign(DotProduct(RightVector, DirectionVector));
float Torque.Z = 0;
if (Time1 < Time2)
{
Torque.Z = AngleSign * Force;
}
else
{
Torque.Z = AngleSign * Force * -1.0f
}
// Torque is applied to object as a change in acceleration (no mass) and modified by DeltaSeconds for frame-rate independent force.
This is far from elegant and there are definitely some sign issues. Do you folks know a better way to achieve this?
EDIT:
If anybody understands Unreal Engine's Blueprint system, this is how I'm currently prototyping it before I move it to C++
Beginning from the "Calculate Direction" line, you could instead directly compute the correction torque vector in 3D, then modify its sign if you know that the previous correction is about to overshoot:
// Calculate Direction we need to apply the force to rotate toward the target direction
Torque = CrossProduct(DirectionVector, ForwardVector)
Torque = Normalize(Torque) * Force
if (Time2 < Time1)
{
Torque = -Torque
}
But you should handle the problematic cases:
// Calculate Direction we need to apply the force to rotate toward the target direction
Torque = CrossProduct(DirectionVector, ForwardVector)
if (Angle < 0.1 degrees)
{
// Avoid divide by zero in Normalize
Torque = {0, 0, 0}
}
else
{
// Handle case of exactly opposite direction (where CrossProduct is zero)
if (Angle > 179.9 degrees)
{
Torque = {0, 0, 1}
}
Torque = Normalize(Torque) * Force
if (Time2 < Time1)
{
Torque = -Torque
}
}
Okay well what i take from the pseudocode above is that you want to start braking when the time needed to break exceeds the time left till angle 0 is reached. Have you tried to slowly start breaking (in short steps because of the constant torque) BEFORE the time to break exceeds the time till angle 0?
When you do so and your satellite is near angle 0 and the velocity very low, you can just set velocity and angle to 0 so it doesn't wobble around anymore.
Did you ever figure this out? I'm working on a similar problem in UE4. I also have a constant force. I'm rotating to a new forward vector. I've realized time can't be predicted. Take for example you're rotating on Z axis at 100 degrees/second and a reverse force in exactly .015 seconds will nail your desired rotation and velocity but the next frame takes .016 seconds to render and you've just overshot it since you aren't changing your force. I think the solution is something like cheating by manually setting the forward vector once velocity is zeroed out.

Use of "mass" in Bullet

I am sorry to ask such a basic question about bullet. However, I am having an issue. Here is the setup:
I have a world with no gravity. When I press a key, a 1x1x1 box is created in the center of the world. When I right click, a box of size 0.05*0.05*0.05 is create at the camera position, and is 'shot' in the direction you are looking. Here is where the trouble begins.
When a small cube hits a large cube, the interaction seems wrong. You would expcet a box 1/8000th the size of another to have very little effect. Yet the large cube goes flying, as if it been with a cube of its same size. I assumed it is because I created both objects with the same mass.
To confirm this, I apply an upward force of 1 newton (or whatever unit bullet uses). Both objects accelerate at the same rate.
My code for creating objects is as follows:
btMotionState *state = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 0, 0)));
btConvexHullShape* shape = new btConvexHullShape();
for(unsigned int i = 0; i < vertices.size(); ++i) {
shape->addPoint(toBt(vertices[i]));
}
shape->setMargin(0.01f);
btScalar mass = 1.f;
btVector3 inertia;
shape->calculateLocalInertia(mass, inertia);
shape->setMargin(0.01f);
btRigidBody::btRigidBodyConstructionInfo ci(mass, state, shape, inertia);
body = new btRigidBody(ci);
I expect that the btScalar mass = 1.f; line is the culprit.
Am I expected to calculate the mass of my objects? This is simple enough for a cube, but what about some weird convex shape? Is there any way I can get bullet to do this for me?
Yes, mass is the culprit. Think about your big box being an empty wooden crate and your small box being a solid cube of iron. Huge difference in size but equal mass. Now your physics seem correct, right?
Yes, you are expected to provide the mass. Whether you calculate it or just state "this box weighs 20kg" is up to you. Actually expecting someone else to calculate the mass for you just makes your problem worse, because you'd have to specify materials, material density, and material distribution of your objects besides its geometry. If you want to go that way there are plenty of other tools available to aid you with such calculations. But I'm sure you agree that just stating some mass through trial and error is easier by far.

Manipulating sprite movement in box2d

For the past days, I've been trying to make a ping pong like game. I have 2 paddles and a ball. All dynamic sprites. Everything's been working well except for one issue I'm having. The ball tends to bounce on the same angle at some point. So there would be times when the player can simply move the paddle on a specific part and the game can go on for a while or might be forever, since the ball doesn't change its angular velocity regardless of which part of the paddle it hits. I'm using a combination of linear and angular velocity to keep the ball moving like so:
if(_isPaused == FALSE)
{
_world->Step(dt, 10, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
if(sprite.tag == 2)
{
b2Vec2 dir = b->GetLinearVelocity();
dir.Normalize();
float currentSpeed = dir.Length();
int maxSpeed = 60;
float accelerate = vel;
if(currentSpeed <= maxSpeed)
{
b->SetLinearVelocity(accelerate * dir);
}
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
//Keep sprite from bouncing in a straight angle
b->SetAngularVelocity(_body->GetAngle());
}}}
So my question is, how can I manipulate the angular velocity to keep the ball bouncing on different angles everytime it collides with my paddle? I'm thinking something like getting the current angular velocity then multiplying it with some value but I'm not sure if that's the right way to approach the issue I'm having. Any suggestions or ideas would be greatly appreciated. Thanks in advanced.
The way I see it, you have two options:
Check the location of a collision. If it's close to the top/bottom edge of the paddle, deflect the outgoing velocity by an angular amount proportional to the surface "curvature" at that point. Of course, this is cheating, but if the artwork and code are in agreement, it looks correct. And graphics is "the art of cheating without getting caught".
You could take into account the current velocity of the paddle as well as that of the ball. Eg: if the ball is moving downwards and to the right, and the paddle is moving down, then you can compute the outgoing direction using conservation of linear momentum. Just make sure you restrict the paddle's change in momentum along the horizontal axis to be zero.
Finally, you could combine the above techniques, but now you'd have to use accurate collision detection (not the hack I described in (1) above).
Hope that helps!
A few pointers, you should use SetLinearVelocity() and SetAngularVelocity() rarely. Each alters a property of the body definition, which could make you run into problems later on when things get more complex. It would be better to use ApplyForceToCenter() or ApplyLinearImpulse() in the place of SetLinearVelocity() as these two are much more versatile functions and are a bit more coder-friendly. In my opinion, I don't think you should use b->SetAngularVelocity(_body->GetAngle()); If you wanted to change the angular velocity each time it collided, you could, in your beginContact method, write that every time the body collides with the paddle body, a random angular impulse is applied to the ball, using ApplyAngularImpulse().Hope that helps.

fixture density of 0 is not working?

i have a fixture which i set his density to 0 , but he is falling down as he HAS a weight .
b2PolygonShape spriteShape; //b2polygon-for box shape
spriteShape.SetAsBox(fruit2.contentSize.width/PTM_RATIO/10,fruit2.contentSize.height/PTM_RATIO/10); //for b2polygon
b2FixtureDef spriteShapeDef;
spriteShapeDef.shape = &spriteShape;
spriteShapeDef.density = 0.0;
the world g is -9.8 as usual.
How i set this fixture to fall down slowly ? why density of 0/1/2 doesnt do that ?
thanks
How do you want it to react? Do you want it to kind of float down like a feather? A feather floats down slowly because it has the force of the air pushing it back up. So in other words, apply a small enough force upwards on the object that it falls slowly, but doesn't go up. A very low density object will still fall fast without an opposing force to slow it down.