Bullet Physics Vehicle

Started by
4 comments, last by MrRowl 10 years, 10 months ago

I'm setting up a simple vehicle and trying to create a box and cylinder, so here is what I'm doing:


// Create a box and cylinder shapes for the vehicle
D3DXCreateBox(device, 2.0f, 1.0f, 4.0f, &meshChassis, NULL);
D3DXCreateCylinder(device, wheelRadius*0.5f, wheelRadius*0.5f, wheelWidth*0.5f, 20, 20, &meshWheels, NULL);

.


void Render()
{
D3DXMATRIX matTransformation;

btTransform trans;
m_carChassis->getMotionState()->getWorldTransform(trans);
matTransformation = btTransformToD3DXMATRIX(trans);

d3ddev->SetTransform(D3DTS_WORLD, &matTransformation);
meshChassis->DrawSubset(0);

// Code to render wheels here...
}

I also debug draw wireframe, and the final result is that the chassis position is not valid as the wireframe:

[attachment=16306:vehicle.png]

Advertisement

You've not really provided much info about how you create the Bullet side.

Depending on how you create the vehicle, there might be some offset between where you think you created the shapes and where Bullet thinks they are. When you create the objects you generally need to calculate the mass properties and adjust the shapes - you'd then need to use that offset to convert from the centre of mass representation to your render representation.

Here is the vehicle code:


// CPP
#ifdef FORCE_ZAXIS_UP
int rightIndex = 0; 
int upIndex = 2; 
int forwardIndex = 1;
btVector3 wheelDirectionCS0(0,0,-1);
btVector3 wheelAxleCS(1,0,0);
#else
int rightIndex = 0;
int upIndex = 1;
int forwardIndex = 2;
btVector3 wheelDirectionCS0(0,-1,0); //0,0,-1
btVector3 wheelAxleCS(-1,0,0); // 0,-1,0
#endif


const int maxProxies = 32766;
const int maxOverlap = 65535;


///btRaycastVehicle is the interface for the constraint that implements the raycast vehicle
///notice that for higher-quality slow-moving vehicles, another approach might be better
///implementing explicit hinged-wheel constraints with cylinder collision, rather then raycasts
float gEngineForce = 0.f;
float gBreakingForce = 0.f;


float maxEngineForce = 1000.f;//this should be engine/velocity dependent
float maxBreakingForce = 100.f;


float gVehicleSteering = 0.f;
float steeringIncrement = 0.0004f;
float steeringClamp = 0.1f;
float wheelRadius = 0.5f;
float wheelWidth = 0.4f;
float wheelFriction = 1000;//BT_LARGE_FLOAT;
float suspensionStiffness = 20.f;
float suspensionDamping = 2.3f;
float suspensionCompression = 4.4f;
float rollInfluence = 0.1f;//1.0f;


btScalar suspensionRestLength(0.6);


#define CUBE_HALF_EXTENTS 1


D3DXMATRIX btTransformToD3DXMATRIX( btTransform &trn ) 
{
btVector3 R = trn.getBasis().getColumn(0);
btVector3 U = trn.getBasis().getColumn(1);
btVector3 L = trn.getBasis().getColumn(2);
btVector3 P = trn.getOrigin();


D3DXVECTOR3 vR, vU, vL, vP;
vR.x = R.x();vR.y = R.y();vR.z = R.z();
vU.x = U.x();vU.y = U.y();vU.z = U.z();
vL.x = L.x();vL.y = L.y();vL.z = L.z();
vP.x = P.x();vP.y = P.y();vP.z = P.z();


D3DXMATRIX matOutput;
matOutput._11 = vR.x;matOutput._12 = vR.y;matOutput._13 = vR.z;matOutput._14 = 0.f;
matOutput._21 = vU.x;matOutput._22 = vU.y;matOutput._23 = vU.z;matOutput._24 = 0.f;
matOutput._31 = vL.x;matOutput._32 = vL.y;matOutput._33 = vL.z;matOutput._34 = 0.f;
matOutput._41 = vP.x;matOutput._42 = vP.y;matOutput._43 = vP.z;matOutput._44 = 1.f;


return matOutput;
}


Vehicle::Vehicle(LPDIRECT3DDEVICE9 lpdevice, btDiscretemDynamicsWorld *world) : device(lpdevice), mDynamicsWorld(world)
{
D3DXCreateBox(device, 2.0f, 1.0f, 4.0f, &meshChassis, NULL); // 1.f,0.5f,2.f
D3DXCreateCylinder(device, wheelRadius*0.5f, wheelRadius*0.5f, wheelWidth*0.5f, 20, 20, &meshWheels, NULL);
}


void Vehicle::DetectInput()
{
if (GetAsyncKeyState(VK_RIGHT) != 0) // VK_LEFT
{
gVehicleSteering += steeringIncrement;
if (gVehicleSteering > steeringClamp)
gVehicleSteering = steeringClamp;
}


if (GetAsyncKeyState(VK_LEFT) != 0) // VK_RIGHT
{
gVehicleSteering -= steeringIncrement;
if (gVehicleSteering < -steeringClamp)
gVehicleSteering = -steeringClamp;


}


    if (GetAsyncKeyState(VK_UP) != 0)
{
gEngineForce += 1.0f;
if (gEngineForce > maxEngineForce)
gEngineForce = maxEngineForce;
gBreakingForce = 0.f;
}




if (GetAsyncKeyState(VK_DOWN) != 0)
{ 
gBreakingForce = maxBreakingForce; 
gEngineForce = 0.f;
}


{
int wheelIndex = 2;
m_vehicle->applyEngineForce(gEngineForce,wheelIndex);
m_vehicle->setBrake(gBreakingForce,wheelIndex);
wheelIndex = 3;
m_vehicle->applyEngineForce(gEngineForce,wheelIndex);
m_vehicle->setBrake(gBreakingForce,wheelIndex);




wheelIndex = 0;
m_vehicle->setSteeringValue(gVehicleSteering,wheelIndex);
wheelIndex = 1;
m_vehicle->setSteeringValue(gVehicleSteering,wheelIndex);


}


return;
if (GetAsyncKeyState(VK_UP) != 0)
{
gEngineForce = maxEngineForce;
gBreakingForce = 0.f;
}


if (GetAsyncKeyState(VK_DOWN) != 0)
{
gBreakingForce = maxBreakingForce; 
gEngineForce = 0.f;
}


if (GetAsyncKeyState(VK_RIGHT) != 0)
{
gVehicleSteering -= steeringIncrement;
if (gVehicleSteering < -steeringClamp)
gVehicleSteering = -steeringClamp;
}


if (GetAsyncKeyState(VK_LEFT) != 0)
{
gVehicleSteering += steeringIncrement;
if (gVehicleSteering > steeringClamp)
gVehicleSteering = steeringClamp;
}




{




int wheelIndex = 1;
m_vehicle->applyEngineForce(gEngineForce,wheelIndex);
//m_vehicle->setBrake(gBreakingForce,wheelIndex);
wheelIndex = 2;
m_vehicle->applyEngineForce(gEngineForce,wheelIndex);
//m_vehicle->setBrake(gBreakingForce,wheelIndex);
wheelIndex = 0;
m_vehicle->applyEngineForce(gEngineForce,wheelIndex);
//m_vehicle->setBrake(gBreakingForce,wheelIndex);
wheelIndex = 3;
m_vehicle->applyEngineForce(gEngineForce,wheelIndex);
//m_vehicle->setBrake(gBreakingForce,wheelIndex);


wheelIndex = 1;
m_vehicle->setSteeringValue(gVehicleSteering,wheelIndex);
wheelIndex = 2;
m_vehicle->setSteeringValue(gVehicleSteering,wheelIndex);




}
}




void Vehicle::Render(float timeElapsed)
{
btTransform trn;
trn.setIdentity();


m_vehicle->getRigidBody()->getMotionState()->getWorldTransform( trn );
D3DXMATRIX vMat = btTransformToD3DXMATRIX(trn);




D3DXMATRIX matTransformation; //= btTransformToD3DXMATRIX(trn);


btTransform trans;
m_carChassis->getMotionState()->getWorldTransform(trans);
matTransformation = btTransformToD3DXMATRIX(trans);


//D3DXMatrixIdentity(&matTransformation);
//matTransformation = btTransformToD3DXMATRIX(trn);
//D3DXMatrixTranslation(&matTransformation, 1200.0f, -400.0f, 0.0f);


device->SetTransform(D3DTS_WORLD, &(matTransformation));
meshChassis->DrawSubset(0);

int i;
for (i=0;i<m_vehicle->getNumWheels();i++)
{
//synchronize the wheels with the (interpolated) chassis worldtransform
m_vehicle->updateWheelTransform(i,true);

btTransform wheelTrans;
wheelTrans.setIdentity();
btVector3 wheelPosition;
//m_vehicle->getWheelInfo(i).m_worldTransform(wheelPosition); //.m_worldTransform(wheelTrans);


wheelTrans = m_vehicle->getWheelInfo(i).m_worldTransform;




D3DXMATRIX matWheelTrans = btTransformToD3DXMATRIX(wheelTrans);


D3DXMATRIX matRot;
D3DXMatrixRotationY( &matRot, D3DXToRadian(90.0f));
device->SetTransform(D3DTS_WORLD, &(matRot * matWheelTrans));
D3DMATERIAL9 material;
material.Diffuse = D3DXCOLOR(255, 255, 255, 255);
material.Ambient = material.Diffuse;
device->SetMaterial(&material);
meshWheels->DrawSubset(0);
}
}


btRigidBody* Vehicle::localCreateRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape)
{
btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE));


//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)
shape->calculateLocalInertia(mass,localInertia);


//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects


#define USE_MOTIONSTATE 1
#ifdef USE_MOTIONSTATE
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);


btRigidBody::btRigidBodyConstructionInfo cInfo(mass,myMotionState,shape,localInertia);


btRigidBody* body = new btRigidBody(cInfo);
body->setContactProcessingThreshold(0.0f); // m_defaultContactProcessingThreshold


#else
btRigidBody* body = new btRigidBody(mass,0,shape,localInertia); 
body->setWorldTransform(startTransform);
#endif//


mDynamicsWorld->addRigidBody(body);


return body;
}


void Vehicle::Create(D3DXVECTOR3 position)
{


btTransform tr;
tr.setIdentity();
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;




#ifdef FORCE_ZAXIS_UP
//   indexRightAxis = 0; 
//   indexUpAxis = 2; 
//   indexForwardAxis = 1; 
btCollisionShape* chassisShape = new btBoxShape(btVector3(1.f,2.f, 0.5f));
btCompoundShape* compound = new btCompoundShape();
btTransform localTrans;
localTrans.setIdentity();
//localTrans effectively shifts the center of mass with respect to the chassis
localTrans.setOrigin(btVector3(0,0,1));
#else


D3DXVECTOR3 bMin, bMax;
BYTE* pData = 0;
meshChassis->LockVertexBuffer(0, (LPVOID*)&pData);
D3DXComputeBoundingBox((D3DXVECTOR3*)pData, meshChassis->GetNumVertices(), meshChassis->GetNumBytesPerVertex(), &bMin, &bMax);
meshChassis->UnlockVertexBuffer();


D3DXVECTOR3 boxHalfExtent = (bMax - bMin) * 0.5f;
boxHalfExtent.x = abs(boxHalfExtent.x);
boxHalfExtent.y = abs(boxHalfExtent.y);
boxHalfExtent.z = abs(boxHalfExtent.z);
btVector3 btBoxHalfExtent(boxHalfExtent.x, boxHalfExtent.y, boxHalfExtent.z);


btCollisionShape* chassisShape = new btBoxShape(btBoxHalfExtent);
m_collisionShapes.push_back(chassisShape);


btCompoundShape* compound = new btCompoundShape();
m_collisionShapes.push_back(compound);
btTransform localTrans;
localTrans.setIdentity();
//localTrans effectively shifts the center of mass with respect to the chassis
localTrans.setOrigin(btVector3(0,1,0));
#endif


compound->addChildShape(localTrans,chassisShape);


tr.setOrigin(btVector3(0,-40.f,0));


m_carChassis = localCreateRigidBody(800,tr,compound);//chassisShape);
//m_carChassis->setDamping(0.2,0.2);
m_wheelShape = new btCylinderShapeX(btVector3(wheelWidth,wheelRadius,wheelRadius));




/// create vehicle
{


m_vehicleRayCaster = new btDefaultVehicleRaycaster(mDynamicsWorld);
m_vehicle = new btRaycastVehicle(m_tuning,m_carChassis,m_vehicleRayCaster);


///never deactivate the vehicle
m_carChassis->setActivationState(DISABLE_DEACTIVATION);


mDynamicsWorld->addVehicle(m_vehicle);


float connectionHeight = 1.2f; // 1.2f




bool isFrontWheel=true;


//choose coordinate system
m_vehicle->setCoordinateSystem(rightIndex,upIndex,forwardIndex);


#ifdef FORCE_ZAXIS_UP
btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight);
#else
btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),connectionHeight,2*CUBE_HALF_EXTENTS-wheelRadius);
#endif


m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);
#ifdef FORCE_ZAXIS_UP
connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight);
#else
connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),connectionHeight,2*CUBE_HALF_EXTENTS-wheelRadius);
#endif


m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);
#ifdef FORCE_ZAXIS_UP
connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight);
#else
connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),connectionHeight,-2*CUBE_HALF_EXTENTS+wheelRadius);
#endif //FORCE_ZAXIS_UP
isFrontWheel = false;
m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);
#ifdef FORCE_ZAXIS_UP
connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight);
#else
connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),connectionHeight,-2*CUBE_HALF_EXTENTS+wheelRadius);
#endif
m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);


for (int i=0;i<m_vehicle->getNumWheels();i++)
{
btWheelInfo& wheel = m_vehicle->getWheelInfo(i);
wheel.m_suspensionStiffness = suspensionStiffness;
wheel.m_wheelsDampingRelaxation = suspensionDamping;
wheel.m_wheelsDampingCompression = suspensionCompression;
wheel.m_frictionSlip = wheelFriction;
wheel.m_rollInfluence = rollInfluence;
}
}
}

Up.

Up, need some help...

I see you've got:

localTrans.setOrigin(btVector3(0,1,0));

which looks like exactly the offset in your picture.

My guess is that you're doing that to move the centre of mass of the vehicle below the wheels, to give it extra stability. That's fine (if you like that sort of thing!) - but my second guess is that you're not applying the same offset to the rendering. The transform you get back from the rigid body will be its centre of mass transform.

This topic is closed to new replies.

Advertisement