[Bullet] Bad performance or I get stuck inside something

Started by
7 comments, last by mind in a box 13 years, 9 months ago
Hi!

I've made a little platformer using Bullet and I ran into a problem.

It is this line of code I think:
Physics.DynamicsWorld->stepSimulation(FPS.GetElapsedTime(),10,1.0f/60.0f);


When it is like this, my player gets stuck inside the levelblocks easily (Jumping and falling is enough):



And other blocks do that, too. And there is now way for the player to get out there (Without cheating).

When I change the line to
Physics.DynamicsWorld->stepSimulation(FPS.GetElapsedTime(),1000,1.0f/500.0f);


this doesn't happen, but the physics is horrible slow then (When many rigid bodys are around).

What can I do now? First time using Bullet [smile]

(Cross post from here)
Advertisement
Never used Bullet, but from my understanding of the parameters, they control the timestep of the physics calculations, and what you're doing in the second line is increasing the "resolution" ~x100, so that's why it's so slow - maybe try playing more with the params?

Thats all i got ;)
It looks like he is stuck between two blocks. How is your character actually controlled, and how is he represented in the world? He should be a block, and you should control him by applying forces to his rigid body.
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!
The three parameter of stepSimulation are
- timestep
- maxSteps
- fixTimestepSize

Bullet will simulate the world in small timesteps each of the fixes size of fixTimestepSize until it reaches the complete "timestep".

Example:
You have a fixed timestep of 1/60s ~ 16 ms and your elapsed time is 1s = 1000ms, then bullet will try to take 60 steps (each 16ms) until it reached 1000ms. The maxSteps parameter tells bullet to stop after X sub steps, in your case after 10 steps.

Smaller sub steps will lead to a more accurate simluation, but will be slower on the other hand.

When your games runs with 30 fps, the average elapse time will be 1/30s=33ms. I would sugguest a fixed timestep of 10ms = 1/100s and a max of 5 steps:
Physics.DynamicsWorld->stepSimulation(FPS.GetElapsedTime(),5,1.0f/100.0f);
Edit: Ashaman73, you Ninja'd me [smile]

Quote:
Never used Bullet, but from my understanding of the parameters, they control the timestep of the physics calculations, and what you're doing in the second line is increasing the "resolution" ~x100, so that's why it's so slow - maybe try playing more with the params?

Thats all i got ;)


I've done a lot of testing here. And I came to the conclusions that I can have either a good performance, or physics blocks which don't get sink into each other.

Quote:It looks like he is stuck between two blocks.



Quote:
How is your character actually controlled, and how is he represented in the world? He should be a block, and you should control him by applying forces to his rigid body.


It is a physics block, and I do it as you said. This "bug" isn't limited to the playerblock. All dynamic blocks do have the same issue.
I do from larger ones. Isn't there any interpolation between frames in bullet?
What are the masses and sizes of your blocks and character? Bullet doesn't deal well with two objects that have very different masses or objects that are very small.

Might also want to think about using a a fixed timestep for you physics. As seen in this article.

If you are using a motionstate to construct your rigid bodies then they should be interpolated between frames.

Might think about using a kinematic object for your character instead of a rigid body. Continually applying forces to a rigid body probably will never give you a true sidescroller feel. And might be a cause of your issue.

Might also want to take a look at Box2D.

Posing your Bullet initialization and rigid body creation would be helpful too. I would suspect there is something wrong in one of those.
Quote:
What are the masses and sizes of your blocks and character? Bullet doesn't deal well with two objects that have very different masses or objects that are very small.


As far I know they are 1. I just copied most of the code from the samples because this is my first time using bullet.

Quote:
Might also want to think about using a a fixed timestep for you physics. As seen in this article.


Doesn't this give me the same issue as I have currently? Bad performace or stucking inside something?

Quote:
Might think about using a kinematic object for your character instead of a rigid body. Continually applying forces to a rigid body probably will never give you a true sidescroller feel. And might be a cause of your issue.


What is that, and how does it differ from a regular rigid body? I've read somewhere that this is something which collides with other rigid bodys, but the rigid bodys don't collide with it or something like that. But I need that two-way collision. (If I'm right here[smile])

Quote:
Might also want to take a look at Box2D.


I make this game because I want to use bullet in my larger project. You can see it as a "testing-game" but it is still a game!

Quote:
Posing your Bullet initialization and rigid body creation would be helpful too. I would suspect there is something wrong in one of those.


I guess here's the problem, too. Here it is:

Main initialization:
PhysicalComponent::PhysicalComponent(void){	DefaultGravity=D3DXVECTOR3(0,900,0);	///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.	CollisionConfiguration = new btDefaultCollisionConfiguration();		///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)	Dispatcher = new	btCollisionDispatcher(CollisionConfiguration);	///btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.	OverlappingPairCache = new btDbvtBroadphase();	///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)	Solver = new btSequentialImpulseConstraintSolver;	DynamicsWorld = new btDiscreteDynamicsWorld(Dispatcher,OverlappingPairCache,Solver,CollisionConfiguration);	DynamicsWorld->setGravity(*(btVector3*)&DefaultGravity);	Simplex = new btVoronoiSimplexSolver();	pdSolver = new btMinkowskiPenetrationDepthSolver();	ConvexAlgo2d = new btConvex2dConvex2dAlgorithm::CreateFunc(Simplex,pdSolver);	Dispatcher->registerCollisionCreateFunc(CONVEX_2D_SHAPE_PROXYTYPE,CONVEX_2D_SHAPE_PROXYTYPE,ConvexAlgo2d);	Dispatcher->registerCollisionCreateFunc(BOX_2D_SHAPE_PROXYTYPE,CONVEX_2D_SHAPE_PROXYTYPE,ConvexAlgo2d);	Dispatcher->registerCollisionCreateFunc(CONVEX_2D_SHAPE_PROXYTYPE,BOX_2D_SHAPE_PROXYTYPE,ConvexAlgo2d);	Dispatcher->registerCollisionCreateFunc(BOX_2D_SHAPE_PROXYTYPE,BOX_2D_SHAPE_PROXYTYPE,new btBox2dBox2dCollisionAlgorithm::CreateFunc());}


And here is the code the blocks are using:
void LevelBlock::InitCollisionOnly(){	///create a few basic rigid bodies	CollisionShape = new btBoxShape(btVector3(Scale.x/2,Scale.y/2,1));	//keep track of the shapes, we release memory at exit.	//make sure to re-use collision shapes among rigid bodies whenever possible!	btAlignedObjectArray<btCollisionShape*> collisionShapes;	btTransform groundTransform;	groundTransform.setIdentity();	groundTransform.setOrigin(btVector3(Position.x,Position.y,Position.z));		btScalar mass(0.);	//rigidbody is dynamic if and only if mass is non zero, otherwise static	bool isDynamic = (mass != 0.f);	btVector3 localInertia(0,0,0);	if (isDynamic)		CollisionShape->calculateLocalInertia(mass,localInertia);	//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects	myMotionState = new btDefaultMotionState(groundTransform);	btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,CollisionShape,localInertia);	RigidBody = new btRigidBody(rbInfo);	//add the body to the dynamics world	Physics.DynamicsWorld->addRigidBody(RigidBody);	RigidBody->setFriction(0.5);	InitialPosition=Position;}void LevelBlock::InitPhysics(){	//create a dynamic rigidbody	//btCollisionShape* colShape = new btBoxShape(btVector3(1,1,1));	CollisionShape = new btBoxShape(btVector3(Scale.x/2,Scale.y/2,1));		/// Create Dynamic Objects	btTransform startTransform;	startTransform.setIdentity();	startTransform.setOrigin(btVector3(Position.x,Position.y,Position.z));	btScalar	mass(1.f);	//rigidbody is dynamic if and only if mass is non zero, otherwise static	bool isDynamic = (mass != 0.f);	btVector3 localInertia(0,0,0);	if (isDynamic)		CollisionShape->calculateLocalInertia(mass,localInertia);	//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects	myMotionState = new btDefaultMotionState(startTransform);	btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,CollisionShape,localInertia);	RigidBody = new btRigidBody(rbInfo);	Physics.DynamicsWorld->addRigidBody(RigidBody);	RigidBody->setLinearFactor(btVector3(1,1,0));	RigidBody->setAngularFactor(btVector3(0,0,1));	RigidBody->setFriction(0.5);	InitialPosition=Position;}



And this is my function for controlling the player-block (Kinda messy, sorry, not all my code looks like this [smile]):
void PlayerBlock::TickBlock(){	TexturedBlock::TickBlock();	if(RigidBody->isActive()==false)	{		//The player must be always active		RigidBody->activate(true);	}	//This is the force apply this frame	D3DXVECTOR3 Force=D3DXVECTOR3(0,0,0);		//Movement:	if(Input.bPressedKeys[VK_LEFT])	{		Force.x-=LR_MoveSpeed;		SetAnimationState(AS_Walk);		bLeft=true;	}	if(Input.bPressedKeys[VK_RIGHT])	{		Force.x+=LR_MoveSpeed;		SetAnimationState(AS_Walk);		bLeft=false;	}	//--	//Make it fit to the FPS	Force*=FPS.GetElapsedTime();	//Cap the speed of the player, so he never gets too fast (Set at the end of this function)	btVector3 Vel = RigidBody->getLinearVelocity();	if(Vel.x()>LR_MaxSpeed)	{		Vel.setX(LR_MaxSpeed);	}	if(Vel.x()<-LR_MaxSpeed)	{		Vel.setX(-LR_MaxSpeed);	}			//Key-Check	if(bOldSpace==true && Input.bPressedKeys[VK_SPACE]==false)	{		bOldSpace=false;	}	//Do a ray test to check if we are on the ground or not	btCollisionObjectArray ColArray;	btVector3 ToRay(Position.x,Position.y+(Scale.y/2)+0.001,Position.z);	btCollisionWorld::ClosestRayResultCallback rc(*(btVector3 *)&Position,ToRay);	Physics.DynamicsWorld->rayTest(*(btVector3 *)&Position,ToRay,rc);	if(rc.hasHit())	{			//We are on ground, make doublejumping possible		bHasDoubleJumped=false;		LastDJTime=0;		bIsOnGround=true;	}else	{		bIsOnGround=false;	}	if(bOldSpace==false && Input.bPressedKeys[VK_SPACE]==true)	{		//Cheat to get out when stucking somewhere		if(Input.bPressedKeys['T'])		{			D3DXVECTOR3 pos=Position;			pos.y-=BlockPlacer.BlockGridSize.y;			SetPosition(&pos);		}				//Do a jump		if(bIsOnGround || (bIsOnGround==false && bHasDoubleJumped==false))		{			if((bIsOnGround==false && bHasDoubleJumped==false) && LastDJTime+DoubleJumpWait<timeGetTime())			{ 				bHasDoubleJumped=true;								LastDJTime=timeGetTime();								Force.y-=JumpStrength;				SetAnimationState(AS_Jump);				//Double jumped, so stop any falling				Vel.setY(0);			}else if(bIsOnGround)			{				Force.y-=JumpStrength;				SetAnimationState(AS_Jump);			}		}		bOldSpace=true;	}		//Clamp the Velocity here	RigidBody->setLinearVelocity(Vel);	if(D3DXVec3Length(&Force)>0)	{		//Force does nothing?? (So impulse)		RigidBody->applyCentralImpulse(*(btVector3*)&Force);	}else	{		SetAnimationState(AS_Idle);	}	UpdateAnimation();	//RigidBody->setLinearVelocity(*(btVector3*)&Force);}

The only thing that really strikes me as being off is your default gravity. What does setting it to the real world value of -9.8 do? Your high gravity might be crushing objects together. Once objects have penatrated each other then Bullet breaks down.

A kinematic object is somebody that rigid bodies will react to but has no physics done on itself. Its up to you to move it around in a proper way around the levels. I'm sure you are using a rigid body on your character so he jumps and falls in a realistic way.

The fixed timestep will make your simulation more stable. If you have really high frame rates so that the physics tick is only doing a very small part of the physics setp it might be causing some weird things. The way you have it setup is internally Bullet is doing 60FPS but each tick is only doing the little bit of game time you give it every frame. So if your game is running 3-400FPS then its only doing a very tiny fraction of the entire physics step every frame. With the fixed timestep you pool up the time between frames so that a step is only called every 60FPS so Bullet will do an entire step every time. Not sure if this is your problem or not but its pretty simple to add and you should use it anyway.

One other thing to maybe try is using a capusle shape for your player instead of a box. Your player box may be getting stuck on edges of your level messing things up. People generally use the character controller anyway so you don't have extra bits of collision box hanging out there and its better about going up inclines and stairs.

I never had these kinds of pentration issues with Bullet. My problem was that Bullet would sometimes return the wrong collision normals in the collision callback messing up my game logic.
Thar issue with the gravity sounds logical. The only problem is, that 9.8 is way too light! Everything behaves like in space then. How do I set the weight of a body? I tried to set the Mass to more than 9000 but everything was still very slow...

This topic is closed to new replies.

Advertisement