New to Bullet - looking for guidance on vehicle movement

Krypt
Posts: 1
Joined: Mon Nov 30, 2009 10:48 pm

New to Bullet - looking for guidance on vehicle movement

Post by Krypt »

Hi there,

I am new to the Bullet physic world, but have managed to integrate it successfully with my project, and can register collision shapes and push them around, etc. A good start hopefully!

I am making a game that involves a futuristic style vehicle simulation. The vehicles don't have wheels (think hover rocket style vehicles :-)), but I want to provide a good feeling physics simulation so its fun to play.

Where I am looking for guidance is in the best way to apply the physics to the vehicle. At this stage I have created a btRigidBody, and have been testing it by applying impulse forces to the shape in order to push it, but havent found a way to create working steering so was hoping for some guidance on the best ways to go about this.

Some of the questions I have:
- Is the btRigidBody the best way to go about this based on my requirements? I see the raycastVehicle class, but it seems to have more detail than I need (i.e., the adding of wheels, suspension, etc) so haven't looked at that further yet.
- What is the best way to push the vehicle... using impules, forces, and/or torques?
- Are there any good links for bullet rigidbody tutorials? I haven't had much joy searching for these.

Any suggestions or guidance on this would be much appreciated.

Kind regards,
Krypt
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: New to Bullet - looking for guidance on vehicle movement

Post by Erwin Coumans »

You could use the btRaycastVehicle, and just not draw the wheels. Further info on this vehicle is here:
http://docs.google.com/Doc?docid=0AXVUZ ... 4Zmo&hl=en

Otherwise, you could use a linear and angular spring to keep your vehicle above the ground.

Here is some code snippet of such code in Blender. It is called every frame, directly after stepSimulation:

Code: Select all

void	CcdPhysicsEnvironment::processFhSprings(double curTime,float interval)
{
	std::set<CcdPhysicsController*>::iterator it;
	// dynamic of Fh spring is based on a timestep of 1/60
	int numIter = (int)(interval*60.0001f);
	
	for (it=m_controllers.begin(); it!=m_controllers.end(); it++)
	{
		CcdPhysicsController* ctrl = (*it);
		btRigidBody* body = ctrl->GetRigidBody();

		if (body && (ctrl->getConstructionInfo().m_do_fh || ctrl->getConstructionInfo().m_do_rot_fh))
		{
			//printf("has Fh or RotFh\n");
			//re-implement SM_FhObject.cpp using btCollisionWorld::rayTest and info from ctrl->getConstructionInfo()
			//send a ray from {0.0, 0.0, 0.0} towards {0.0, 0.0, -10.0}, in local coordinates
			CcdPhysicsController* parentCtrl = ctrl->getParentCtrl();
			btRigidBody* parentBody = parentCtrl?parentCtrl->GetRigidBody() : 0;
			btRigidBody* cl_object = parentBody ? parentBody : body;

			if (body->isStaticOrKinematicObject())
				continue;

			btVector3 rayDirLocal(0,0,-10);

			//m_dynamicsWorld
			//ctrl->GetRigidBody();
			btVector3 rayFromWorld = body->getCenterOfMassPosition();
			//btVector3	rayToWorld = rayFromWorld + body->getCenterOfMassTransform().getBasis() * rayDirLocal;
			//ray always points down the z axis in world space...
			btVector3	rayToWorld = rayFromWorld + rayDirLocal;
			
			ClosestRayResultCallbackNotMe	resultCallback(rayFromWorld,rayToWorld,body,parentBody);

			m_dynamicsWorld->rayTest(rayFromWorld,rayToWorld,resultCallback);
			if (resultCallback.hasHit())
			{
				//we hit this one: resultCallback.m_collisionObject;
				CcdPhysicsController* controller = static_cast<CcdPhysicsController*>(resultCallback.m_collisionObject->getUserPointer());

				if (controller)
				{
					if (controller->getConstructionInfo().m_fh_distance < SIMD_EPSILON)
						continue;

					btRigidBody* hit_object = controller->GetRigidBody();
					if (!hit_object)
						continue;

					CcdConstructionInfo& hitObjShapeProps = controller->getConstructionInfo();

					float distance = resultCallback.m_closestHitFraction*rayDirLocal.length()-ctrl->getConstructionInfo().m_radius;
					if (distance >= hitObjShapeProps.m_fh_distance)
						continue;
					
					

					//btVector3 ray_dir = cl_object->getCenterOfMassTransform().getBasis()* rayDirLocal.normalized();
					btVector3 ray_dir = rayDirLocal.normalized();
					btVector3 normal = resultCallback.m_hitNormalWorld;
					normal.normalize();

					for (int i=0; i<numIter; i++)
					{
						if (ctrl->getConstructionInfo().m_do_fh) 
						{
							btVector3 lspot = cl_object->getCenterOfMassPosition()
								+ rayDirLocal * resultCallback.m_closestHitFraction;


								

							lspot -= hit_object->getCenterOfMassPosition();
							btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot);
							btScalar rel_vel_ray = ray_dir.dot(rel_vel);
							btScalar spring_extent = 1.0 - distance / hitObjShapeProps.m_fh_distance; 
							
							btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring;
							btScalar i_damp =   rel_vel_ray * hitObjShapeProps.m_fh_damping;
							
							cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (-(i_spring + i_damp) * ray_dir)); 
							if (hitObjShapeProps.m_fh_normal) 
							{
								cl_object->setLinearVelocity(cl_object->getLinearVelocity()+(i_spring + i_damp) *(normal - normal.dot(ray_dir) * ray_dir));
							}
							
							btVector3 lateral = rel_vel - rel_vel_ray * ray_dir;
							
							
							if (ctrl->getConstructionInfo().m_do_anisotropic) {
								//Bullet basis contains no scaling/shear etc.
								const btMatrix3x3& lcs = cl_object->getCenterOfMassTransform().getBasis();
								btVector3 loc_lateral = lateral * lcs;
								const btVector3& friction_scaling = cl_object->getAnisotropicFriction();
								loc_lateral *= friction_scaling;
								lateral = lcs * loc_lateral;
							}

							btScalar rel_vel_lateral = lateral.length();
							
							if (rel_vel_lateral > SIMD_EPSILON) {
								btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction();

								btScalar max_friction = friction_factor * btMax(btScalar(0.0), i_spring);
								
								btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass();
								
								btVector3 friction = (rel_mom_lateral > max_friction) ?
									-lateral * (max_friction / rel_vel_lateral) :
									-lateral;
								
									cl_object->applyCentralImpulse(friction);
							}
						}

						
						if (ctrl->getConstructionInfo().m_do_rot_fh) {
							btVector3 up2 = cl_object->getWorldTransform().getBasis().getColumn(2);

							btVector3 t_spring = up2.cross(normal) * hitObjShapeProps.m_fh_spring;
							btVector3 ang_vel = cl_object->getAngularVelocity();
							
							// only rotations that tilt relative to the normal are damped
							ang_vel -= ang_vel.dot(normal) * normal;
							
							btVector3 t_damp = ang_vel * hitObjShapeProps.m_fh_damping;  
							
							cl_object->setAngularVelocity(cl_object->getAngularVelocity() + (t_spring - t_damp));
						}
					}
				}
			}
		}
	}
}