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