Files
PhysX4.1/kaplademo/source/kaplaDemo/VehicleManager.cpp
2025-11-28 23:13:44 +05:30

500 lines
22 KiB
C++

//
// 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) 2018 NVIDIA Corporation. All rights reserved.
#include "SceneVehicleSceneQuery.h"
#include "VehicleManager.h"
#include "VehicleWheelQueryResults.h"
#include "vehicle/PxVehicleUtilSetup.h"
#include "PxRigidActorExt.h"
#include "PxSceneLock.h"
#include "PxD6Joint.h"
VehicleManager::VehicleManager() : mSqWheelRaycastBatchQuery(NULL)
{
}
VehicleManager::~VehicleManager()
{
PxCloseVehicleSDK();
}
void VehicleManager::init(PxPhysics& physics, const PxMaterial** drivableSurfaceMaterials, const PxVehicleDrivableSurfaceType* drivableSurfaceTypes)
{
//Initialise the sdk.
PxInitVehicleSDK(physics, NULL);
//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 vehicle ptrs to null.
mVehicle = 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 = VehicleSceneQueryData::allocate(4);
//Data to store reports for each wheel.
mWheelQueryResults = VehicleWheelQueryResults::allocate(4);
//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, 1.3f*TireFrictionMultipliers::getValue(i, j));
}
}
}
void VehicleManager::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 VehicleManager::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 VehicleManager::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, 5, 5);
//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 = 1500.0f;
engine.mMaxOmega = 1000.0f;//approx 6000 rpm
engine.mMOI = 2.f;
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 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->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, false);
//wheelShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
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->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, false);
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;
wheelCollFilterData.word2 = PxPairFlag::eMODIFY_CONTACTS;
//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;
VehicleSetupVehicleShapeQueryFilterData(&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 VehicleManager::resetNWCar(const PxTransform& startTransform, PxVehicleWheels* vehWheels)
{
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);
//Set the car's transform to be the start transform.
PxRigidDynamic* actor = vehWheels->getRigidDynamicActor();
PxSceneWriteLock scopedLock(*actor->getScene());
actor->setGlobalPose(startTransform);
}
void 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);
PxVehicleWheels* vehicles[1] = { mVehicle };
PxVehicleSuspensionRaycasts(mSqWheelRaycastBatchQuery, 1, vehicles, mSqData->getRaycastQueryResultBufferSize(), mSqData->getRaycastQueryResultBuffer());
}
void VehicleManager::suspensionSweeps(PxScene* scene)
{
//Create a scene query if we haven't already done so.
if (NULL == mSqWheelRaycastBatchQuery)
{
mSqWheelRaycastBatchQuery = mSqData->setUpBatchedSceneQuerySweep(scene);
}
//Raycasts.
PxSceneReadLock scopedLock(*scene);
PxVehicleWheels* vehicles[1] = { mVehicle };
PxVehicleSuspensionSweeps(mSqWheelRaycastBatchQuery, 1, vehicles, mSqData->getSweepQueryResultBufferSize(), mSqData->getSweepQueryResultBuffer(), 1);
}
void VehicleManager::update(const PxF32 timestep, const PxVec3& gravity)
{
PxVehicleWheels* vehicles[1] = { mVehicle };
PxVehicleUpdates(timestep, gravity, *mSurfaceTirePairs, 1, vehicles, &mVehicleWheelQueryResults);
}
void 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)
{
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;
VehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData);
car->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData);
car->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData);
car->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData);
car->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData);
//Set the autogear mode of the instantiate car.
car->mDriveDynData.setUseAutoGears(useAutoGearFlag);
car->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
//Increment the number of vehicles
mVehicle = car;
mVehicleWheelQueryResults.nbWheelQueryResults = 4;
mVehicleWheelQueryResults.wheelQueryResults = mWheelQueryResults->addVehicle(4);
PxQuat rotation(3.1415 / 2.f, PxVec3(0.f, 0.f, 1.f));
PxD6Joint* joint = PxD6JointCreate(physics, vehActor, PxTransform(rotation), NULL, PxTransform(rotation));
joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eY, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eZ, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eLIMITED);
joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eLIMITED);
PxJointLimitCone limitCone(3.1415/4.f, 3.1415 / 4.f);
joint->setSwingLimit(limitCone);
}