skateboard physics

Jacky_J
Posts: 16
Joined: Fri May 11, 2007 7:06 am

skateboard physics

Post by Jacky_J »

I'm trying to create a skateboarding game with bullet physics. It seems like there are two ways to go about it:

1. Use the vehicle raycaster.

2. Use a regular shape (box or sphere) and constrain its movement to a vertical plane.

I'm trying the second approach, since it seems like the vehicle method might be overkill.

My plan is to use btGeneric6DofConstraint to constrain to a vertical plane of movement, but my question is how do i constrain it to an arbitrarily rotated plane? setLimit only uses x, y and z axes.

for example this constrains it to the xy plane:

Code: Select all

Constraint->setLimit(0, 1, 0);
Constraint->setLimit(1, 1, 0);
Constraint->setLimit(2, 0, 0);
Constraint->setLimit(3, 1, 0);
Constraint->setLimit(4, 1, 0);
Constraint->setLimit(5, 1, 0);
As the player leans left or right, the plane would have to be updated to reflect that angle.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: skateboard physics

Post by Erwin Coumans »

One solution for skateboard physics could be a linear and angular spring and a raytest.

In Blender we added those 'Fh' springs externally to Bullet. Can you check the (hover) skategirl demo?
http://www.bulletphysics.com/ftp/pub/te ... view10.zip
If you are under Windows: drag the file webskategirl_bullet.blend over blenderplayer.exe, and use A,D,S,W keys to control the skateboarder.

Should we add such raycast spring to Bullet?
Thanks,
Erwin

Code: Select all

void	CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep)
{
	std::set<CcdPhysicsController*>::iterator it;
	
	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();

					
					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));
					}

				}


			}


		}
	}
	
}
Jacky_J
Posts: 16
Joined: Fri May 11, 2007 7:06 am

Re: skateboard physics

Post by Jacky_J »

Cool demos!

I think that the webskategirl is more of a hoverboard simulation rather than a classical skateboard simulation. It seems like it has trouble going up the ramps though, since it's using a ray spring. I think that if you used a sphere to model the board, it could roll up the ramps smoothly. That demo gave me some ideas though.

I figured out the answer to my own question, which is to simply just rotate the object that the player is constrained to.

I've been out of the bullet loop for about 20 versions, so i don't know if springs have been added. I remember i had to write my own on irrlamb: http://code.google.com/p/irrlamb/source ... gjoint.cpp

I'm sure bullet would benefit with some ray springs, but i think spring constraints would be advantageous.