// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #include "SampleVehicle.h" #include "SampleVehicle_VehicleManager.h" #include "SampleVehicle_VehicleCooking.h" #include "SampleVehicle_SceneQuery.h" #include "SampleVehicle_WheelQueryResults.h" #include "RendererMemoryMacros.h" #include "vehicle/PxVehicleSDK.h" #include "vehicle/PxVehicleDrive4W.h" #include "vehicle/PxVehicleDriveNW.h" #include "vehicle/PxVehicleDriveTank.h" #include "vehicle/PxVehicleUpdate.h" #include "vehicle/PxVehicleTireFriction.h" #include "vehicle/PxVehicleUtilSetup.h" #include "PxRigidDynamic.h" #include "PxScene.h" #include "geometry/PxConvexMesh.h" #include "geometry/PxConvexMeshGeometry.h" #include "SampleAllocatorSDKClasses.h" /////////////////////////////////// SampleVehicle_VehicleManager::SampleVehicle_VehicleManager() : mNumVehicles(0), mSqWheelRaycastBatchQuery(NULL), mIsIn3WMode(false), mSerializationRegistry(NULL) { } SampleVehicle_VehicleManager::~SampleVehicle_VehicleManager() { } void SampleVehicle_VehicleManager::init(PxPhysics& physics, const PxMaterial** drivableSurfaceMaterials, const PxVehicleDrivableSurfaceType* drivableSurfaceTypes) { #if defined(SERIALIZE_VEHICLE_RPEX) || defined(SERIALIZE_VEHICLE_BINARY) mSerializationRegistry = PxSerialization::createSerializationRegistry(physics); #endif //Initialise the sdk. PxInitVehicleSDK(physics, mSerializationRegistry); //Set the basis vectors. 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); //Initialise all vehicle ptrs to null. for(PxU32 i=0;isetup(MAX_NUM_TIRE_TYPES,MAX_NUM_SURFACE_TYPES,drivableSurfaceMaterials,drivableSurfaceTypes); for(PxU32 i=0;isetTypePairFriction(i,j,TireFrictionMultipliers::getValue(i, j)); } } } void SampleVehicle_VehicleManager::shutdown() { //Remove the N-wheeled vehicles. for(PxU32 i=0;igetVehicleType()) { case PxVehicleTypes::eDRIVE4W: { PxVehicleDrive4W* veh=(PxVehicleDrive4W*)mVehicles[i]; veh->free(); } break; case PxVehicleTypes::eDRIVENW: { PxVehicleDriveNW* veh=(PxVehicleDriveNW*)mVehicles[i]; veh->free(); } break; case PxVehicleTypes::eDRIVETANK: { PxVehicleDriveTank* veh=(PxVehicleDriveTank*)mVehicles[i]; veh->free(); } break; default: PX_ASSERT(false); break; } } //Deallocate simulation data that was used to switch from 3-wheeled to 4-wheeled cars by switching simulation data. mWheelsSimData4W->free(); //Deallocate scene query data that was used for suspension raycasts. mSqData->free(); //Deallocate buffers that store wheel reports. mWheelQueryResults->free(); //Release the friction values used for combinations of tire type and surface type. mSurfaceTirePairs->release(); //Scene query. if(mSqWheelRaycastBatchQuery) { mSqWheelRaycastBatchQuery=NULL; } PxCloseVehicleSDK(mSerializationRegistry); if(mSerializationRegistry) mSerializationRegistry->release(); } void SampleVehicle_VehicleManager::addVehicle(const PxU32 i, PxVehicleWheels* vehicle) { mVehicles[i] = vehicle; const PxU32 numWheels = vehicle->mWheelsSimData.getNbWheels(); mVehicleWheelQueryResults[i].nbWheelQueryResults = numWheels; mVehicleWheelQueryResults[i].wheelQueryResults = mWheelQueryResults->addVehicle(numWheels); mNumVehicles++; } void SampleVehicle_VehicleManager::resetNWCar(const PxTransform& transform, const PxU32 vehicleId) { PX_ASSERT(vehicleIdsetUpBatchedSceneQuery(scene); } //Raycasts. PxSceneReadLock scopedLock(*scene); PxVehicleSuspensionRaycasts(mSqWheelRaycastBatchQuery,mNumVehicles,mVehicles,mSqData->getRaycastQueryResultBufferSize(),mSqData->getRaycastQueryResultBuffer()); } #if PX_DEBUG_VEHICLE_ON void SampleVehicle_VehicleManager::updateAndRecordTelemetryData (const PxF32 timestep, const PxVec3& gravity, PxVehicleWheels* focusVehicle, PxVehicleTelemetryData* telemetryData) { PX_ASSERT(focusVehicle && telemetryData); //Update all vehicles except for focusVehicle. PxVehicleWheels* vehicles[MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES]; PxVehicleWheelQueryResult vehicleWheelQueryResults[MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES]; PxVehicleWheelQueryResult focusVehicleWheelQueryResults[1]; PxU32 numVehicles=0; for(PxU32 i=0;igetVehicleType()) { case PxVehicleTypes::eDRIVE4W: { PxVehicleDrive4W* vehDrive4W=(PxVehicleDrive4W*)vehWheels; //Set the car back to its rest state. vehDrive4W->setToRestState(); //Set the car to first gear. vehDrive4W->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); } break; case PxVehicleTypes::eDRIVENW: { PxVehicleDriveNW* vehDriveNW=(PxVehicleDriveNW*)vehWheels; //Set the car back to its rest state. vehDriveNW->setToRestState(); //Set the car to first gear. vehDriveNW->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); } break; case PxVehicleTypes::eDRIVETANK: { PxVehicleDriveTank* vehDriveTank=(PxVehicleDriveTank*)vehWheels; //Set the car back to its rest state. vehDriveTank->setToRestState(); //Set the car to first gear. vehDriveTank->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); } break; default: PX_ASSERT(false); break; } //Set the car's transform to be the start transform. PxRigidDynamic* actor=vehWheels->getRigidDynamicActor(); PxSceneWriteLock scopedLock(*actor->getScene()); actor->setGlobalPose(startTransform); } void setupActor (PxRigidDynamic* vehActor, const PxFilterData& vehQryFilterData, const PxGeometry** wheelGeometries, const PxTransform* wheelLocalPoses, const PxU32 numWheelGeometries, const PxMaterial* wheelMaterial, const PxFilterData& wheelCollFilterData, const PxGeometry** chassisGeometries, const PxTransform* chassisLocalPoses, const PxU32 numChassisGeometries, const PxMaterial* chassisMaterial, const PxFilterData& chassisCollFilterData, const PxVehicleChassisData& chassisData, PxPhysics* physics) { //Add all the wheel shapes to the actor. for(PxU32 i=0;isetQueryFilterData(vehQryFilterData); wheelShape->setSimulationFilterData(wheelCollFilterData); wheelShape->setLocalPose(wheelLocalPoses[i]); } //Add the chassis shapes to the actor. for(PxU32 i=0;isetQueryFilterData(vehQryFilterData); chassisShape->setSimulationFilterData(chassisCollFilterData); chassisShape->setLocalPose(chassisLocalPoses[i]); } vehActor->setMass(chassisData.mMass); vehActor->setMassSpaceInertiaTensor(chassisData.mMOI); vehActor->setCMassLocalPose(PxTransform(chassisData.mCMOffset,PxQuat(PxIdentity))); } PxRigidDynamic* createVehicleActor4W (const PxVehicleChassisData& chassisData, PxConvexMesh** wheelConvexMeshes, PxConvexMesh* chassisConvexMesh, PxScene& scene, PxPhysics& physics, const PxMaterial& material) { //We need a rigid body actor for the vehicle. //Don't forget to add the actor the scene after setting up the associated vehicle. PxRigidDynamic* vehActor=physics.createRigidDynamic(PxTransform(PxIdentity)); //We need to add wheel collision shapes, their local poses, a material for the wheels, and a simulation filter for the wheels. PxConvexMeshGeometry frontLeftWheelGeom(wheelConvexMeshes[0]); PxConvexMeshGeometry frontRightWheelGeom(wheelConvexMeshes[1]); PxConvexMeshGeometry rearLeftWheelGeom(wheelConvexMeshes[2]); PxConvexMeshGeometry rearRightWheelGeom(wheelConvexMeshes[3]); const PxGeometry* wheelGeometries[4]={&frontLeftWheelGeom,&frontRightWheelGeom,&rearLeftWheelGeom,&rearRightWheelGeom}; const PxTransform wheelLocalPoses[4]={PxTransform(PxIdentity),PxTransform(PxIdentity),PxTransform(PxIdentity),PxTransform(PxIdentity)}; const PxMaterial& wheelMaterial=material; PxFilterData wheelCollFilterData; wheelCollFilterData.word0=COLLISION_FLAG_WHEEL; wheelCollFilterData.word1=COLLISION_FLAG_WHEEL_AGAINST; //We need to add chassis collision shapes, their local poses, a material for the chassis, and a simulation filter for the chassis. PxConvexMeshGeometry chassisConvexGeom(chassisConvexMesh); const PxGeometry* chassisGeoms[1]={&chassisConvexGeom}; const PxTransform chassisLocalPoses[1]={PxTransform(PxIdentity)}; const PxMaterial& chassisMaterial=material; PxFilterData chassisCollFilterData; chassisCollFilterData.word0=COLLISION_FLAG_CHASSIS; chassisCollFilterData.word1=COLLISION_FLAG_CHASSIS_AGAINST; //Create a query filter data for the car to ensure that cars //do not attempt to drive on themselves. PxFilterData vehQryFilterData; SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData); //Set up the physx rigid body actor with shapes, local poses, and filters. setupActor (vehActor, vehQryFilterData, wheelGeometries,wheelLocalPoses,4,&wheelMaterial,wheelCollFilterData, chassisGeoms,chassisLocalPoses,1,&chassisMaterial,chassisCollFilterData, chassisData, &physics); return vehActor; } void computeWheelWidthsAndRadii(PxConvexMesh** wheelConvexMeshes, PxF32* wheelWidths, PxF32* wheelRadii) { for(PxU32 i=0;i<4;i++) { const PxU32 numWheelVerts=wheelConvexMeshes[i]->getNbVertices(); const PxVec3* wheelVerts=wheelConvexMeshes[i]->getVertices(); PxVec3 wheelMin(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32); PxVec3 wheelMax(-PX_MAX_F32,-PX_MAX_F32,-PX_MAX_F32); for(PxU32 j=0;jgetNbVertices(); const PxVec3* chassisVerts=chassisConvexMesh->getVertices(); PxVec3 chassisMin(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32); PxVec3 chassisMax(-PX_MAX_F32,-PX_MAX_F32,-PX_MAX_F32); for(PxU32 i=0;isetup(&physics,vehActor,*wheelsSimData,driveSimData,0); //Free the sim data because we don't need that any more. wheelsSimData->free(); //Don't forget to add the actor to the scene. { PxSceneWriteLock scopedLock(scene); scene.addActor(*vehActor); } //Set up the mapping between wheel and actor shape. car->mWheelsSimData.setWheelShapeMapping(0,0); car->mWheelsSimData.setWheelShapeMapping(1,1); car->mWheelsSimData.setWheelShapeMapping(2,2); car->mWheelsSimData.setWheelShapeMapping(3,3); //Set up the scene query filter data for each suspension line. PxFilterData vehQryFilterData; SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData); //Set the transform and the instantiated car and set it be to be at rest. resetNWCar(startTransform,car); //Set the autogear mode of the instantiate car. car->mDriveDynData.setUseAutoGears(useAutoGearFlag); //Increment the number of vehicles mVehicles[mNumVehicles]=car; mVehicleWheelQueryResults[mNumVehicles].nbWheelQueryResults=4; mVehicleWheelQueryResults[mNumVehicles].wheelQueryResults=mWheelQueryResults->addVehicle(4); mNumVehicles++; } PxRigidDynamic* createVehicleActor6W (const PxVehicleChassisData& chassisData, PxConvexMesh** wheelConvexMeshes, PxConvexMesh* chassisConvexMesh, PxScene& scene, PxPhysics& physics, const PxMaterial& material) { PxTransform ident=PxTransform(PxIdentity); //We need a rigid body actor for the vehicle. //Don't forget to add the actor the scene after setting up the associated vehicle. PxRigidDynamic* vehActor=physics.createRigidDynamic(PxTransform(PxIdentity)); //We need to add wheel collision shapes, their local poses, a material for the wheels, and a simulation filter for the wheels. PxConvexMeshGeometry frontLeftWheelGeom(wheelConvexMeshes[0]); PxConvexMeshGeometry frontRightWheelGeom(wheelConvexMeshes[1]); PxConvexMeshGeometry rearLeftWheelGeom(wheelConvexMeshes[2]); PxConvexMeshGeometry rearRightWheelGeom(wheelConvexMeshes[3]); PxConvexMeshGeometry extraWheel0(wheelConvexMeshes[0]); PxConvexMeshGeometry extraWheel1(wheelConvexMeshes[1]); const PxGeometry* wheelGeoms[6]={&frontLeftWheelGeom,&frontRightWheelGeom,&rearLeftWheelGeom,&rearRightWheelGeom,&extraWheel0,&extraWheel1}; const PxTransform wheelLocalPoses[6]={ident,ident,ident,ident,ident,ident}; const PxMaterial& wheelMaterial=material; PxFilterData wheelCollFilterData; wheelCollFilterData.word0=COLLISION_FLAG_WHEEL; wheelCollFilterData.word1=COLLISION_FLAG_WHEEL_AGAINST; //We need to add chassis collision shapes, their local poses, a material for the chassis, and a simulation filter for the chassis. PxConvexMeshGeometry chassisConvexGeom(chassisConvexMesh); const PxGeometry* chassisGeoms[1]={&chassisConvexGeom}; const PxTransform chassisLocalPoses[1]={ident}; const PxMaterial& chassisMaterial=material; PxFilterData chassisCollFilterData; chassisCollFilterData.word0=COLLISION_FLAG_CHASSIS; chassisCollFilterData.word1=COLLISION_FLAG_CHASSIS_AGAINST; //Create a query filter data for the car to ensure that cars //do not attempt to drive on themselves. PxFilterData vehQryFilterData; SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData); //Set up the physx rigid body actor with shapes, local poses, and filters. setupActor( vehActor, vehQryFilterData, wheelGeoms,wheelLocalPoses,6,&wheelMaterial,wheelCollFilterData, chassisGeoms,chassisLocalPoses,1,&chassisMaterial,chassisCollFilterData, chassisData, &physics); return vehActor; } void createVehicle6WSimulationData (const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4, PxVehicleWheelsSimData& wheelsSimData6W, PxVehicleDriveSimData4W& driveSimData6W, PxVehicleChassisData& chassisData6W) { //Start by constructing the simulation data for a 4-wheeled vehicle. PxVehicleWheelsSimData* wheelsSimData4W=PxVehicleWheelsSimData::allocate(4); PxVehicleDriveSimData4W driveData4W; PxVehicleChassisData chassisData4W; createVehicle4WSimulationData( chassisMass,chassisConvexMesh, 20.0f,wheelConvexMeshes4,wheelCentreOffsets4, *wheelsSimData4W,driveData4W,chassisData4W); //Quickly setup the simulation data for the 6-wheeled vehicle. //(this will copy wheel4 from wheel0 and wheel5 from wheel1). driveSimData6W=driveData4W; wheelsSimData6W.copy(*wheelsSimData4W,0,0); wheelsSimData6W.copy(*wheelsSimData4W,1,1); wheelsSimData6W.copy(*wheelsSimData4W,2,2); wheelsSimData6W.copy(*wheelsSimData4W,3,3); wheelsSimData6W.copy(*wheelsSimData4W,0,4); wheelsSimData6W.copy(*wheelsSimData4W,1,5); wheelsSimData6W.setTireLoadFilterData(wheelsSimData4W->getTireLoadFilterData()); chassisData6W = chassisData4W; //Make sure that the two non-driven wheels don't respond to the handbrake. PxVehicleWheelData wheelData; wheelData=wheelsSimData6W.getWheelData(4); wheelData.mMaxHandBrakeTorque=0.0f; wheelsSimData6W.setWheelData(4,wheelData); wheelData=wheelsSimData6W.getWheelData(5); wheelData.mMaxHandBrakeTorque=0.0f; wheelsSimData6W.setWheelData(5,wheelData); //We've now got a 6-wheeled vehicle but the offsets of the 2 extra wheels are still incorrect. //Lets set up the 2 extra wheels to lie on an axle that goes through the centre of the car //and is parallel to the front and rear axles. { PxVec3 w; PxF32 offsetLeft; PxF32 offsetRight; offsetLeft=0.5f*(wheelsSimData6W.getWheelCentreOffset(0).z+wheelsSimData6W.getWheelCentreOffset(2).z); w=wheelsSimData4W->getWheelCentreOffset(0); w.z=offsetLeft; wheelsSimData6W.setWheelCentreOffset(4,w); offsetRight=0.5f*(wheelsSimData6W.getWheelCentreOffset(1).z+wheelsSimData6W.getWheelCentreOffset(3).z); w=wheelsSimData6W.getWheelCentreOffset(1); w.z=offsetRight; wheelsSimData6W.setWheelCentreOffset(5,w); offsetLeft=0.5f*(wheelsSimData6W.getSuspForceAppPointOffset(0).z+wheelsSimData6W.getSuspForceAppPointOffset(2).z); w=wheelsSimData4W->getSuspForceAppPointOffset(0); w.z=offsetLeft; wheelsSimData6W.setSuspForceAppPointOffset(4,w); offsetRight=0.5f*(wheelsSimData6W.getSuspForceAppPointOffset(1).z+wheelsSimData6W.getSuspForceAppPointOffset(3).z); w=wheelsSimData6W.getSuspForceAppPointOffset(1); w.z=offsetRight; wheelsSimData6W.setSuspForceAppPointOffset(5,w); offsetLeft=0.5f*(wheelsSimData6W.getTireForceAppPointOffset(0).z+wheelsSimData6W.getTireForceAppPointOffset(2).z); w=wheelsSimData4W->getTireForceAppPointOffset(0); w.z=offsetLeft; wheelsSimData6W.setTireForceAppPointOffset(4,w); offsetRight=0.5f*(wheelsSimData6W.getTireForceAppPointOffset(1).z+wheelsSimData6W.getTireForceAppPointOffset(3).z); w=wheelsSimData6W.getTireForceAppPointOffset(1); w.z=offsetRight; wheelsSimData6W.setTireForceAppPointOffset(5,w); } //The first 4 wheels were all set up to support a mass M but now that mass is //distributed between 6 wheels. Adjust the suspension springs accordingly //and try to preserve the natural frequency and damping ratio of the springs. for(PxU32 i=0;i<4;i++) { PxVehicleSuspensionData suspData=wheelsSimData6W.getSuspensionData(i); suspData.mSprungMass*=0.6666f; suspData.mSpringStrength*=0.666f; suspData.mSpringDamperRate*=0.666f; wheelsSimData6W.setSuspensionData(i,suspData); } const PxF32 sprungMass=(wheelsSimData6W.getSuspensionData(0).mSprungMass+wheelsSimData6W.getSuspensionData(3).mSprungMass)/2.0f; const PxF32 strength=(wheelsSimData6W.getSuspensionData(0).mSpringStrength+wheelsSimData6W.getSuspensionData(3).mSpringStrength)/2.0f; const PxF32 damperRate=(wheelsSimData6W.getSuspensionData(0).mSpringDamperRate+wheelsSimData6W.getSuspensionData(3).mSpringDamperRate)/2.0f; PxVehicleSuspensionData suspData4=wheelsSimData6W.getSuspensionData(4); suspData4.mSprungMass=sprungMass; suspData4.mSpringStrength=strength; suspData4.mSpringDamperRate=damperRate; wheelsSimData6W.setSuspensionData(4,suspData4); PxVehicleSuspensionData suspData5=wheelsSimData6W.getSuspensionData(5); suspData5.mSprungMass=sprungMass; suspData5.mSpringStrength=strength; suspData5.mSpringDamperRate=damperRate; wheelsSimData6W.setSuspensionData(5,suspData5); //Free the 4W sim data because we don't need this any more. wheelsSimData4W->free(); } void createVehicle6WSimulationData (const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4, PxVehicleWheelsSimData& wheelsSimData6W, PxVehicleDriveSimDataNW& driveSimData6W, PxVehicleChassisData& chassisData6W) { //Start by constructing the simulation data for a 4-wheeled vehicle. PxVehicleWheelsSimData* wheelsSimData4W=PxVehicleWheelsSimData::allocate(4); PxVehicleDriveSimData4W driveData4W; PxVehicleChassisData chassisData4W; createVehicle4WSimulationData( chassisMass,chassisConvexMesh, 20.0f,wheelConvexMeshes4,wheelCentreOffsets4, *wheelsSimData4W,driveData4W,chassisData4W); //Quickly setup the simulation data for the 6-wheeled vehicle. //(this will copy wheel4 from wheel0 and wheel5 from wheel1). driveSimData6W.setAutoBoxData(driveData4W.getAutoBoxData()); driveSimData6W.setClutchData(driveData4W.getClutchData()); driveSimData6W.setEngineData(driveData4W.getEngineData()); driveSimData6W.setGearsData(driveData4W.getGearsData()); PxVehicleDifferentialNWData diffNW; diffNW.setDrivenWheel(0,true); diffNW.setDrivenWheel(1,true); diffNW.setDrivenWheel(2,true); diffNW.setDrivenWheel(3,true); diffNW.setDrivenWheel(4,true); diffNW.setDrivenWheel(5,true); driveSimData6W.setDiffData(diffNW); wheelsSimData6W.copy(*wheelsSimData4W,0,0); wheelsSimData6W.copy(*wheelsSimData4W,1,1); wheelsSimData6W.copy(*wheelsSimData4W,2,2); wheelsSimData6W.copy(*wheelsSimData4W,3,3); wheelsSimData6W.copy(*wheelsSimData4W,0,4); wheelsSimData6W.copy(*wheelsSimData4W,1,5); wheelsSimData6W.setTireLoadFilterData(wheelsSimData4W->getTireLoadFilterData()); chassisData6W = chassisData4W; //Make sure that the two non-driven wheels don't respond to the handbrake. PxVehicleWheelData wheelData; wheelData=wheelsSimData6W.getWheelData(4); wheelData.mMaxHandBrakeTorque=0.0f; wheelsSimData6W.setWheelData(4,wheelData); wheelData=wheelsSimData6W.getWheelData(5); wheelData.mMaxHandBrakeTorque=0.0f; wheelsSimData6W.setWheelData(5,wheelData); //We've now got a 6-wheeled vehicle but the offsets of the 2 extra wheels are still incorrect. //Lets set up the 2 extra wheels to lie on an axle that goes through the centre of the car //and is parallel to the front and rear axles. { PxVec3 w; PxF32 offsetLeft; PxF32 offsetRight; offsetLeft=0.5f*(wheelsSimData6W.getWheelCentreOffset(0).z+wheelsSimData6W.getWheelCentreOffset(2).z); w=wheelsSimData4W->getWheelCentreOffset(0); w.z=offsetLeft; wheelsSimData6W.setWheelCentreOffset(4,w); offsetRight=0.5f*(wheelsSimData6W.getWheelCentreOffset(1).z+wheelsSimData6W.getWheelCentreOffset(3).z); w=wheelsSimData6W.getWheelCentreOffset(1); w.z=offsetRight; wheelsSimData6W.setWheelCentreOffset(5,w); offsetLeft=0.5f*(wheelsSimData6W.getSuspForceAppPointOffset(0).z+wheelsSimData6W.getSuspForceAppPointOffset(2).z); w=wheelsSimData4W->getSuspForceAppPointOffset(0); w.z=offsetLeft; wheelsSimData6W.setSuspForceAppPointOffset(4,w); offsetRight=0.5f*(wheelsSimData6W.getSuspForceAppPointOffset(1).z+wheelsSimData6W.getSuspForceAppPointOffset(3).z); w=wheelsSimData6W.getSuspForceAppPointOffset(1); w.z=offsetRight; wheelsSimData6W.setSuspForceAppPointOffset(5,w); offsetLeft=0.5f*(wheelsSimData6W.getTireForceAppPointOffset(0).z+wheelsSimData6W.getTireForceAppPointOffset(2).z); w=wheelsSimData4W->getTireForceAppPointOffset(0); w.z=offsetLeft; wheelsSimData6W.setTireForceAppPointOffset(4,w); offsetRight=0.5f*(wheelsSimData6W.getTireForceAppPointOffset(1).z+wheelsSimData6W.getTireForceAppPointOffset(3).z); w=wheelsSimData6W.getTireForceAppPointOffset(1); w.z=offsetRight; wheelsSimData6W.setTireForceAppPointOffset(5,w); } //The first 4 wheels were all set up to support a mass M but now that mass is //distributed between 6 wheels. Adjust the suspension springs accordingly //and try to preserve the natural frequency and damping ratio of the springs. for(PxU32 i=0;i<4;i++) { PxVehicleSuspensionData suspData=wheelsSimData6W.getSuspensionData(i); suspData.mSprungMass*=0.6666f; suspData.mSpringStrength*=0.666f; suspData.mSpringDamperRate*=0.666f; wheelsSimData6W.setSuspensionData(i,suspData); } const PxF32 sprungMass=(wheelsSimData6W.getSuspensionData(0).mSprungMass+wheelsSimData6W.getSuspensionData(3).mSprungMass)/2.0f; const PxF32 strength=(wheelsSimData6W.getSuspensionData(0).mSpringStrength+wheelsSimData6W.getSuspensionData(3).mSpringStrength)/2.0f; const PxF32 damperRate=(wheelsSimData6W.getSuspensionData(0).mSpringDamperRate+wheelsSimData6W.getSuspensionData(3).mSpringDamperRate)/2.0f; PxVehicleSuspensionData suspData4=wheelsSimData6W.getSuspensionData(4); suspData4.mSprungMass=sprungMass; suspData4.mSpringStrength=strength; suspData4.mSpringDamperRate=damperRate; wheelsSimData6W.setSuspensionData(4,suspData4); PxVehicleSuspensionData suspData5=wheelsSimData6W.getSuspensionData(5); suspData5.mSprungMass=sprungMass; suspData5.mSpringStrength=strength; suspData5.mSpringDamperRate=damperRate; wheelsSimData6W.setSuspensionData(5,suspData5); //Free the 4W sim data because we don't need this any more. wheelsSimData4W->free(); } void SampleVehicle_VehicleManager::create6WVehicle (PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material, const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4, const PxTransform& startTransform, const bool useAutoGearFlag) { PX_ASSERT(mNumVehiclessetup(&physics,vehActor,*wheelsSimData,driveSimData,6); //Free the sim data because we don't need that any more. wheelsSimData->free(); //Don't forget to add the actor to the scene. { PxSceneWriteLock scopedLock(scene); scene.addActor(*vehActor); } //Set up the mapping between wheel and actor shape. car->mWheelsSimData.setWheelShapeMapping(0,0); car->mWheelsSimData.setWheelShapeMapping(1,1); car->mWheelsSimData.setWheelShapeMapping(2,2); car->mWheelsSimData.setWheelShapeMapping(3,3); car->mWheelsSimData.setWheelShapeMapping(4,4); car->mWheelsSimData.setWheelShapeMapping(5,5); //Set up the scene query filter data for each suspension line. PxFilterData vehQryFilterData; SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(4, vehQryFilterData); car->mWheelsSimData.setSceneQueryFilterData(5, vehQryFilterData); //Set the transform and the instantiated car and set it be to be at rest. resetNWCar(startTransform,car); //Set the autogear mode of the instantiate car. car->mDriveDynData.setUseAutoGears(useAutoGearFlag); //Increment the number of vehicles mVehicles[mNumVehicles]=car; mVehicleWheelQueryResults[mNumVehicles].nbWheelQueryResults=6; mVehicleWheelQueryResults[mNumVehicles].wheelQueryResults=mWheelQueryResults->addVehicle(6); mNumVehicles++; } void setTank4WCustomisations(PxVehicleWheelsSimData& suspWheelTyreData, PxVehicleDriveSimData& coreData, const PxVehicleDriveTankControlModel::Enum tankDriveModel) { //Increase damping, especially when the clutch isn't engaged. for(PxU32 i=0;i<4;i++) { PxVehicleWheelData wheelData=suspWheelTyreData.getWheelData(i); wheelData.mDampingRate=2.0f; suspWheelTyreData.setWheelData(i,wheelData); } PxVehicleEngineData engineData=coreData.getEngineData(); engineData.mDampingRateZeroThrottleClutchEngaged=2.0f; engineData.mDampingRateZeroThrottleClutchDisengaged=0.5f; engineData.mDampingRateFullThrottle=0.5f; //engineData.mPeakTorque=1500; coreData.setEngineData(engineData); if(PxVehicleDriveTankControlModel::eSPECIAL==tankDriveModel) { PxVehicleGearsData gearsData=coreData.getGearsData(); gearsData.mFinalRatio=16; coreData.setGearsData(gearsData); } } void SampleVehicle_VehicleManager::create4WTank (PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material, const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4, const PxTransform& startTransform, const bool useAutoGearFlag, const PxVehicleDriveTankControlModel::Enum tankDriveModel) { PX_ASSERT(mNumVehicles<(MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES)); //Create simulation data for 4W drive car. PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(4); PxVehicleDriveSimData4W driveSimData; PxVehicleChassisData chassisData; createVehicle4WSimulationData( chassisMass,chassisConvexMesh, 20.0f,wheelConvexMeshes4,wheelCentreOffsets4, *wheelsSimData,driveSimData,chassisData); //Copy the relevant tank data and customise. PxVehicleDriveSimData tankDriveSimData; tankDriveSimData.setEngineData(driveSimData.getEngineData()); tankDriveSimData.setGearsData(driveSimData.getGearsData()); tankDriveSimData.setClutchData(driveSimData.getClutchData()); tankDriveSimData.setAutoBoxData(driveSimData.getAutoBoxData()); setTank4WCustomisations(*wheelsSimData,tankDriveSimData,tankDriveModel); //Instantiate and finalize the vehicle using physx. PxRigidDynamic* vehActor=createVehicleActor4W(chassisData,wheelConvexMeshes4,chassisConvexMesh,scene,physics,material); //Create a tank. PxVehicleDriveTank* tank = PxVehicleDriveTank::allocate(4); tank->setup(&physics,vehActor,*wheelsSimData,tankDriveSimData,4); //Free the sim data because we don't need that any more. wheelsSimData->free(); //Don't forget to add the actor to the scene. scene.addActor(*vehActor); //Set up the mapping between wheel and actor shape. tank->mWheelsSimData.setWheelShapeMapping(0,0); tank->mWheelsSimData.setWheelShapeMapping(1,1); tank->mWheelsSimData.setWheelShapeMapping(2,2); tank->mWheelsSimData.setWheelShapeMapping(3,3); //Set up the scene query filter data for each suspension line. PxFilterData vehQryFilterData; SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData); //Set the transform and the instantiated car and set it be to be at rest. resetNWCar(startTransform,tank); //Set the autogear mode of the instantiate car. tank->mDriveDynData.setUseAutoGears(useAutoGearFlag); //Set the drive model. tank->setDriveModel(tankDriveModel); //Increment the number of vehicles mVehicles[mNumVehicles]=tank; mVehicleWheelQueryResults[mNumVehicles].nbWheelQueryResults=4; mVehicleWheelQueryResults[mNumVehicles].wheelQueryResults=mWheelQueryResults->addVehicle(4); mNumVehicles++; } void setTank6WCustomisations(PxVehicleWheelsSimData& suspWheelTyreData, PxVehicleDriveSimData& coreData, const PxVehicleDriveTankControlModel::Enum tankDriveModel) { //Increase damping, especially when the clutch isn't engaged. for(PxU32 i=0;i<6;i++) { PxVehicleWheelData wheelData=suspWheelTyreData.getWheelData(i); wheelData.mDampingRate=2.0f; suspWheelTyreData.setWheelData(i,wheelData); } PxVehicleEngineData engineData=coreData.getEngineData(); engineData.mDampingRateZeroThrottleClutchEngaged=2.0f; engineData.mDampingRateZeroThrottleClutchDisengaged=0.5f; engineData.mDampingRateFullThrottle=0.5f; //engineData.mPeakTorque=1500; coreData.setEngineData(engineData); if(PxVehicleDriveTankControlModel::eSPECIAL==tankDriveModel) { PxVehicleGearsData gearsData=coreData.getGearsData(); gearsData.mFinalRatio=16; coreData.setGearsData(gearsData); } } void SampleVehicle_VehicleManager::create6WTank (PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material, const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4, const PxTransform& startTransform, const bool useAutoGearFlag, const PxVehicleDriveTankControlModel::Enum tankDriveModel) { //Create simulation data for 4W drive car. PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(6); PxVehicleDriveSimData4W driveSimData; PxVehicleChassisData chassisData; createVehicle6WSimulationData(chassisMass,wheelCentreOffsets4,chassisConvexMesh,wheelConvexMeshes4,*wheelsSimData,driveSimData,chassisData); //Copy the relevant tank data and customize. PxVehicleDriveSimData tankDriveSimData; tankDriveSimData.setEngineData(driveSimData.getEngineData()); tankDriveSimData.setGearsData(driveSimData.getGearsData()); tankDriveSimData.setClutchData(driveSimData.getClutchData()); tankDriveSimData.setAutoBoxData(driveSimData.getAutoBoxData()); setTank6WCustomisations(*wheelsSimData,tankDriveSimData,tankDriveModel); //Instantiate and finalize the vehicle using physx. PxRigidDynamic* vehActor=createVehicleActor6W(chassisData,wheelConvexMeshes4,chassisConvexMesh,scene,physics,material); //Create a tank. PxVehicleDriveTank* tank = PxVehicleDriveTank::allocate(6); tank->setup(&physics,vehActor,*wheelsSimData,tankDriveSimData,6); //Free the sim data because we don't need that any more. wheelsSimData->free(); //Don't forget to add the actor to the scene. scene.addActor(*vehActor); //Set up the mapping between wheel and actor shape. tank->mWheelsSimData.setWheelShapeMapping(0,0); tank->mWheelsSimData.setWheelShapeMapping(1,1); tank->mWheelsSimData.setWheelShapeMapping(2,2); tank->mWheelsSimData.setWheelShapeMapping(3,3); tank->mWheelsSimData.setWheelShapeMapping(4,4); tank->mWheelsSimData.setWheelShapeMapping(5,5); //Set up the scene query filter data for each suspension line. PxFilterData vehQryFilterData; SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(4, vehQryFilterData); tank->mWheelsSimData.setSceneQueryFilterData(5, vehQryFilterData); //Set the transform and the instantiated car and set it be to be at rest. resetNWCar(startTransform,tank); //Set the autogear mode of the instantiate car. tank->mDriveDynData.setUseAutoGears(useAutoGearFlag); //set the drive model tank->setDriveModel(tankDriveModel); //Increment the number of vehicles mVehicles[mNumVehicles]=tank; mVehicleWheelQueryResults[mNumVehicles].nbWheelQueryResults=6; mVehicleWheelQueryResults[mNumVehicles].wheelQueryResults=mWheelQueryResults->addVehicle(6); mNumVehicles++; } void SampleVehicle_VehicleManager::switchTo3WDeltaMode(const PxU32 vehicleId) { //Get the vehicle that will be in 3-wheeled mode. PX_ASSERT(mVehicles[vehicleId]->getVehicleType()==PxVehicleTypes::eDRIVE4W); PxVehicleDrive4W* veh=(PxVehicleDrive4W*)mVehicles[vehicleId]; if(mIsIn3WMode) { switchTo4WMode(vehicleId); } else { veh->mWheelsSimData=*mWheelsSimData4W; veh->mDriveSimData=mDriveSimData4W; } PxVehicle4WEnable3WDeltaMode(veh->mWheelsSimData, veh->mWheelsDynData, veh->mDriveSimData); mIsIn3WMode=true; } void SampleVehicle_VehicleManager::switchTo3WTadpoleMode(const PxU32 vehicleId) { //Get the vehicle that will be in 3-wheeled mode. PX_ASSERT(mVehicles[vehicleId]->getVehicleType()==PxVehicleTypes::eDRIVE4W); PxVehicleDrive4W* veh=(PxVehicleDrive4W*)mVehicles[vehicleId]; if(mIsIn3WMode) { switchTo4WMode(vehicleId); } else { veh->mWheelsSimData=*mWheelsSimData4W; veh->mDriveSimData=mDriveSimData4W; } PxVehicle4WEnable3WTadpoleMode(veh->mWheelsSimData, veh->mWheelsDynData, veh->mDriveSimData); mIsIn3WMode=true; } void SampleVehicle_VehicleManager::switchTo4WMode(const PxU32 vehicleId) { //Get the vehicle that will be in 3-wheeled mode. PX_ASSERT(mVehicles[vehicleId]->getVehicleType()==PxVehicleTypes::eDRIVE4W); PxVehicleDrive4W* veh=(PxVehicleDrive4W*)mVehicles[vehicleId]; *mWheelsSimData4W=veh->mWheelsSimData; mDriveSimData4W=veh->mDriveSimData; mIsIn3WMode=false; }