PhysX Vehicles 1
PhysX • Collision and Dynamics SDK (now) owned by Nvidia • Most common physics library used in games for this course • Includes lots of vehicle specific features, which we strongly recommend using • We used to allow rigid body physics libraries but required building driving model from scratch • Getting a good driving model is by far the biggest challenge for teams, and was often holding back game quality significantly
Basics of PhysX Vehicle SDK • Essential tasks – Set up library – Create some meshes – Allocate simulation data – Allocate actor and add to world – Per frame : Setup inputs to drive and steering – Per frame : Wheel raycasts – Per frame : Tick simulation • Caveat : I have not personally built anything with this • Sample code : PhysX-SDK/Sample/SampleVehicle
Initialization • PxPhysics – Base context for all operations PxAllocatorCallback* allocator = &gDefaultAllocatorCallback; mFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, *allocator, getSampleErrorCallback()); mPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *mFoundation, scale, recordMemoryAllocations, mProfileZoneManager);
Initialization • PxCooking – Utility class for creating meshes in physics – PhysX vehicles uses meshes for all objects in vehicle system PxCookingParams params(scale); params.meshWeldTolerance = 0.001f; params.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES | PxMeshPreprocessingFlag::eREMOVE_UNREFERENCED_VERTICES | PxMeshPreprocessingFlag::eREMOVE_DUPLICATED_TRIANGLES); mCooking = PxCreateCooking(PX_PHYSICS_VERSION, *mFoundation, params);
Initialization • PxScene – Container for all object in simulation – Global world properties (i.e. gravity) – Any objects not in vehicle system can be added straight to this with minimal extra work – Probably going to want to add at least one static object mScene = mPhysics->createScene(sceneDesc); mScene.setGravity(PxVec3(0.0f, -9.81f, 0.0f)); mMaterials = getPhysics().createMaterial(staticFriction, dynamicFriction, restitution); PxRigidStatic* plane = PxCreatePlane(*mPhysics, PxPlane(PxVec3(0,1,0), 0), *mMaterial); mScene->addActor(*plane);
Initialization • Setup vehicle support • Few essential parameters need to be set • No context object, just free functions PxInitVehicleSDK(physics); PxVec3 up(0,1,0); PxVec3 forward(0,0,1); PxVehicleSetBasisVectors(up,forward); //Set the vehicle update mode to be immediate velocity changes. PxVehicleSetUpdateMode(PxVehicleUpdateMode::eVELOCITY_CHANGE);
Mesh creation PxConvexMeshDesc convexDesc; convexDesc.points.count = numVerts; convexDesc.points.stride = sizeof(PxVec3); convexDesc.points.data = verts; convexDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX | PxConvexFlag::eINFLATE_CONVEX; PxConvexMesh* convexMesh = NULL; PxDefaultMemoryOutputStream buf; if(cooking.cookConvexMesh(convexDesc, buf)) { PxDefaultMemoryInputData id(buf.getData(), buf.getSize()); convexMesh = physics.createConvexMesh(id); }
Set up simulation data void createVehicle4WSimulationData (const PxF32 chassisMass, PxConvexMesh* chassisConvexMesh, const PxF32 wheelMass, PxConvexMesh** wheelConvexMeshes, const PxVec3* wheelCentreOffsets, PxVehicleWheelsSimData& wheelsData, PxVehicleDriveSimData4W& driveData, PxVehicleChassisData& chassisData) { //Extract the chassis AABB dimensions from the chassis convex mesh. const PxVec3 chassisDims=computeChassisAABBDimensions(chassisConvexMesh); //The origin is at the center of the chassis mesh. //Set the center of mass to be below this point and a little towards the front. const PxVec3 chassisCMOffset=PxVec3(0.0f,-chassisDims.y*0.5f+0.65f,0.25f); //Now compute the chassis mass and moment of inertia. //Use the moment of inertia of a cuboid as an approximate value for the chassis moi. PxVec3 chassisMOI ((chassisDims.y*chassisDims.y + chassisDims.z*chassisDims.z)*chassisMass/12.0f, (chassisDims.x*chassisDims.x + chassisDims.z*chassisDims.z)*chassisMass/12.0f, (chassisDims.x*chassisDims.x + chassisDims.y*chassisDims.y)*chassisMass/12.0f); //A bit of tweaking here. The car will have more responsive turning if we reduce the //y-component of the chassis moment of inertia. chassisMOI.y*=0.8f; //Let's set up the chassis data structure now. chassisData.mMass=chassisMass; chassisData.mMOI=chassisMOI; chassisData.mCMOffset=chassisCMOffset; //Compute the sprung masses of each suspension spring using a helper function. PxF32 suspSprungMasses[4]; PxVehicleComputeSprungMasses(4,wheelCentreOffsets,chassisCMOffset,chassisMass,1,suspSprungMasses); //Extract the wheel radius and width from the wheel convex meshes. PxF32 wheelWidths[4]; PxF32 wheelRadii[4]; computeWheelWidthsAndRadii(wheelConvexMeshes,wheelWidths,wheelRadii); //Now compute the wheel masses and inertias components around the axle's axis. //http://en.wikipedia.org/wiki/List_of_moments_of_inertia PxF32 wheelMOIs[4]; for(PxU32 i=0;i<4;i++) { wheelMOIs[i]=0.5f*wheelMass*wheelRadii[i]*wheelRadii[i]; } //Let's set up the wheel data structures now with radius, mass, and moi. PxVehicleWheelData wheels[4]; for(PxU32 i=0;i<4;i++) { wheels[i].mRadius=wheelRadii[i]; wheels[i].mMass=wheelMass; wheels[i].mMOI=wheelMOIs[i]; wheels[i].mWidth=wheelWidths[i]; } //Disable the handbrake from the front wheels and enable for the rear wheels wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mMaxHandBrakeTorque=0.0f; wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mMaxHandBrakeTorque=0.0f; wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mMaxHandBrakeTorque=4000.0f; wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mMaxHandBrakeTorque=4000.0f; //Enable steering for the front wheels and disable for the front wheels. wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mMaxSteer=PxPi*0.3333f; wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mMaxSteer=PxPi*0.3333f; wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mMaxSteer=0.0f; wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mMaxSteer=0.0f; //Let's set up the tire data structures now. //Put slicks on the front tires and wets on the rear tires. PxVehicleTireData tires[4]; tires[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mType=TIRE_TYPE_SLICKS; tires[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mType=TIRE_TYPE_SLICKS; tires[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mType=TIRE_TYPE_WETS; tires[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mType=TIRE_TYPE_WETS; //Let's set up the suspension data structures now. PxVehicleSuspensionData susps[4]; for(PxU32 i=0;i<4;i++) { susps[i].mMaxCompression=0.3f; susps[i].mMaxDroop=0.1f; susps[i].mSpringStrength=35000.0f; susps[i].mSpringDamperRate=4500.0f; } susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mSprungMass=suspSprungMasses[PxVehicleDrive4WWheelOrder::eFRONT_LEFT]; susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mSprungMass=suspSprungMasses[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT]; susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mSprungMass=suspSprungMasses[PxVehicleDrive4WWheelOrder::eREAR_LEFT]; susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mSprungMass=suspSprungMasses[PxVehicleDrive4WWheelOrder::eREAR_RIGHT]; //Set up the camber. //Remember that the left and right wheels need opposite camber so that the car preserves symmetry about the forward direction. //Set the camber to 0.0f when the spring is neither compressed or elongated. const PxF32 camberAngleAtRest=0.0; susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mCamberAtRest=camberAngleAtRest; susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mCamberAtRest=-camberAngleAtRest; susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mCamberAtRest=camberAngleAtRest; susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mCamberAtRest=-camberAngleAtRest; //Set the wheels to camber inwards at maximum droop (the left and right wheels almost form a V shape) const PxF32 camberAngleAtMaxDroop=0.001f; susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mCamberAtMaxDroop=camberAngleAtMaxDroop;
Simulation data setup • Three key classes • Wheel - Suspension, radius, etc.. • Chassis - Body of the vehicle • Drive - How are power and steering applied PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(4); PxVehicleDriveSimData4W driveSimData; PxVehicleChassisData chassisData; createVehicle4WSimulationData (chassisMass,chassisConvexMesh, 20.0f,wheelConvexMeshes4,wheelCentreOffsets4, *wheelsSimData,driveSimData,chassisData);
Setup examples • Chassis centre of mass const PxVec3 chassisCMOffset=PxVec3(0.0f,-chassisDims.y*0.5f+0.65f,0.25f); chassisData.mCMOffset=chassisCMOffset; • Suspension spring parameters PxVehicleSuspensionData susps[4]; for(PxU32 i=0;i<4;i++) { susps[i].mMaxCompression=0.3f; susps[i].mMaxDroop=0.1f; susps[i].mSpringStrength=35000.0f; susps[i].mSpringDamperRate=4500.0f; } for(PxU32 i=0;i<4;i++) { wheelsData.setSuspensionData(i,susps[i]); //... } • Engine properties PxVehicleEngineData engine; engine.mPeakTorque=500.0f; engine.mMaxOmega=600.0f;//approx 6000 rpm driveData.setEngineData(engine);
Recommend
More recommend