aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp')
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp1171
1 files changed, 1171 insertions, 0 deletions
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp
new file mode 100644
index 00000000..930804c8
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp
@@ -0,0 +1,1171 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 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"
+
+#include "PxVehicleSerialization.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;i<MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES;i++)
+ {
+ mVehicles[i]=NULL;
+ }
+
+ //Allocate simulation data so we can switch from 3-wheeled to 4-wheeled cars by switching simulation data.
+ mWheelsSimData4W = PxVehicleWheelsSimData::allocate(4);
+
+ //Scene query data for to allow raycasts for all suspensions of all vehicles.
+ mSqData = SampleVehicleSceneQueryData::allocate(MAX_NUM_4W_VEHICLES*4 + MAX_NUM_6W_VEHICLES*6);
+
+ //Data to store reports for each wheel.
+ mWheelQueryResults = SampleVehicleWheelQueryResults::allocate(MAX_NUM_4W_VEHICLES*4 + MAX_NUM_6W_VEHICLES*6);
+
+ //Set up the friction values arising from combinations of tire type and surface type.
+ mSurfaceTirePairs=PxVehicleDrivableSurfaceToTireFrictionPairs::allocate(MAX_NUM_TIRE_TYPES,MAX_NUM_SURFACE_TYPES);
+ mSurfaceTirePairs->setup(MAX_NUM_TIRE_TYPES,MAX_NUM_SURFACE_TYPES,drivableSurfaceMaterials,drivableSurfaceTypes);
+ for(PxU32 i=0;i<MAX_NUM_SURFACE_TYPES;i++)
+ {
+ for(PxU32 j=0;j<MAX_NUM_TIRE_TYPES;j++)
+ {
+ mSurfaceTirePairs->setTypePairFriction(i,j,TireFrictionMultipliers::getValue(i, j));
+ }
+ }
+}
+
+void SampleVehicle_VehicleManager::shutdown()
+{
+ //Remove the N-wheeled vehicles.
+ for(PxU32 i=0;i<mNumVehicles;i++)
+ {
+ switch(mVehicles[i]->getVehicleType())
+ {
+ 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(vehicleId<mNumVehicles);
+ resetNWCar(transform,mVehicles[vehicleId]);
+}
+
+void SampleVehicle_VehicleManager::suspensionRaycasts(PxScene* scene)
+{
+ //Create a scene query if we haven't already done so.
+ if(NULL==mSqWheelRaycastBatchQuery)
+ {
+ mSqWheelRaycastBatchQuery=mSqData->setUpBatchedSceneQuery(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;i<mNumVehicles;i++)
+ {
+ if(focusVehicle!=mVehicles[i])
+ {
+ vehicles[numVehicles]=mVehicles[i];
+ vehicleWheelQueryResults[numVehicles]=mVehicleWheelQueryResults[i];
+ numVehicles++;
+ }
+ else
+ {
+ focusVehicleWheelQueryResults[0]=mVehicleWheelQueryResults[i];
+ }
+ }
+ PxVehicleUpdates(timestep,gravity,*mSurfaceTirePairs,numVehicles,vehicles,vehicleWheelQueryResults);
+
+
+ //Update the vehicle for which we want to record debug data.
+ PxVehicleUpdateSingleVehicleAndStoreTelemetryData(timestep,gravity,*mSurfaceTirePairs,focusVehicle,focusVehicleWheelQueryResults,*telemetryData);
+}
+
+#else
+
+void SampleVehicle_VehicleManager::update(const PxF32 timestep, const PxVec3& gravity)
+{
+ PxVehicleUpdates(timestep,gravity,*mSurfaceTirePairs,mNumVehicles,mVehicles,mVehicleWheelQueryResults);
+}
+
+#endif //PX_DEBUG_VEHICLE_ON
+
+void SampleVehicle_VehicleManager::resetNWCar(const PxTransform& startTransform, PxVehicleWheels* vehWheels)
+{
+ switch(vehWheels->getVehicleType())
+ {
+ 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;i<numWheelGeometries;i++)
+ {
+ PxShape* wheelShape=PxRigidActorExt::createExclusiveShape(*vehActor, *wheelGeometries[i],*wheelMaterial);
+ wheelShape->setQueryFilterData(vehQryFilterData);
+ wheelShape->setSimulationFilterData(wheelCollFilterData);
+ wheelShape->setLocalPose(wheelLocalPoses[i]);
+ }
+
+ //Add the chassis shapes to the actor.
+ for(PxU32 i=0;i<numChassisGeometries;i++)
+ {
+ PxShape* chassisShape=PxRigidActorExt::createExclusiveShape(*vehActor, *chassisGeometries[i],*chassisMaterial);
+ chassisShape->setQueryFilterData(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;j<numWheelVerts;j++)
+ {
+ wheelMin.x=PxMin(wheelMin.x,wheelVerts[j].x);
+ wheelMin.y=PxMin(wheelMin.y,wheelVerts[j].y);
+ wheelMin.z=PxMin(wheelMin.z,wheelVerts[j].z);
+ wheelMax.x=PxMax(wheelMax.x,wheelVerts[j].x);
+ wheelMax.y=PxMax(wheelMax.y,wheelVerts[j].y);
+ wheelMax.z=PxMax(wheelMax.z,wheelVerts[j].z);
+ }
+ wheelWidths[i]=wheelMax.x-wheelMin.x;
+ wheelRadii[i]=PxMax(wheelMax.y,wheelMax.z)*0.975f;
+ }
+}
+
+PxVec3 computeChassisAABBDimensions(const PxConvexMesh* chassisConvexMesh)
+{
+ const PxU32 numChassisVerts=chassisConvexMesh->getNbVertices();
+ 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;i<numChassisVerts;i++)
+ {
+ chassisMin.x=PxMin(chassisMin.x,chassisVerts[i].x);
+ chassisMin.y=PxMin(chassisMin.y,chassisVerts[i].y);
+ chassisMin.z=PxMin(chassisMin.z,chassisVerts[i].z);
+ chassisMax.x=PxMax(chassisMax.x,chassisVerts[i].x);
+ chassisMax.y=PxMax(chassisMax.y,chassisVerts[i].y);
+ chassisMax.z=PxMax(chassisMax.z,chassisVerts[i].z);
+ }
+ const PxVec3 chassisDims=chassisMax-chassisMin;
+ return chassisDims;
+}
+
+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;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mCamberAtMaxDroop=-camberAngleAtMaxDroop;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mCamberAtMaxDroop=camberAngleAtMaxDroop;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mCamberAtMaxDroop=-camberAngleAtMaxDroop;
+ //Set the wheels to camber outwards at maximum compression (the left and right wheels almost form a A shape).
+ const PxF32 camberAngleAtMaxCompression=-0.001f;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mCamberAtMaxCompression=camberAngleAtMaxCompression;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mCamberAtMaxCompression=-camberAngleAtMaxCompression;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mCamberAtMaxCompression=camberAngleAtMaxCompression;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mCamberAtMaxCompression=-camberAngleAtMaxCompression;
+
+ //We need to set up geometry data for the suspension, wheels, and tires.
+ //We already know the wheel centers described as offsets from the actor center and the center of mass offset from actor center.
+ //From here we can approximate application points for the tire and suspension forces.
+ //Lets assume that the suspension travel directions are absolutely vertical.
+ //Also assume that we apply the tire and suspension forces 30cm below the center of mass.
+ PxVec3 suspTravelDirections[4]={PxVec3(0,-1,0),PxVec3(0,-1,0),PxVec3(0,-1,0),PxVec3(0,-1,0)};
+ PxVec3 wheelCentreCMOffsets[4];
+ PxVec3 suspForceAppCMOffsets[4];
+ PxVec3 tireForceAppCMOffsets[4];
+ for(PxU32 i=0;i<4;i++)
+ {
+ wheelCentreCMOffsets[i]=wheelCentreOffsets[i]-chassisCMOffset;
+ suspForceAppCMOffsets[i]=PxVec3(wheelCentreCMOffsets[i].x,-0.3f,wheelCentreCMOffsets[i].z);
+ tireForceAppCMOffsets[i]=PxVec3(wheelCentreCMOffsets[i].x,-0.3f,wheelCentreCMOffsets[i].z);
+ }
+
+ //Now add the wheel, tire and suspension data.
+ for(PxU32 i=0;i<4;i++)
+ {
+ wheelsData.setWheelData(i,wheels[i]);
+ wheelsData.setTireData(i,tires[i]);
+ wheelsData.setSuspensionData(i,susps[i]);
+ wheelsData.setSuspTravelDirection(i,suspTravelDirections[i]);
+ wheelsData.setWheelCentreOffset(i,wheelCentreCMOffsets[i]);
+ wheelsData.setSuspForceAppPointOffset(i,suspForceAppCMOffsets[i]);
+ wheelsData.setTireForceAppPointOffset(i,tireForceAppCMOffsets[i]);
+ }
+
+ //Set the car to perform 3 sub-steps when it moves with a forwards speed of less than 5.0
+ //and with a single step when it moves at speed greater than or equal to 5.0.
+ wheelsData.setSubStepCount(5.0f, 3, 1);
+
+
+ //Now set up the differential, engine, gears, clutch, and ackermann steering.
+
+ //Diff
+ PxVehicleDifferential4WData diff;
+ diff.mType=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD;
+ driveData.setDiffData(diff);
+
+ //Engine
+ PxVehicleEngineData engine;
+ engine.mPeakTorque=500.0f;
+ engine.mMaxOmega=600.0f;//approx 6000 rpm
+ driveData.setEngineData(engine);
+
+ //Gears
+ PxVehicleGearsData gears;
+ gears.mSwitchTime=0.5f;
+ driveData.setGearsData(gears);
+
+ //Clutch
+ PxVehicleClutchData clutch;
+ clutch.mStrength=10.0f;
+ driveData.setClutchData(clutch);
+
+ //Ackermann steer accuracy
+ PxVehicleAckermannGeometryData ackermann;
+ ackermann.mAccuracy=1.0f;
+ ackermann.mAxleSeparation=wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].z-wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eREAR_LEFT].z;
+ ackermann.mFrontWidth=wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].x-wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].x;
+ ackermann.mRearWidth=wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].x-wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eREAR_LEFT].x;
+ driveData.setAckermannGeometryData(ackermann);
+}
+
+void SampleVehicle_VehicleManager::create4WVehicle
+(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(mNumVehicles<MAX_NUM_4W_VEHICLES);
+
+ PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(4);
+ PxVehicleDriveSimData4W driveSimData;
+ PxVehicleChassisData chassisData;
+ createVehicle4WSimulationData
+ (chassisMass,chassisConvexMesh,
+ 20.0f,wheelConvexMeshes4,wheelCentreOffsets4,
+ *wheelsSimData,driveSimData,chassisData);
+
+ //Instantiate and finalize the vehicle using physx.
+ PxRigidDynamic* vehActor=createVehicleActor4W(chassisData,wheelConvexMeshes4,chassisConvexMesh,scene,physics,material);
+
+ //Create a car.
+ PxVehicleDrive4W* car = PxVehicleDrive4W::allocate(4);
+ car->setup(&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(mNumVehicles<MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES);
+
+ //We're going to create an 4-wheeled vehicle then quickly copy components to make an 6-wheeled vehicle.
+ PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(6);
+ PxVehicleDriveSimDataNW driveSimData;
+ PxVehicleChassisData chassisData;
+ createVehicle6WSimulationData(chassisMass,wheelCentreOffsets4,chassisConvexMesh,wheelConvexMeshes4,*wheelsSimData,driveSimData,chassisData);
+
+ //Instantiate and finalize the vehicle using physx.
+ PxRigidDynamic* vehActor=createVehicleActor6W(chassisData,wheelConvexMeshes4,chassisConvexMesh,scene,physics,material);
+
+ //Create a car.
+ PxVehicleDriveNW* car = PxVehicleDriveNW::allocate(6);
+ car->setup(&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;
+}
+
+
+