diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleVehicle | |
| download | physx-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')
21 files changed, 7197 insertions, 0 deletions
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.cpp new file mode 100644 index 00000000..52f86b8c --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.cpp @@ -0,0 +1,2271 @@ +// 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 "RendererMemoryMacros.h" +#include "RenderMeshActor.h" +#include "SampleVehicle_VehicleCooking.h" +#include "SampleVehicle_SceneQuery.h" +#include "PxPhysicsAPI.h" +#include "extensions/PxExtensionsAPI.h" +#include "RenderPhysX3Debug.h" + +#include "SampleVehicleInputEventIds.h" +#include <SampleFrameworkInputEventIds.h> +#include <SampleBaseInputEventIds.h> +#include <SamplePlatform.h> +#include <SampleUserInput.h> +#include <SampleUserInputIds.h> +#include <SampleUserInputDefines.h> +#include "PxTkFile.h" + +REGISTER_SAMPLE(SampleVehicle, "SampleVehicle") + +enum +{ + LOAD_TYPE_VEHICLE=0, + LOAD_TYPE_LOOPTHELOOP, + LOAD_TYPE_SKYDOME, + MAX_NUM_LOAD_TYPES +}; +static PxU32 gLoadType = MAX_NUM_LOAD_TYPES; + +using namespace physx; +using namespace SampleRenderer; +using namespace SampleFramework; + +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////// +//VEHICLE START PARAMETERS +/////////////////////////////////// + +#define NUM_PLAYER_CARS 1 +static PxTransform gPlayerCarStartTransforms[NUM_PLAYER_CARS] = +{ + PxTransform(PxVec3(-154.699753f, 9.863837f, 87.684113f), PxQuat(-0.000555f, -0.267015, 0.000155, -0.963692 )) +}; + +#define NUM_NONPLAYER_4W_VEHICLES 7 +#if NUM_NONPLAYER_4W_VEHICLES +static PxTransform gVehicle4WStartTransforms[NUM_NONPLAYER_4W_VEHICLES] = +{ + //Stack of 2 cars + PxTransform(PxVec3(-78.796158f,9.8764671f,155.47554f), PxQuat(0.00062184106f,0.97696519f,-0.0029967001f,0.21337670f)), + PxTransform(PxVec3(-78.796158f,11.7764671f,155.47554f), PxQuat(0.00062184106f,0.97696519f,-0.0029967001f,0.21337670f)), + + //Stack of 2 cars + PxTransform(PxVec3(-80.391357f,9.8760214f,161.93578f), PxQuat(1.0251222e-005f, 0.98799443f, -6.0369461e-005f, 0.15448983f)), + PxTransform(PxVec3(-80.391357f,11.7760214f,161.93578f), PxQuat(1.0251222e-005f, 0.98799443f, -6.0369461e-005f, 0.15448983f)), + + //Bookends to car stacks + PxTransform(PxVec3(-77.945328f,9.9765568f,151.78404f), PxQuat(0.0014836629f,-0.86193967f,0.0024594457f,0.50700283f)), + PxTransform(PxVec3(-80.395328f,9.8786600f,167.44662f), PxQuat(0.0014836629f,-0.86193967f,0.0024594457f,0.50700283f)), + + //Car in-between two ramps + PxTransform(PxVec3(116.04498f,9.9760214f,139.02933f), PxQuat(7.5981094e-005f,-0.38262743f,-3.1461415e-005f,-0.92390275f)), +}; +#endif + +#define NUM_NONPLAYER_6W_VEHICLES 1 +#if NUM_NONPLAYER_6W_VEHICLES +static PxTransform gVehicle6WStartTransforms[NUM_NONPLAYER_6W_VEHICLES]= +{ + //6-wheeled car + PxTransform(PxVec3(-158.09471f,9.8649321f,80.359474f), PxQuat(-0.0017525638f,-0.24773766f,0.00040674198f,-0.96882552f)) +}; +#endif + +#define NUM_NONPLAYER_4W_TANKS 0 +#if NUM_NONPLAYER_4W_TANKS +static PxTransform gTank4WStartTransforms[NUM_NONPLAYER_4W_TANKS]= +{ + //6-wheeled car + PxTransform(PxVec3(-158.09471f,9.8649321f,80.359474f), PxQuat(-0.0017525638f,-0.24773766f,0.00040674198f,-0.96882552f)) +}; +#endif + +#define NUM_NONPLAYER_6W_TANKS 0 +#if NUM_NONPLAYER_6W_TANKS +static PxTransform gTank6WStartTransforms[NUM_NONPLAYER_6W_TANKS]= +{ + //6-wheeled car + PxTransform(PxVec3(-158.09471f,9.8649321f,80.359474f), PxQuat(-0.0017525638f,-0.24773766f,0.00040674198f,-0.96882552f)) +}; +#endif + + +PxU32 gNumVehicleAdded=0; + +//////////////////////////////////////////////////////////////// +//VEHICLE SETUP DATA +//////////////////////////////////////////////////////////////// + +PxF32 gChassisMass=1500.0f; +PxF32 gSuspensionShimHeight=0.125f; + +//////////////////////////////////////////////////////////////// +//RENDER USER DATA TO ASSOCIATE EACH RENDER MESH WITH A +//VEHICLE PHYSICS COMPONENT +//////////////////////////////////////////////////////////////// + +enum +{ + CAR_PART_FRONT_LEFT_WHEEL=0, + CAR_PART_FRONT_RIGHT_WHEEL, + CAR_PART_REAR_LEFT_WHEEL, + CAR_PART_REAR_RIGHT_WHEEL, + CAR_PART_CHASSIS, + CAR_PART_WINDOWS, + NUM_CAR4W_RENDER_COMPONENTS, + CAR_PART_EXTRA_WHEEL0=NUM_CAR4W_RENDER_COMPONENTS, + CAR_PART_EXTRA_WHEEL1, + NUM_CAR6W_RENDER_COMPONENTS +}; + +static const char gCarPartNames[NUM_CAR4W_RENDER_COMPONENTS][64]= +{ + "frontwheelleftshape", + "frontwheelrightshape", + "backwheelleftshape", + "backwheelrightshape", + "car_02_visshape", + "car_02_windowsshape" +}; + +struct CarRenderUserData +{ + PxU8 carId; + PxU8 carPart; + PxU8 carPartDependency; + PxU8 pad; +}; + +static const CarRenderUserData gCar4WRenderUserData[NUM_CAR6W_RENDER_COMPONENTS] = +{ + //wheel fl wheel fr wheel rl wheel rl chassis windows extra wheel0 extra wheel1 + {0,0,255}, {0,1,255}, {0,2,255}, {0,3,255}, {0,4,255}, {0,4,4}, {255,255,255}, {255,255,255} +}; + +static const CarRenderUserData gCar6WRenderUserData[NUM_CAR6W_RENDER_COMPONENTS] = +{ + //wheel fl wheel fr wheel rl wheel rl chassis windows extra wheel0 extra wheel1 + {0,0,255}, {0,1,255}, {0,2,255}, {0,3,255}, {0,6,255}, {0,6,6}, {0,4,255}, {0,5,255} +}; + +CarRenderUserData gVehicleRenderUserData[NUM_PLAYER_CARS + NUM_NONPLAYER_4W_VEHICLES + NUM_NONPLAYER_6W_VEHICLES + NUM_NONPLAYER_4W_TANKS + NUM_NONPLAYER_6W_TANKS][NUM_CAR6W_RENDER_COMPONENTS]; + +RenderMeshActor* gRenderMeshActors[NUM_CAR6W_RENDER_COMPONENTS]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + +//////////////////////////////////////////////////////////////// +//TRANSFORM APPLIED TO CHASSIS RENDER MESH VERTS +//THAT IS REQUIRED TO PLACE AABB OF CHASSIS RENDER MESH AT ORIGIN +//AT CENTRE-POINT OF WHEELS. +//////////////////////////////////////////////////////////////// + +static PxVec3 gChassisMeshTransform(0,0,0); + +//////////////////////////////////////////////////////////////// +//WHEEL CENTRE OFFSETS FROM CENTRE OF CHASSIS RENDER MESH AABB +//OF 4-WHEELED VEHICLE +//////////////////////////////////////////////////////////////// + +static PxVec3 gWheelCentreOffsets4[4]; + +//////////////////////////////////////////////////////////////// +//CONVEX HULL OF RENDER MESH FOR CHASSIS AND WHEELS OF +//4-WHEELED VEHICLE +//////////////////////////////////////////////////////////////// + +static PxConvexMesh* gChassisConvexMesh=NULL; +static PxConvexMesh* gWheelConvexMeshes4[4]={NULL,NULL,NULL,NULL}; + +//////////////////////////////////////////////////////////////// +//Revolute joints and gian pendula +//////////////////////////////////////////////////////////////// + +#define MAX_NUM_PENDULA 4 + +PxTransform gPendulaBallStartTransforms[MAX_NUM_PENDULA]= +{ + PxTransform(PxVec3( 151.867020 , 11.364232 , 97.350906 ), PxQuat( -0.000106 , -0.951955 , 0.000370 , -0.306239 ) ) , + PxTransform(PxVec3( 163.001953 , 11.364203 , 77.854568 ), PxQuat( -0.000070 , -0.971984 , 0.000323 , -0.235048 ) ) , + PxTransform(PxVec3( 173.971405 , 11.364145 , 45.944290 ), PxQuat( -0.000050 , -0.994988 , 0.000448 , -0.099990 ) ) , + PxTransform(PxVec3( 179.876785 , 11.364090 , 3.679581 ), PxQuat( -0.000024 , -1.000000 , 0.000431 , -0.000193 ) ) +}; + +PxF32 gPendulumBallRadius=2.0f; +PxF32 gPendulumBallMass=1000.0f; +PxF32 gPendulumShaftLength=10.0f; +PxF32 gPendulumShaftWidth=0.1f; +PxF32 gPendulumSuspensionStructureWidth=13.0f; + +PxRevoluteJoint* gRevoluteJoints[MAX_NUM_PENDULA]={NULL,NULL,NULL,NULL}; +PxF32 gRevoluteJointDriveSpeeds[MAX_NUM_PENDULA]={0.932f,1.0f,1.237f,0.876f}; +PxF32 gRevoluteJointTimers[MAX_NUM_PENDULA]={0,0,0,0}; +PxU32 gNumRevoluteJoints=0; +PxF32 gRevoluteJointMaxTheta=0; + +//////////////////////////////////////////////////////////////// +//Route +//////////////////////////////////////////////////////////////// + +PxTransform gWayPoints[35]= +{ + PxTransform(PxVec3( -154.699753 , 9.863837 , 87.684113 ), PxQuat( -0.000555 , -0.267015 , 0.000155 , -0.963692 ) ) , + PxTransform(PxVec3( -133.385757 , 9.863703 , 118.680717 ), PxQuat( -0.000620 , -0.334975 , 0.000219 , -0.942227 ) ) , + PxTransform(PxVec3( -103.853020 , 9.863734 , 146.631256 ), PxQuat( -0.000560 , -0.474673 , 0.000301 , -0.880162 ) ) , + PxTransform(PxVec3( -20.397881 , 9.862607 , 177.345657 ), PxQuat( -0.000938 , -0.674493 , 0.000867 , -0.738281 ) ) , + PxTransform(PxVec3( 14.272619 , 9.863173 , 178.745789 ), PxQuat( -0.000736 , -0.723563 , 0.000740 , -0.690257 ) ) , + PxTransform(PxVec3( 49.057743 , 9.862507 , 173.464539 ), PxQuat( -0.000387 , -0.794072 , 0.001316 , -0.607822 ) ) , + PxTransform(PxVec3( 82.226036 , 9.862642 , 159.649200 ), PxQuat( -0.000670 , -0.853613 , 0.001099 , -0.520905 ) ) , + PxTransform(PxVec3( 158.675018 , 9.864265 , 86.166740 ), PxQuat( -0.000052 , -0.973169 , 0.000286 , -0.230092 ) ) , + PxTransform(PxVec3( 165.983170 , 9.857763 , 67.031097 ), PxQuat( -0.014701 , -0.979587 , 0.002133 , 0.200471 ) ) , + PxTransform(PxVec3( 177.577393 , 9.864532 , 30.462427 ), PxQuat( 0.000022 , -0.998473 , -0.000423 , -0.055239 ) ) , + PxTransform(PxVec3( 180.127686 , 9.864151 , -10.116920 ), PxQuat( 0.000011 , 0.999869 , 0.000295 , -0.016194 ) ) , + PxTransform(PxVec3( 174.281616 , 9.863608 , -42.319435 ), PxQuat( 0.000168 , 0.989981 , -0.001008 , -0.141194 ) ) , + PxTransform(PxVec3( 166.054413 , 9.864248 , -68.973045 ), PxQuat( -0.000052 , 0.985021 , -0.000213 , -0.172433 ) ) , + PxTransform(PxVec3( 154.505814 , 9.864180 , -77.992622 ), PxQuat( -0.000098 , 0.754213 , -0.000129 , -0.656630 ) ) , + PxTransform(PxVec3( 140.834076 , 9.863158 , -78.122841 ), PxQuat( -0.000730 , 0.709598 , -0.000737 , -0.704606 ) ) , + PxTransform(PxVec3( 100.152573 , 9.853898 , -78.407364 ), PxQuat( 0.066651 , 0.683499 , 0.070412 , -0.723484 ) ) , + PxTransform(PxVec3( 68.866241 , 10.293923 , -77.979095 ), PxQuat( -0.045687 , 0.703115 , -0.044258 , -0.708225 ) ), + PxTransform(PxVec3( 26.558704 , 10.495461 , -77.729164 ), PxQuat( -0.018349 , 0.708445 , -0.018563 , -0.705283 ) ) , + PxTransform(PxVec3( -2.121686 , 9.860541 , -77.735886 ), PxQuat( -0.000792 , 0.706926 , -0.000792 , -0.707287 ) ) , + PxTransform(PxVec3( -28.991186 , 9.867218 , -77.722122 ), PxQuat( -0.000251 , 0.706926 , -0.000251 , -0.707287 ) ) , + PxTransform(PxVec3( -59.285870 , 9.861916 , -77.746246 ), PxQuat( -0.001042 , 0.708723 , -0.001048 , -0.705485 ) ) , + PxTransform(PxVec3( -73.170433 , 9.863565 , -78.034157 ), PxQuat( -0.001567 , 0.736642 , -0.001323 , -0.676280 ) ) , + PxTransform(PxVec3( -77.792152 , 9.864209 , -87.821510 ), PxQuat( 0.000006 , 0.999772 , -0.000294 , -0.021342 ) ) , + PxTransform(PxVec3( -78.164032 , 9.862655 , -114.313690 ), PxQuat( -0.000010 , 0.999962 , -0.001280 , -0.008618 ) ), + PxTransform(PxVec3( -78.567627 , 9.862757 , -137.274292 ), PxQuat( -0.000010 , 0.999961 , -0.001146 , -0.008796 ) ) , + PxTransform(PxVec3( -80.392769 , 9.863695 , -149.740082 ), PxQuat( -0.000149 , 0.987276 , -0.000512 , -0.159015 ) ) , + PxTransform(PxVec3( -88.452507 , 9.864114 , -152.396698 ), PxQuat( -0.000355 , 0.622921 , -0.000278 , -0.782285 ) ) , + PxTransform(PxVec3( -106.042450 , 9.863844 , -144.640076 ), PxQuat( -0.000485 , 0.459262 , -0.000133 , -0.888301 ) ) , + PxTransform(PxVec3( -134.893997 , 15.093562 , -114.433586 ), PxQuat( 0.073759 , 0.354141 , 0.027569 , -0.931871 ) ) , + PxTransform(PxVec3( -145.495453 , 9.864394 , -101.019417 ), PxQuat( -0.000351 , 0.305924 , -0.000104 , -0.952056 ) ) , + PxTransform(PxVec3( -152.808212 , 9.864192 , -86.800613 ), PxQuat( -0.000099 , 0.206095 , -0.000015 , -0.978532 ) ) , + PxTransform(PxVec3( -156.457855 , 9.864244 , -81.270035 ), PxQuat( -0.000420 , 0.201378 , -0.000086 , -0.979514 ) ) , + PxTransform(PxVec3( -169.079376 , 10.192255 , -48.906967 ), PxQuat( 0.003633 , 0.179159 , 0.000892 , -0.983813 ) ) , + PxTransform(PxVec3( -151.470123 , 7.783551 , -17.838057 ), PxQuat( 0.029215 , -0.077987 , -0.050732 , -0.995234 ) ) , + PxTransform(PxVec3( -171.549225 , 9.864206 , 47.239426 ), PxQuat( -0.000319 , -0.159609 , 0.000039 , -0.987180 ) ) +}; +PxU32 gNumWayPoints=35; + +/////////////////////////////////////////////////////////////////////////////// + + +SampleVehicle::SampleVehicle(PhysXSampleApplication& app) : + PhysXSample (app), + mTerrainVB (NULL), + mNbTerrainVerts (0), + mNbIB (0), + mChassisMaterialDrivable (NULL), + mChassisMaterialNonDrivable (NULL), + mTerrainMaterial (NULL), + mRoadMaterial (NULL), + mRoadIceMaterial (NULL), + mRoadGravelMaterial (NULL), + mPlayerVehicle (0), + mPlayerVehicleType (ePLAYER_VEHICLE_TYPE_VEHICLE4W), + //mPlayerVehicleType (ePLAYER_VEHICLE_TYPE_VEHICLE6W), + //mPlayerVehicleType (ePLAYER_VEHICLE_TYPE_TANK4W), + //mPlayerVehicleType (ePLAYER_VEHICLE_TYPE_TANK6W), + //mTankDriveModel (PxVehicleDriveTankControlModel::eSPECIAL), + //mTankDriveModel (PxVehicleDriveTankControlModel::eSTANDARD), + mTerrainSize (256), + mTerrainWidth (2.0f), + mHFActor (NULL), + mHideScreenText (false), + mDebugRenderFlag (false), + mFixCar (false), + mBackToStart (false), + m3WModeIncremented (false), + m3WMode (0), + mForwardSpeedHud (0.0f) +{ + mCreateGroundPlane = false; + //mStepperType = FIXED_STEPPER; + + for(PxU32 i=0;i<MAX_NUM_INDEX_BUFFERS;i++) + mStandardMaterials[i] = NULL; + +#if PX_DEBUG_VEHICLE_ON + mDebugRenderActiveGraphChannelWheel = 0; + mDebugRenderActiveGraphChannelEngine = 0; + mTelemetryData4W = NULL; + mTelemetryData6W = NULL; +#endif +} + +SampleVehicle::~SampleVehicle() +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleVehicle::customizeSample(SampleSetup& setup) +{ + setup.mName = "SampleVehicle"; +} + +void SampleVehicle::setupTelemetryData() +{ +#if PX_DEBUG_VEHICLE_ON + + mDebugRenderActiveGraphChannelWheel=PxVehicleWheelGraphChannel::eWHEEL_OMEGA; + mDebugRenderActiveGraphChannelEngine=PxVehicleDriveGraphChannel::eENGINE_REVS; + + { + const PxF32 graphSizeX=0.25f; + const PxF32 graphSizeY=0.25f; + const PxF32 engineGraphPosX=0.5f; + const PxF32 engineGraphPosY=0.5f; + const PxF32 wheelGraphPosX[4]={0.75f,0.25f,0.75f,0.25f}; + const PxF32 wheelGraphPosY[4]={0.75f,0.75f,0.25f,0.25f}; + const PxVec3 backgroundColor(255,255,255); + const PxVec3 lineColorHigh(255,0,0); + const PxVec3 lineColorLow(0,0,0); + + mTelemetryData4W = PxVehicleTelemetryData::allocate(4); + + mTelemetryData4W->setup + (graphSizeX,graphSizeY, + engineGraphPosX,engineGraphPosY, + wheelGraphPosX,wheelGraphPosY, + backgroundColor,lineColorHigh,lineColorLow); + } + + { + const PxF32 graphSizeX=0.225f; + const PxF32 graphSizeY=0.225f; + const PxF32 engineGraphPosX=0.5f; + const PxF32 engineGraphPosY=0.5f; + const PxF32 wheelGraphPosX[6]={0.75f,0.25f,0.75f,0.25f,0.75f,0.25f}; + const PxF32 wheelGraphPosY[8]={0.83f,0.83f,0.17f,0.17f,0.5f,0.5f}; + const PxVec3 backgroundColor(255,255,255); + const PxVec3 lineColorHigh(255,0,0); + const PxVec3 lineColorLow(0,0,0); + + mTelemetryData6W = PxVehicleTelemetryData::allocate(6); + + mTelemetryData6W->setup + (graphSizeX,graphSizeY, + engineGraphPosX,engineGraphPosY, + wheelGraphPosX,wheelGraphPosY, + backgroundColor,lineColorHigh,lineColorLow); + } + +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleVehicle::onInit() +{ + mNbThreads = PxMax(PxI32(shdfnd::Thread::getNbPhysicalCores())-1, 0); + + PhysXSample::onInit(); + + PxSceneWriteLock scopedLock(*mScene); + +#if defined(SERIALIZE_VEHICLE_BINARY) + mMemory = NULL; +#endif + + //Create physx objects. + createStandardMaterials(); + createVehicles(); + createTrack(mTerrainSize, mTerrainWidth, mTerrainSize*4.0f); + createObstacles(); + + //Setup camera. + setCameraController(NULL); + + //Setup debug render data. + setupTelemetryData(); + + //Setup the waypoint system. + mWayPoints.setWayPoints(gWayPoints,gNumWayPoints); + + //Load the skydome. + gLoadType = LOAD_TYPE_SKYDOME; + importRAWFile("sky_mission_race1.raw", 1.0f); + + //Set up the fog. + getRenderer()->setFog(SampleRenderer::RendererColor(40,40,40), 225.0f); +} + +void SampleVehicle::newMesh(const RAWMesh& data) +{ + if(LOAD_TYPE_LOOPTHELOOP==gLoadType) + { + PxMaterial* saved = mMaterial; + mMaterial = mStandardMaterials[SURFACE_TYPE_TARMAC]; + PhysXSample::newMesh(data); + mMaterial = saved; + } + else if(LOAD_TYPE_VEHICLE==gLoadType) + { + PxU32 carPart=0xffffffff; + if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_CHASSIS])) + { + carPart=CAR_PART_CHASSIS; + + //Find the min and max of the set of verts. + PxVec3 min(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32); + PxVec3 max(-PX_MAX_F32,-PX_MAX_F32,-PX_MAX_F32); + for(PxU32 i=0;i<data.mNbVerts;i++) + { + min.x=PxMin(min.x,data.mVerts[i].x); + min.y=PxMin(min.y,data.mVerts[i].y); + min.z=PxMin(min.z,data.mVerts[i].z); + max.x=PxMax(max.x,data.mVerts[i].x); + max.y=PxMax(max.y,data.mVerts[i].y); + max.z=PxMax(max.z,data.mVerts[i].z); + } + + //Make sure the chassis has an aabb that is centred at (0,0,0). + //This just makes it a lot easier to set the centre of mass offset relative to the centre of the actor. + gChassisMeshTransform=(min+max)*0.5f; + + //Make sure wheel offsets are symmetric (they are not quite symmetric left to right or front to back). + gWheelCentreOffsets4[CAR_PART_FRONT_LEFT_WHEEL].x=-gWheelCentreOffsets4[CAR_PART_FRONT_RIGHT_WHEEL].x; + gWheelCentreOffsets4[CAR_PART_REAR_LEFT_WHEEL].x=-gWheelCentreOffsets4[CAR_PART_REAR_RIGHT_WHEEL].x; + gWheelCentreOffsets4[CAR_PART_FRONT_LEFT_WHEEL].y=gWheelCentreOffsets4[CAR_PART_REAR_LEFT_WHEEL].y; + gWheelCentreOffsets4[CAR_PART_FRONT_RIGHT_WHEEL].y=gWheelCentreOffsets4[CAR_PART_REAR_RIGHT_WHEEL].y; + + //Make an adjustment so that the the centre of the four wheels is at the origin. + //Again, this just makes it a lot easier to set the centre of mass because we have a known point + //that represents the origin. Also, it kind of makes sense that the default centre of mass is at the + //centre point of the wheels. + PxF32 wheelOffsetZ=0; + for(PxU32 i=0;i<=CAR_PART_REAR_RIGHT_WHEEL;i++) + { + wheelOffsetZ+=gWheelCentreOffsets4[i].z; + } + wheelOffsetZ*=0.25f; + gChassisMeshTransform.z+=wheelOffsetZ; + + //Reposition the mesh verts. + PxVec3* verts = const_cast<PxVec3*>(data.mVerts); + for(PxU32 i=0;i<data.mNbVerts;i++) + { + verts[i]-=gChassisMeshTransform; + } + + //Need a convex mesh for the chassis. + gChassisConvexMesh=createChassisConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking()); + } + else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_FRONT_LEFT_WHEEL])) + { + carPart=CAR_PART_FRONT_LEFT_WHEEL; + gWheelConvexMeshes4[CAR_PART_FRONT_LEFT_WHEEL]=createWheelConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking()); + } + else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_FRONT_RIGHT_WHEEL])) + { + carPart=CAR_PART_FRONT_RIGHT_WHEEL; + gWheelConvexMeshes4[CAR_PART_FRONT_RIGHT_WHEEL]=createWheelConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking()); + } + else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_REAR_LEFT_WHEEL])) + { + carPart=CAR_PART_REAR_LEFT_WHEEL; + gWheelConvexMeshes4[CAR_PART_REAR_LEFT_WHEEL]=createWheelConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking()); + } + else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_REAR_RIGHT_WHEEL])) + { + carPart=CAR_PART_REAR_RIGHT_WHEEL; + gWheelConvexMeshes4[CAR_PART_REAR_RIGHT_WHEEL]=createWheelConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking()); + } + else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_WINDOWS])) + { + carPart=CAR_PART_WINDOWS; + //Take the offset that was required to centre the chassis and apply it to everything that is dependent on the chassis transform. + PxVec3* verts = const_cast<PxVec3*>(data.mVerts); + for(PxU32 i=0;i<data.mNbVerts;i++) + { + verts[i]-=gChassisMeshTransform; + } + for(PxU32 i=0;i<=CAR_PART_REAR_RIGHT_WHEEL;i++) + { + gWheelCentreOffsets4[i]-=gChassisMeshTransform; + } + } + + RenderMeshActor* meshActor = createRenderMeshFromRawMesh(data); + PX_ASSERT(carPart!=0xffffffff); + gRenderMeshActors[carPart]=meshActor; + + //Store the wheel offsets from the centre. + for(PxU32 i=0;i<=CAR_PART_REAR_RIGHT_WHEEL;i++) + { + if(0==Ps::strcmp(data.mName,gCarPartNames[i])) + { + gWheelCentreOffsets4[i]=meshActor->getTransform().p; + gWheelCentreOffsets4[i].y-=gSuspensionShimHeight; + + //The left and right wheels seem to be mixed up. + //Swap them to correct this. + gWheelCentreOffsets4[i].x*=-1.0f; + } + } + } + else if(LOAD_TYPE_SKYDOME==gLoadType) + { + createRenderMeshFromRawMesh(data); + } + else + { + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Unknown mesh type", __FILE__, __LINE__); + } +} + +void SampleVehicle::onShutdown() +{ + { + PxSceneWriteLock scopedLock(*mScene); + for(PxU32 i=0;i<mNbIB;i++) + SAMPLE_FREE(mIB[i]); + SAMPLE_FREE(mTerrainVB); + +#if PX_DEBUG_VEHICLE_ON + mTelemetryData4W->free(); + mTelemetryData6W->free(); +#endif + mVehicleManager.shutdown(); + } + + PhysXSample::onShutdown(); + +#if defined(SERIALIZE_VEHICLE_BINARY) + if(mMemory) + SAMPLE_FREE(mMemory); +#endif +} + + +void SampleVehicle::onTickPreRender(PxF32 dtime) +{ + mScene->lockWrite(); + if(mFixCar) + { + //Get the transform of the last crossed waypoint and reset the player car + //at this transform. + resetFocusVehicleAtWaypoint(); + mFixCar=false; + //Reset the control logic driving the car back to start state to avoid mismatch + //between vehicle gears and state stored in vehicle controller. + mVehicleController.clear(); +#if PX_DEBUG_VEHICLE_ON + //Clear all the graph data because the discontinuity in car position makes the stored data redundant. + clearTelemetryData(); +#endif + } + else if(mBackToStart) + { + //Set the progress back to zero. + mWayPoints.setBackAtStart(); + //Get the transform of the last crossed waypoint (this will now be the start + //waypoint) and reset the player car at this transform. + resetFocusVehicleAtWaypoint(); + mBackToStart=false; + //Reset the control logic driving the car back to start state to avoid mismatch + //between vehicle gears and state stored in vehicle controller. + mVehicleController.clear(); +#if PX_DEBUG_VEHICLE_ON + //Clear all the graph data because the discontinuity in car position makes the stored data redundant. + clearTelemetryData(); +#endif + } + + //Only switch to 3-wheeled if driving a 4-wheeled car. + if(ePLAYER_VEHICLE_TYPE_VEHICLE4W==mPlayerVehicleType) + { + if(m3WModeIncremented) + { + const PxU32 old3WMode=m3WMode; + const PxU32 new3WMode=(m3WMode+1)%3; + if(0==old3WMode && 1==new3WMode) + { + mVehicleManager.switchTo3WDeltaMode(mPlayerVehicle); + } + else if(1==old3WMode && 2==new3WMode) + { + mVehicleManager.switchTo3WTadpoleMode(mPlayerVehicle); + } + else if(2==old3WMode && 0==new3WMode) + { + mVehicleManager.switchTo4WMode(mPlayerVehicle); + } + m3WModeIncremented=false; + m3WMode=new3WMode; + } + } + + //Make sure we can still update the camera in pause model. + if(mPause) + { + mCameraController.setInputs( + mControlInputs.getRotateY(), + mControlInputs.getRotateZ()); + updateCameraController(dtime, getActiveScene()); + } + + //Set the global transforms of all actors that have user data. + const size_t nbVehicleGraphicsMeshes = mVehicleGraphics.size(); + for(PxU32 i=0;i<nbVehicleGraphicsMeshes;i++) + { + //Get the mesh actor that represents a vehicle render component. + RenderMeshActor* actor = mVehicleGraphics[i]; + + //Get the data that associates the render component with a physics vehicle component. + const CarRenderUserData* carRenderUserData=(CarRenderUserData*)actor->mUserData; + const PxU8 carId=carRenderUserData->carId; + const PxU8 carPart=carRenderUserData->carPart; + const PxU8 carPartDependency=carRenderUserData->carPartDependency; + + //Get the physics shapes of the vehicle. + //The transform of these shapes will be applied to the render meshes. + PxShape* carShapes[PX_MAX_NB_WHEELS+1]; + const PxVehicleWheels& vehicle=*mVehicleManager.getVehicle(carId); + const PxU32 numShapes=vehicle.getRigidDynamicActor()->getNbShapes(); + const PxRigidDynamic& vehicleActor = *vehicle.getRigidDynamicActor(); + vehicleActor.getShapes(carShapes,numShapes); + + //Set the transform of the render component from the associated physics shape transform. + if(255==carPartDependency) + { + //The transform of this car component has been computed by the vehicle physics + //and stored in the composite bound of the car (chassis + wheels). + actor->setTransform(PxShapeExt::getGlobalPose(*carShapes[carPart], vehicleActor)); + + //update bounds of render actor, for camera cull + actor->setWorldBounds(PxShapeExt::getWorldBounds(*carShapes[carPart], vehicleActor)); + } + else + { + //The transform of this car component hasn't been computed by the vehicle physics. + //The transform is just an offset from another vehicle physics component. + //(This is kind of like a very,very simple skeleton of hierarchical transforms that would normally + //be used to render a vehicle). + actor->setTransform(PxShapeExt::getGlobalPose(*carShapes[carPartDependency], vehicleActor)); + + //update bounds of render actor, for camera cull + actor->setWorldBounds(PxShapeExt::getWorldBounds(*carShapes[carPartDependency], vehicleActor)); + } + } + + getCamera().lookAt(mCameraController.getCameraPos(), mCameraController.getCameraTar()); + + mScene->unlockWrite(); + + // Update the physics + PhysXSample::onTickPreRender(dtime); + +} + +void SampleVehicle::onTickPostRender(PxF32 dtime) +{ + // Fetch results + PhysXSample::onTickPostRender(dtime); + + if(mDebugRenderFlag) + { + drawWheels(); + drawVehicleDebug(); + } + + //Draw the next three way-points. + const RendererColor colors[3]={RendererColor(255,0,0),RendererColor(0,255,0),RendererColor(0,0,255)}; + PxVec3 v[3]; + PxVec3 w[3]; + PxU32 numPoints=0; + mWayPoints.getNextWayPointsAndLineDirs(numPoints,v[0],v[1],v[2],w[0],w[1],w[2]); + for(PxU32 i=0;i<numPoints;i++) + { + getDebugRenderer()->addLine(v[i],v[i]+PxVec3(0,5,0),colors[i]); + getDebugRenderer()->addLine(v[i]-w[i],v[i]+w[i],colors[i]); + } +} + +void SampleVehicle::onSubstep(PxF32 dtime) +{ + //Update the vehicle controls. + switch(mPlayerVehicleType) + { + case ePLAYER_VEHICLE_TYPE_VEHICLE4W: + case ePLAYER_VEHICLE_TYPE_VEHICLE6W: + mVehicleController.setCarKeyboardInputs( + mControlInputs.getAccelKeyPressed(), + mControlInputs.getBrakeKeyPressed(), + mControlInputs.getHandbrakeKeyPressed(), + mControlInputs.getSteerLeftKeyPressed(), + mControlInputs.getSteerRightKeyPressed(), + mControlInputs.getGearUpKeyPressed(), + mControlInputs.getGearDownKeyPressed()); + mVehicleController.setCarGamepadInputs( + mControlInputs.getAccel(), + mControlInputs.getBrake(), + mControlInputs.getSteer(), + mControlInputs.getGearUp(), + mControlInputs.getGearDown(), + mControlInputs.getHandbrake()); + break; + case ePLAYER_VEHICLE_TYPE_TANK4W: + case ePLAYER_VEHICLE_TYPE_TANK6W: + mVehicleController.setTankKeyboardInputs( + mControlInputs.getAccelKeyPressed(), + mControlInputs.getThrustLeftKeyPressed(), + mControlInputs.getThrustRightKeyPressed(), + mControlInputs.getBrakeLeftKeyPressed(), + mControlInputs.getBrakeRightKeyPressed(), + mControlInputs.getGearUpKeyPressed(), + mControlInputs.getGearDownKeyPressed()); + mVehicleController.setTankGamepadInputs( + mControlInputs.getAccel(), + mControlInputs.getThrustLeft(), + mControlInputs.getThrustRight(), + mControlInputs.getBrakeLeft(), + mControlInputs.getBrakeRight(), + mControlInputs.getGearUp(), + mControlInputs.getGearDown()); + break; + default: + PX_ASSERT(false); + break; + } + + updateVehicleController(dtime); + + //Update the vehicles. + mVehicleManager.suspensionRaycasts(&getActiveScene()); + + if (dtime > 0.0f) + { + PxSceneWriteLock scopedLock(*mScene); +#if PX_DEBUG_VEHICLE_ON + updateVehicleManager(dtime,getActiveScene().getGravity()); +#else + mVehicleManager.update(dtime,getActiveScene().getGravity()); +#endif + } + + //Update the camera. + mCameraController.setInputs( + mControlInputs.getRotateY(), + mControlInputs.getRotateZ()); + updateCameraController(dtime,getActiveScene()); + + //Update the revolute joints. + //If the joint has exceeded the rotation limit then reverse the drive velocity + //to make the joint rotate in the opposite direction. + for(PxU32 i=0;i<gNumRevoluteJoints;i++) + { + PxSceneWriteLock scopedLock(*mScene); + //Get the two actors of the joint. + PxRigidActor* actor0=NULL; + PxRigidActor* actor1=NULL; + gRevoluteJoints[i]->getActors(actor0,actor1); + + //Work out the rotation angle of the joint. + const PxF32 cosTheta=PxAbs(actor1->is<PxRigidDynamic>()->getGlobalPose().q.getBasisVector1().y); + const PxF32 theta=PxAcos(cosTheta); + + //If the joint rotation limit has been exceeded then reverse the drive direction. + //It's possible to reverse the direction but then after a timestep or two for it to still be beyond the rotation limit. + //To avoid switching back and forth don't switch drive direction until a minimum time has passed since the last drive direction change. + //Its possible that the pendulum has hit the car and is unable to reach the limit. A nice fix for this is to keep a track of the time + //passed since the last direction change and reverse the joint drive direction if a time limit has been reached. This gives the car + //a chance to escape the pendulum. + if((theta > gRevoluteJointMaxTheta && gRevoluteJointTimers[i]>4*dtime) || gRevoluteJointTimers[i] > 4*gRevoluteJointMaxTheta/gRevoluteJointDriveSpeeds[i]) + { + //Help the joint by setting the actor momenta to zero. + ((PxRigidDynamic*)actor1)->setLinearVelocity(PxVec3(0,0,0)); + ((PxRigidDynamic*)actor1)->setAngularVelocity(PxVec3(0,0,0)); + + //Switch the joint drive direction. + const PxF32 currDriveVel=gRevoluteJoints[i]->getDriveVelocity(); + const PxF32 newDriveVel=-currDriveVel; + gRevoluteJoints[i]->setDriveVelocity(newDriveVel); + + //Reset the timer. + gRevoluteJointTimers[i]=0; + } + + //Increment the joint timer. + gRevoluteJointTimers[i]+=dtime; + } + + { + PxSceneReadLock scopedLock(*mScene); + + //Update the progress around the track with the latest vehicle transform. + PxRigidDynamic* actor=getFocusVehicleRigidDynamicActor(); + mWayPoints.update(actor->getGlobalPose(),dtime); + + //Cache forward speed for the HUD to avoid making API calls while vehicle update is running + const PxVehicleWheels& focusVehicle = *mVehicleManager.getVehicle(mPlayerVehicle); + mForwardSpeedHud = focusVehicle.computeForwardSpeed(); + } +} + +void SampleVehicle::helpRender(PxU32 x, PxU32 y, PxU8 textAlpha) +{ + Renderer* renderer = getRenderer(); + const PxU32 yInc=18; + const PxF32 scale=0.5f; + const PxF32 shadowOffset=6.0f; + const RendererColor textColor(255, 255, 255, textAlpha); + const bool isKeyboardSupported = getApplication().getPlatform()->getSampleUserInput()->keyboardSupported(); + const bool isPadSupported = getApplication().getPlatform()->getSampleUserInput()->gamepadSupported(); + const char* msg; + + + if(ePLAYER_VEHICLE_TYPE_TANK4W==mPlayerVehicleType || ePLAYER_VEHICLE_TYPE_TANK6W==mPlayerVehicleType) + { + renderer->print(x, y += yInc, "TODO: document inputs for ePLAYER_VEHICLE_TYPE_TANK4W, ePLAYER_VEHICLE_TYPE_TANK6W", scale, shadowOffset, textColor); + if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel) + { + } + else + { + } + } + else + { + if (isPadSupported && isKeyboardSupported) + renderer->print(x, y += yInc, "Use right stick or numpad keys to rotate the camera", scale, shadowOffset, textColor); + else if (isPadSupported) + renderer->print(x, y += yInc, "Use right stick to rotate the camera", scale, shadowOffset, textColor); + else if (isKeyboardSupported) + renderer->print(x, y += yInc, "Use numpad keys to rotate the camera", scale, shadowOffset, textColor); + + if (isPadSupported) + renderer->print(x, y += yInc, "Use left stick to steer", scale, shadowOffset, textColor); + + msg = mApplication.inputInfoMsg("Press "," for accelerate", VEH_ACCELERATE_PAD, VEH_ACCELERATE_KBD); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," for brake", CAR_BRAKE_PAD, CAR_BRAKE_KBD); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to steer", CAR_STEER_LEFT_KBD, CAR_STEER_RIGHT_KBD); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + } + + msg = mApplication.inputInfoMsg("Press "," for handbrake", CAR_HANDBRAKE_PAD, CAR_HANDBRAKE_KBD); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + + if(!getFocusVehicleUsesAutoGears()) + { + msg = mApplication.inputInfoMsg("Press "," to gear up", VEH_GEAR_UP_PAD, VEH_GEAR_UP_KBD); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to gear down", VEH_GEAR_DOWN_PAD, VEH_GEAR_DOWN_KBD); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + } + + msg = mApplication.inputInfoMsg("Press "," to toggle car debug render",DEBUG_RENDER_FLAG , -1); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to go back to start",RETRY, -1); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to go back to last waypoint",FIX_CAR, -1); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + +#if PX_DEBUG_VEHICLE_ON + if(mDebugRenderFlag) + { + msg = mApplication.inputInfoMsg("Press "," to increment wheel graphs", DEBUG_RENDER_WHEEL,-1); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to increment central graphs", DEBUG_RENDER_ENGINE,-1); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + } +#endif +} + +void SampleVehicle::descriptionRender(PxU32 x, PxU32 y, PxU8 textAlpha) +{ + bool print=(textAlpha!=0.0f); + + if(print) + { + Renderer* renderer = getRenderer(); + const PxU32 yInc = 24; + const PxReal scale = 0.5f; + const PxReal shadowOffset = 6.0f; + const RendererColor textColor(255, 255, 255, textAlpha); + + char line0[256]="This sample demonstrates vehicle simulation using PhysX. In particular,"; + char line1[256]="vehicle instantiation, the setup of vehicle description data, and"; + char line2[256]="integration with the PhysX SDK are all presented. Key concepts such"; + char line3[256]="as raycast and simulation filtering are illustrated as a means to"; + char line4[256]="tailor vehicle interaction with the scene. The setup and rendering"; + char line5[256]="of vehicle telemetry data is also shown. Finally, physics obstacles"; + char line6[256]="such as swinging pendula exemplify the configuration and run-time "; + char line7[256]="control of driven joints using PhysX."; + + renderer->print(x, y+=yInc, line0, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line1, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line2, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line3, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line4, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line5, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line6, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line7, scale, shadowOffset, textColor); + } +} + +void SampleVehicle::customizeRender() +{ + drawHud(); + if(mDebugRenderFlag) + { + drawFocusVehicleGraphsAndPrintTireSurfaces(); + } + + const PxU32 width=getCamera().getScreenWidth(); + const PxU32 height=getCamera().getScreenHeight(); + + const PxU32 xCentre=280*width/800; + const PxU32 xRight=570*width/800; + const PxU32 yBottom=600*height/600; + + const PxU32 yInc=18; + + Renderer* renderer = getRenderer(); + + char time[64]; + sprintf(time, "Curr Lap Time: %1.1f \n", mWayPoints.getTimeElapsed()); + renderer->print(xRight, yBottom - yInc*2, time); + sprintf(time, "Best Lap Time: %1.1f \n", mWayPoints.getMinTimeElapsed()); + renderer->print(xRight, yBottom - yInc*3, time); + + if(!mCameraController.getIsLockedOnVehicleTransform()) + { + renderer->print(xCentre, yBottom - yInc*4, "Camera decoupled from car"); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +PxFilterFlags SampleVehicleFilterShader( + PxFilterObjectAttributes attributes0, PxFilterData filterData0, + PxFilterObjectAttributes attributes1, PxFilterData filterData1, + PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize) +{ + PX_UNUSED(constantBlock); + PX_UNUSED(constantBlockSize); + + // let triggers through + if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1)) + { + pairFlags = PxPairFlag::eTRIGGER_DEFAULT; + return PxFilterFlags(); + } + + + + // use a group-based mechanism for all other pairs: + // - Objects within the default group (mask 0) always collide + // - By default, objects of the default group do not collide + // with any other group. If they should collide with another + // group then this can only be specified through the filter + // data of the default group objects (objects of a different + // group can not choose to do so) + // - For objects that are not in the default group, a bitmask + // is used to define the groups they should collide with + if ((filterData0.word0 != 0 || filterData1.word0 != 0) && + !(filterData0.word0&filterData1.word1 || filterData1.word0&filterData0.word1)) + return PxFilterFlag::eSUPPRESS; + + pairFlags = PxPairFlag::eCONTACT_DEFAULT; + + // The pairFlags for each object are stored in word2 of the filter data. Combine them. + pairFlags |= PxPairFlags(PxU16(filterData0.word2 | filterData1.word2)); + return PxFilterFlags(); +} + + +void SampleVehicle::customizeSceneDesc(PxSceneDesc& sceneDesc) +{ + sceneDesc.filterShader = SampleVehicleFilterShader; + sceneDesc.flags |= PxSceneFlag::eREQUIRE_RW_LOCK; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleVehicle::createStandardMaterials() +{ + const PxF32 restitutions[MAX_NUM_SURFACE_TYPES] = {0.2f, 0.2f, 0.2f, 0.2f}; + const PxF32 staticFrictions[MAX_NUM_SURFACE_TYPES] = {0.5f, 0.5f, 0.5f, 0.5f}; + const PxF32 dynamicFrictions[MAX_NUM_SURFACE_TYPES] = {0.5f, 0.5f, 0.5f, 0.5f}; + + for(PxU32 i=0;i<MAX_NUM_SURFACE_TYPES;i++) + { + //Create a new material. + mStandardMaterials[i] = getPhysics().createMaterial(staticFrictions[i], dynamicFrictions[i], restitutions[i]); + if(!mStandardMaterials[i]) + { + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "createMaterial failed", __FILE__, __LINE__); + } + + //Set up the drivable surface type that will be used for the new material. + mVehicleDrivableSurfaceTypes[i].mType = i; + } + + mChassisMaterialDrivable = getPhysics().createMaterial(0.0f, 0.0f, 0.0f); + if(!mChassisMaterialDrivable) + { + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "createMaterial failed", __FILE__, __LINE__); + } + + mChassisMaterialNonDrivable = getPhysics().createMaterial(1.0f, 1.0f, 0.0f); + if(!mChassisMaterialNonDrivable) + { + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "createMaterial failed", __FILE__, __LINE__); + } +} + +/////////////////////////////////////////////////////////////////////////////// +static const char* getPlatformName() +{ +#if PX_X86 + return "PC32"; +#elif PX_X64 + return "PC64"; +#elif PX_ARM_FAMILY + return "ARM"; +#else + return ""; +#endif +} + +const char* SampleVehicle::getFocusVehicleName() +{ + switch(mPlayerVehicleType) + { + case ePLAYER_VEHICLE_TYPE_VEHICLE4W: + return "VEHICLE4W"; + case ePLAYER_VEHICLE_TYPE_TANK4W: + return "TANK4W"; + case ePLAYER_VEHICLE_TYPE_VEHICLE6W: + return "VEHICLE6W"; + case ePLAYER_VEHICLE_TYPE_TANK6W: + return "TANK6W"; + default: + return NULL; + } +} + +static PxU32 GetFileSize(const char* name) +{ + if(!name) return 0; + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + + SampleFramework::File* fp; + if (PxToolkit::fopen_s(&fp, name, "rb")) + return 0; + fseek(fp, 0, SEEK_END); + PxU32 eof_ftell = (PxU32)ftell(fp); + fclose(fp); + return eof_ftell; +} + +void SampleVehicle::createVehicles() +{ + bool hasFocusVehicle = false; + //Make sure that we set the foundation before doing anything. + mVehicleManager.init(getPhysics(),(const PxMaterial**)mStandardMaterials,mVehicleDrivableSurfaceTypes); + + //Not added any vehicles yet. + gNumVehicleAdded=0; + + //Load the vehicle model (this will add the render actors for the chassis, 4 wheels, and windows). + gLoadType = LOAD_TYPE_VEHICLE; + importRAWFile("car2.raw", 1.0f); + + //The extra wheels of an 8-wheeled vehicle are instanced from the 4 wheels of the 4-wheeled car. + gRenderMeshActors[CAR_PART_EXTRA_WHEEL0]=gRenderMeshActors[CAR_PART_FRONT_LEFT_WHEEL]; + gRenderMeshActors[CAR_PART_EXTRA_WHEEL1]=gRenderMeshActors[CAR_PART_FRONT_RIGHT_WHEEL]; + + //Clear the array of render actors before adding the actors for each vehicle. + for(PxU32 i=0;i<mRenderActors.size();i++) + { + RenderBaseActor* renderActor=mRenderActors[i]; + renderActor->setRendering(false); + } + + //Load the player car. + switch(mPlayerVehicleType) + { + case ePLAYER_VEHICLE_TYPE_VEHICLE4W: + case ePLAYER_VEHICLE_TYPE_TANK4W: + { + for(PxU32 i=0;i<NUM_CAR4W_RENDER_COMPONENTS;i++) + { + gVehicleRenderUserData[gNumVehicleAdded][i]=gCar4WRenderUserData[i]; + gVehicleRenderUserData[gNumVehicleAdded][i].carId=PxU8(gNumVehicleAdded); + + RenderMeshActor* clone=SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[i]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][i]; + clone->setEnableCameraCull(true); + + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + } + + mPlayerVehicle=0; + if(!hasFocusVehicle) + { + if(ePLAYER_VEHICLE_TYPE_VEHICLE4W==mPlayerVehicleType) + { + mVehicleManager.create4WVehicle(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gPlayerCarStartTransforms[0],true); + } + else + { + mVehicleManager.create4WTank(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gPlayerCarStartTransforms[0],true,mTankDriveModel); + } + } + + gNumVehicleAdded++; + } + break; + + case ePLAYER_VEHICLE_TYPE_VEHICLE6W: + case ePLAYER_VEHICLE_TYPE_TANK6W: + { + for(PxU32 i=0;i<NUM_CAR4W_RENDER_COMPONENTS;i++) + { + gVehicleRenderUserData[gNumVehicleAdded][i]=gCar6WRenderUserData[i]; + gVehicleRenderUserData[gNumVehicleAdded][i].carId=PxU8(gNumVehicleAdded); + + RenderMeshActor* clone=SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[i]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][i]; + clone->setEnableCameraCull(true); + + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + } + + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]=gCar6WRenderUserData[CAR_PART_EXTRA_WHEEL0]; + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]=gCar6WRenderUserData[CAR_PART_EXTRA_WHEEL1]; + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0].carId = PxU8(gNumVehicleAdded); + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1].carId = PxU8(gNumVehicleAdded); + + //Add the extra wheels. + RenderMeshActor* clone; + clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL0]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]; + clone->setEnableCameraCull(true); + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL1]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]; + clone->setEnableCameraCull(true); + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + + mPlayerVehicle=0; + + if(!hasFocusVehicle) + { + if(ePLAYER_VEHICLE_TYPE_VEHICLE6W==mPlayerVehicleType) + { + mVehicleManager.create6WVehicle(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gPlayerCarStartTransforms[0],true); + } + else + { + mVehicleManager.create6WTank(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gPlayerCarStartTransforms[0],true,mTankDriveModel); + } + } + gNumVehicleAdded++; + } + break; + + default: + PX_ASSERT(false); + break; + } + +#if NUM_NONPLAYER_4W_VEHICLES + for(PxU32 i=0;i<NUM_NONPLAYER_4W_VEHICLES;i++) + { + //Clone the meshes from the instanced meshes. + for(PxU32 j=0;j<NUM_CAR4W_RENDER_COMPONENTS;j++) + { + gVehicleRenderUserData[gNumVehicleAdded][j]=gCar4WRenderUserData[j]; + gVehicleRenderUserData[gNumVehicleAdded][j].carId=PxU8(gNumVehicleAdded); + + RenderMeshActor* clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[j]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][j]; + clone->setEnableCameraCull(true); + + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + } + + //Add the next vehicle. + mVehicleManager.create4WVehicle(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialNonDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gVehicle4WStartTransforms[i],true); + + gNumVehicleAdded++; + } +#endif + +#if NUM_NONPLAYER_6W_VEHICLES + for(PxU32 i=0;i<NUM_NONPLAYER_6W_VEHICLES;i++) + { + //Clone the meshes from the instanced meshes. + for(PxU32 j=0;j<NUM_CAR4W_RENDER_COMPONENTS;j++) + { + gVehicleRenderUserData[gNumVehicleAdded][j]=gCar6WRenderUserData[j]; + gVehicleRenderUserData[gNumVehicleAdded][j].carId=PxU8(gNumVehicleAdded); + + RenderMeshActor* clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[j]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][j]; + clone->setEnableCameraCull(true); + + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + } + + //Add the extra wheels. + + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]=gCar6WRenderUserData[CAR_PART_EXTRA_WHEEL0]; + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]=gCar6WRenderUserData[CAR_PART_EXTRA_WHEEL1]; + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0].carId = PxU8(gNumVehicleAdded); + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1].carId = PxU8(gNumVehicleAdded); + + RenderMeshActor* clone; + clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL0]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]; + clone->setEnableCameraCull(true); + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL1]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]; + clone->setEnableCameraCull(true); + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + + //Add the next vehicle. + mVehicleManager.create6WVehicle(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialNonDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gVehicle6WStartTransforms[i],true); + + gNumVehicleAdded++; + } +#endif + +#if NUM_NONPLAYER_4W_TANKS + for(PxU32 i=0;i<NUM_NONPLAYER_4W_TANKS;i++) + { + //Clone the meshes from the instanced meshes. + for(PxU32 j=0;j<NUM_CAR4W_RENDER_COMPONENTS;j++) + { + gVehicleRenderUserData[gNumVehicleAdded][j]=gCar4WRenderUserData[j]; + gVehicleRenderUserData[gNumVehicleAdded][j].carId=PxU8(gNumVehicleAdded); + + RenderMeshActor* clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[j]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][j]; + clone->setEnableCameraCull(true); + + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + } + + mPlayerVehicle=0; + //Add the next vehicle. + mVehicleManager.create4WTank(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterial,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gTank4WStartTransforms[i],true, PxVehicleDriveTank::eDRIVE_MODEL_SPECIAL); + + gNumVehicleAdded++; + } +#endif + +#if NUM_NONPLAYER_6W_TANKS + for(PxU32 i=0;i<NUM_NONPLAYER_6W_TANKS;i++) + { + //Clone the meshes from the instanced meshes. + for(PxU32 j=0;j<NUM_CAR4W_RENDER_COMPONENTS;j++) + { + gVehicleRenderUserData[gNumVehicleAdded][j]=gTank6WRenderUserData[j]; + gVehicleRenderUserData[gNumVehicleAdded][j].carId=PxU8(gNumVehicleAdded); + + RenderMeshActor* clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[j]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][j]; + clone->setEnableCameraCull(true); + + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + } + + //Add the extra wheels. + + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]=gTank6WRenderUserData[CAR_PART_EXTRA_WHEEL0]; + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]=gTank6WRenderUserData[CAR_PART_EXTRA_WHEEL1]; + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0].carId = PxU8(gNumVehicleAdded); + gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1].carId = PxU8(gNumVehicleAdded); + + RenderMeshActor* clone; + + clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL0]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]; + clone->setEnableCameraCull(true); + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + + clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL1]); + clone->setRendering(true); + clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]; + clone->setEnableCameraCull(true); + mVehicleGraphics.push_back(clone); + mRenderActors.push_back(clone); + + //Add the next vehicle. + mVehicleManager.create6WTank(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterial,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gTank6WStartTransforms[i],true); + + gNumVehicleAdded++; + } +#endif +} + +PxRigidStatic* SampleVehicle::addStaticObstacle +(const PxTransform& transform, const PxU32 numShapes, PxTransform* shapeTransforms, PxGeometry** shapeGeometries, PxMaterial** shapeMaterials) +{ + PxFilterData simFilterData; + simFilterData.word0=COLLISION_FLAG_GROUND; + simFilterData.word1=COLLISION_FLAG_GROUND_AGAINST; + PxFilterData qryFilterData; + SampleVehicleSetupDrivableShapeQueryFilterData(&qryFilterData); + + PxRigidStatic* actor=getPhysics().createRigidStatic(transform); + for(PxU32 i=0;i<numShapes;i++) + { + PxShape* shape=PxRigidActorExt::createExclusiveShape(*actor, *shapeGeometries[i], *shapeMaterials[i]); + shape->setLocalPose(shapeTransforms[i]); + shape->setSimulationFilterData(simFilterData); + shape->setQueryFilterData(qryFilterData); + } + getActiveScene().addActor(*actor); + createRenderObjectsFromActor(actor); + return actor; +} + +PxRigidDynamic* SampleVehicle::addDynamicObstacle +(const PxTransform& transform, const PxF32 mass, const PxU32 numShapes, PxTransform* shapeTransforms, PxGeometry** shapeGeometries, PxMaterial** shapeMaterials) +{ + PxFilterData simFilterData; + simFilterData.word0=COLLISION_FLAG_OBSTACLE; + simFilterData.word1=COLLISION_FLAG_OBSTACLE_AGAINST; + PxFilterData qryFilterData; + SampleVehicleSetupNonDrivableShapeQueryFilterData(&qryFilterData); + + PxRigidDynamic* actor = getPhysics().createRigidDynamic(transform); + for(PxU32 i=0;i<numShapes;i++) + { + PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, *shapeGeometries[i], *shapeMaterials[i]); + shape->setLocalPose(shapeTransforms[i]); + shape->setSimulationFilterData(simFilterData); + shape->setQueryFilterData(qryFilterData); + } + + PxRigidBodyExt::setMassAndUpdateInertia(*actor,mass); + getActiveScene().addActor(*actor); + createRenderObjectsFromActor(actor); + return actor; +} + +PxRigidDynamic* SampleVehicle::addDynamicDrivableObstacle +(const PxTransform& transform, const PxF32 mass, const PxU32 numShapes, PxTransform* shapeTransforms, PxGeometry** shapeGeometries, PxMaterial** shapeMaterials) +{ + PxFilterData simFilterData; + simFilterData.word0=COLLISION_FLAG_DRIVABLE_OBSTACLE; + simFilterData.word1=COLLISION_FLAG_DRIVABLE_OBSTACLE_AGAINST; + PxFilterData qryFilterData; + SampleVehicleSetupDrivableShapeQueryFilterData(&qryFilterData); + + PxRigidDynamic* actor = getPhysics().createRigidDynamic(transform); + for(PxU32 i=0;i<numShapes;i++) + { + PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, *shapeGeometries[i], *shapeMaterials[i]); + shape->setLocalPose(shapeTransforms[i]); + shape->setSimulationFilterData(simFilterData); + shape->setQueryFilterData(qryFilterData); + } + + PxRigidBodyExt::setMassAndUpdateInertia(*actor,mass); + getActiveScene().addActor(*actor); + createRenderObjectsFromActor(actor); + return actor; +} + +void SampleVehicle::createStack(PxU32 numBaseBoxes, PxF32 boxSize, const PxVec3& pos, const PxQuat& quat) +{ + const PxF32 density=50.0f; + + const PxF32 sizeX = boxSize; + const PxF32 sizeY = boxSize; + const PxF32 sizeZ = boxSize; + + const PxF32 mass = boxSize*boxSize*boxSize*density; + const PxVec3 halfExtents(sizeX*0.5f,sizeY*0.5f,sizeZ*0.5f); + PxBoxGeometry geometry(halfExtents); + PxTransform shapeTransforms[1]={PxTransform(PxIdentity)}; + PxGeometry* shapeGeometries[1]={&geometry}; + PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]}; + + const PxF32 spacing = 0.0001f; + PxVec3 relPos(0.0f, sizeY/2, 0.0f); + PxF32 offsetX = -(numBaseBoxes * (sizeX + spacing) * 0.5f); + PxF32 offsetZ = 0.0f; + while(numBaseBoxes) + { + for(PxU32 i=0;i<numBaseBoxes ;i++) + { + relPos.x = offsetX + (PxF32)i * (sizeX + spacing); + relPos.z = offsetZ; + + PxTransform transform(pos + quat.rotate(relPos),quat); + addDynamicObstacle(transform,mass,1,shapeTransforms,shapeGeometries,shapeMaterials); + } + + offsetX += sizeX/2; + relPos.y += (sizeY + spacing); + numBaseBoxes--; + } +} + +void SampleVehicle::createWall(const PxU32 numHorizontalBoxes, const PxU32 numVerticalBoxes, const PxF32 boxSize, const PxVec3& pos, const PxQuat& quat) +{ + const PxF32 density=50.0f; + + const PxF32 sizeX = boxSize; + const PxF32 sizeY = boxSize; + const PxF32 sizeZ = boxSize; + + const PxF32 mass = sizeX*sizeY*sizeZ*density; + const PxVec3 halfExtents(sizeX*0.5f,sizeY*0.5f,sizeZ*0.5f); + PxBoxGeometry geometry(halfExtents); + PxTransform shapeTransforms[1] = {PxTransform(PxIdentity)}; + PxGeometry* shapeGeometries[1] = {&geometry}; + PxMaterial* shapeMaterials[1] = {mStandardMaterials[SURFACE_TYPE_TARMAC]}; + + const PxF32 spacing = 0.0001f; + PxVec3 relPos(0.0f, sizeY/2, 0.0f); + PxF32 offsetX = -(numHorizontalBoxes * (sizeX + spacing) * 0.5f); + PxF32 offsetZ = 0.0f; + + for(PxU32 k=0;k<numVerticalBoxes;k++) + { + for(PxU32 i=0;i<numHorizontalBoxes;i++) + { + relPos.x = offsetX + (sizeX + spacing)*i; + relPos.z = offsetZ; + PxTransform transform(pos + quat.rotate(relPos),quat); + addDynamicObstacle(transform,mass,1,shapeTransforms,shapeGeometries,shapeMaterials); + } + + if(0==(k%2)) + { + offsetX += sizeX/2; + } + else + { + offsetX -= sizeX/2; + } + relPos.y += (sizeY + spacing); + } +} + +void SampleVehicle::createObstacles() +{ + PxSceneWriteLock scopedLock(*mScene); + //Create some giant pendula + { + PxTransform shapeTransforms[3]={PxTransform(PxIdentity),PxTransform(PxIdentity),PxTransform(PxIdentity)}; + PxMaterial* shapeMaterials[3]={NULL,NULL,NULL}; + PxGeometry* shapeGeometries[3]={NULL,NULL,NULL}; + PxShape* shapes[3]={NULL,NULL,NULL}; + + gNumRevoluteJoints=0; + + for(PxU32 i=0;i<MAX_NUM_PENDULA;i++) + { + //Get the transform to position the next pendulum ball. + const PxTransform& ballStartTransform=gPendulaBallStartTransforms[i]; + + //Pendulum made of two shapes : a sphere for the ball and a cylinder for the shaft. + //In the absence of a special material for pendula just use the tarmac material. + PxSphereGeometry geomBall(gPendulumBallRadius); + shapeGeometries[0]=&geomBall; + shapeTransforms[0]=PxTransform(PxIdentity); + shapeMaterials[0]=mStandardMaterials[SURFACE_TYPE_TARMAC]; + PxConvexMeshGeometry geomShaft(createCylinderConvexMesh(gPendulumShaftLength, gPendulumShaftWidth, 8, getPhysics(), getCooking())); + shapeGeometries[1]=&geomShaft; + shapeTransforms[1]=PxTransform(PxVec3(0, 0.5f*gPendulumShaftLength, 0), PxQuat(PxHalfPi, PxVec3(0,0,1))), + shapeMaterials[1]=mStandardMaterials[SURFACE_TYPE_TARMAC]; + + //Ready to add the pendulum as a dynamic object. + PxRigidDynamic* actor=addDynamicObstacle(ballStartTransform,gPendulumBallMass,2,shapeTransforms,shapeGeometries,shapeMaterials); + + //As an optimization we don't want pendulum to intersect with static geometry because the position and + //limits on joint rotation will ensure that this is already impossible. + actor->getShapes(shapes,2); + PxFilterData simFilterData=shapes[0]->getSimulationFilterData(); + simFilterData.word1 &= ~COLLISION_FLAG_GROUND; + shapes[0]->setSimulationFilterData(simFilterData); + shapes[1]->setSimulationFilterData(simFilterData); + //As a further optimization lets set the pendulum shapes to be non-drivable surfaces. + PxFilterData qryFilterData; + SampleVehicleSetupNonDrivableShapeQueryFilterData(&qryFilterData); + shapes[0]->setQueryFilterData(qryFilterData); + shapes[1]->setQueryFilterData(qryFilterData); + + //Add static geometry to give the appearance that something is physically supporting the pendulum. + //This supporting geometry is just a vertical bar and two horizontal bars. + const PxF32 groundClearance=3.0f; + PxConvexMeshGeometry geomHorizontalBar(createCylinderConvexMesh(gPendulumSuspensionStructureWidth, gPendulumShaftWidth, 8, getPhysics(), getCooking())); + PxConvexMeshGeometry geomVerticalBar(createCylinderConvexMesh(gPendulumShaftLength+groundClearance, gPendulumShaftWidth, 8, getPhysics(), getCooking())); + shapeGeometries[0]=&geomHorizontalBar; + shapeMaterials[0]=mStandardMaterials[SURFACE_TYPE_TARMAC]; + shapeTransforms[0]=PxTransform(PxVec3(0, gPendulumShaftLength, 0), PxQuat(PxIdentity)); + shapeGeometries[1]=&geomVerticalBar; + shapeMaterials[1]=mStandardMaterials[SURFACE_TYPE_TARMAC]; + shapeTransforms[1]=PxTransform(PxVec3(0.5f*gPendulumSuspensionStructureWidth, 0.5f*(gPendulumShaftLength-groundClearance), 0), PxQuat(PxHalfPi, PxVec3(0,0,1))); + shapeGeometries[2]=&geomVerticalBar; + shapeMaterials[2]=mStandardMaterials[SURFACE_TYPE_TARMAC]; + shapeTransforms[2]=PxTransform(PxVec3(-0.5f*gPendulumSuspensionStructureWidth, 0.5f*(gPendulumShaftLength-groundClearance), 0), PxQuat(PxHalfPi, PxVec3(0,0,1))); + + //Ready to add the support geometry as a static object. + PxRigidStatic* staticActor=addStaticObstacle(ballStartTransform,3,shapeTransforms,shapeGeometries,shapeMaterials); + + //As an optimization lets disable collision with the dynamic pendulum because the joint limits will make + //collision impossible. + staticActor->getShapes(shapes,3); + simFilterData=shapes[0]->getSimulationFilterData(); + simFilterData.word1 &= ~COLLISION_FLAG_OBSTACLE; + shapes[0]->setSimulationFilterData(simFilterData); + shapes[1]->setSimulationFilterData(simFilterData); + shapes[2]->setSimulationFilterData(simFilterData); + + //Now finally add the joint that will create the pendulum behaviour : rotation around a single axis. + const PxVec3 pendulumPos=ballStartTransform.p + PxVec3(0, gPendulumShaftLength, 0); + PxQuat pendulumRotation=PxQuat(PxHalfPi,PxVec3(0,1,0)); + PxRevoluteJoint* joint=PxRevoluteJointCreate + (getPhysics(), + NULL, PxTransform(pendulumPos, ballStartTransform.q*pendulumRotation), + actor, PxTransform(PxVec3(0,gPendulumShaftLength,0), pendulumRotation)); + joint->setDriveVelocity(gRevoluteJointDriveSpeeds[i]); + joint->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_ENABLED, true); + gRevoluteJoints[gNumRevoluteJoints]=joint; + gNumRevoluteJoints++; + } + + //Work out the maximum angle of rotation allowed before the pendulum hits the support geometry. + //We're going to monitor the pendulum's progress at each update and reverse the pendulum drive speed + //if the limit is exceed. + const PxF32 sinTheta=(gPendulumSuspensionStructureWidth*0.5f - gPendulumBallRadius)/gPendulumShaftLength; + gRevoluteJointMaxTheta=PxAsin(sinTheta); + } + + //Create a see-saw + { + //See-saw made of two separate objects : a static prism-shaped base and a ramp that balances on top of the prism. + //In the absence of a special material for see-saws just reuse the tarmac material. + PxTransform shapeTransforms[1]={PxTransform(PxIdentity)}; + PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]}; + PxGeometry* shapeGeometries[1]={NULL}; + + //Add the static prism-shaped object. + PxTransform tBase(PxVec3( -132.940292 , 8.664189 , -116.392891 ), PxQuat( -0.000319 , 0.348920 , -0.000129 , -0.937153 ) ); + PxConvexMesh* meshBase=createPrismConvexMesh(12,3.0f,4.5f,getPhysics(), getCooking()); + PxConvexMeshGeometry geomBase(meshBase); + shapeGeometries[0]=&geomBase; + addStaticObstacle(tBase,1,shapeTransforms,shapeGeometries,shapeMaterials); + + //Add the dynamic ramp that balances on the prism. + PxTransform tRamp(PxVec3( -130.357010 , 12.584847 , -119.381256 ), PxQuat( 0.088919 , 0.347436 , 0.033112 , -0.932891 ) ) ; + PxConvexMesh* meshRamp=createSquashedCuboidMesh(6.0f, 40.0f, 0.25f, 0.065f, getPhysics(), getCooking()); + PxConvexMeshGeometry geomRamp(meshRamp); + shapeGeometries[0]=&geomRamp; + addDynamicDrivableObstacle(tRamp,1000.0f,1,shapeTransforms,shapeGeometries,shapeMaterials); + } + + //Add a really big ramp to jump over the car stack. + { + PxVec3 halfExtentsRamp(5.0f,1.9f,7.0f); + PxConvexMeshGeometry geomRamp(createWedgeConvexMesh(halfExtentsRamp,getPhysics(),getCooking())); + PxTransform shapeTransforms[1]={PxTransform(PxIdentity)}; + PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]}; + PxGeometry* shapeGeometries[1]={&geomRamp}; + PxTransform tRamp(PxVec3( -89.849564 , 9.950000 , 154.516617 ), PxQuat( -0.000002 , -0.837118 , -0.000004 , 0.547022 ) ); + addStaticObstacle(tRamp,1,shapeTransforms,shapeGeometries,shapeMaterials); + } + + //Add two ramps side by side with a gap in between + { + PxVec3 halfExtents(3.0f,1.5f,3.5f); + PxConvexMeshGeometry geometry(createWedgeConvexMesh(halfExtents,getPhysics(),getCooking())); + PxTransform shapeTransforms[1]={PxTransform(PxIdentity)}; + PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]}; + PxGeometry* shapeGeometries[1]={&geometry}; + PxTransform t1(PxVec3( 112.797081 , 10.086022 , 134.419052 ), PxQuat( 0.000013 , -0.406322 , 0.000006 , 0.913730 ) ); + addStaticObstacle(t1,1,shapeTransforms,shapeGeometries,shapeMaterials); + PxTransform t2(PxVec3( 120.135361 , 10.086023 , 140.594055 ), PxQuat( 0.000013 , -0.406322 , 0.000006 , 0.913730 ) ); + addStaticObstacle(t2,1,shapeTransforms,shapeGeometries,shapeMaterials); + } + + //Add a wall made of dynamic objects with cuboid shapes for bricks. + { + PxTransform t(PxVec3( -37.525650 , 9.864201 , -77.926567 ), PxQuat( -0.000286 , 0.728016 , -0.000290 , -0.685561 ) ) ; + createWall(12,4,1.0f,t.p,t.q); + } + + //Create a kind of cattle grid of cylindrical rods. + { + //Cattle grid made out of 128 identical cylindrical rods. + //Need to instantiate geometry used for the rods. + const PxF32 logRadius=0.125f; + PxConvexMesh* mesh=createCylinderConvexMesh(10.0f,logRadius,8,getPhysics(),getCooking()); + PxConvexMeshGeometry geom(mesh); + + //Set up transform, geometry, and material of each cylindrical rod shape. + PxGeometry* shapeGeometries[128]; + PxMaterial* shapeMaterials[128]; + PxTransform shapeTransforms[128]; + PxTransform shapeTransform=PxTransform(PxVec3(0,0,0),PxQuat(PxIdentity)); + for(PxU32 i=0;i<128;i++) + { + shapeTransforms[i]=shapeTransform; + shapeGeometries[i]=&geom; + shapeMaterials[i]=mStandardMaterials[SURFACE_TYPE_TARMAC]; + + //Work out the position of the next cylindrical rod. + shapeTransform.p.z += (2.40f*logRadius); + shapeTransform.p.y += 0.0025f; + } + + //Ready to add the cattle grid as a static object with a composite bound of 128 cylindrical rods. + PxTransform t(PxVec3( -160.972595 , 8.739249 , -74.141998 ), PxQuat( 0.000407 , -0.165312 , 0.000060 , 0.986241 ) ) ; + addStaticObstacle(t,128,shapeTransforms,shapeGeometries,shapeMaterials); + } + + //Add three static walls + { + PxBoxGeometry box(8,2,1); + PxTransform shapeTransforms[1]={PxTransform(PxIdentity)}; + PxGeometry* shapeGeometries[1]={&box}; + PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]}; + + PxTransform t1(PxVec3( -175.981186 , 9.864196 , -25.040220 ), PxQuat( -0.000417 , 0.042262 , -0.000009 , -0.999106 ) ); + addStaticObstacle(t1,1,shapeTransforms,shapeGeometries,shapeMaterials); + PxTransform t2(PxVec3( -174.972122 , 9.864214 , 32.517246 ), PxQuat( -0.000384 , -0.080625 , 0.000019 , -0.996744 ) ) ; + addStaticObstacle(t2,1,shapeTransforms,shapeGeometries,shapeMaterials); + PxTransform t3(PxVec3( 157.825897 , 9.864218 , -83.961632 ), PxQuat( -0.000124 , 0.997806 , -0.000358 , -0.066201 ) ); + addStaticObstacle(t3,1,shapeTransforms,shapeGeometries,shapeMaterials); + } +} + +void SampleVehicle::collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents) +{ + PhysXSample::collectInputEvents(inputEvents); + + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_GAMEPAD_MOVE_LEFT_RIGHT); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_GAMEPAD_MOVE_FORWARD_BACK); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(SPAWN_DEBUG_OBJECT); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(MENU_VISUALIZATIONS); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(HIDE_GRAPHICS); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(VARIABLE_TIMESTEP); + + DIGITAL_INPUT_EVENT_DEF(VEH_SAVE_KBD, WKEY_I, XKEY_I, X1KEY_I, PS3KEY_I, PS4KEY_I, AKEY_UNKNOWN, SCAN_CODE_FORWARD, IKEY_UNKNOWN, SCAN_CODE_FORWARD, WIIUKEY_UNKNOWN); + + + //Driving keyboard controls. + if(ePLAYER_VEHICLE_TYPE_TANK4W==mPlayerVehicleType || ePLAYER_VEHICLE_TYPE_TANK6W==mPlayerVehicleType) + { + DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_KBD, SCAN_CODE_9, XKEY_9, X1KEY_9, PS3KEY_9, PS4KEY_9, AKEY_UNKNOWN, SCAN_CODE_9, IKEY_UNKNOWN, SCAN_CODE_9, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_KBD, SCAN_CODE_0, XKEY_0, X1KEY_0, PS3KEY_0, PS4KEY_0, AKEY_UNKNOWN, SCAN_CODE_0, IKEY_UNKNOWN, SCAN_CODE_0, WIIUKEY_UNKNOWN); + + DIGITAL_INPUT_EVENT_DEF(TANK_THRUST_LEFT_KBD, WKEY_Q, XKEY_S, X1KEY_S, PS3KEY_S, PS4KEY_S, AKEY_UNKNOWN, SCAN_CODE_BACKWARD, IKEY_UNKNOWN, SCAN_CODE_BACKWARD, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_KBD, WKEY_I, XKEY_A, X1KEY_A, PS3KEY_A, PS4KEY_A, AKEY_UNKNOWN, SCAN_CODE_LEFT, IKEY_UNKNOWN, SCAN_CODE_LEFT, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(TANK_BRAKE_LEFT_KBD, WKEY_A, XKEY_D, X1KEY_D, PS3KEY_D, PS4KEY_D, AKEY_UNKNOWN, SCAN_CODE_RIGHT, IKEY_UNKNOWN, SCAN_CODE_RIGHT, GAMEPAD_LEFT_SHOULDER_BOT); + DIGITAL_INPUT_EVENT_DEF(TANK_BRAKE_RIGHT_KBD, WKEY_J, XKEY_L, X1KEY_L, PS3KEY_L, PS4KEY_L, AKEY_UNKNOWN, SCAN_CODE_L, IKEY_UNKNOWN, SCAN_CODE_L, GAMEPAD_RIGHT_SHOULDER_BOT); + } + else + { + DIGITAL_INPUT_EVENT_DEF(VEH_ACCELERATE_KBD, SCAN_CODE_FORWARD, XKEY_W, X1KEY_W, PS3KEY_W, PS4KEY_W, AKEY_UNKNOWN, SCAN_CODE_FORWARD, IKEY_UNKNOWN, SCAN_CODE_FORWARD, GAMEPAD_RIGHT_SHOULDER_BOT); + DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_KBD, SCAN_CODE_9, XKEY_9, X1KEY_9, PS3KEY_9, PS4KEY_9, AKEY_UNKNOWN, SCAN_CODE_9, IKEY_UNKNOWN, SCAN_CODE_9, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_KBD, SCAN_CODE_0, XKEY_0, X1KEY_0, PS3KEY_0, PS4KEY_0, AKEY_UNKNOWN, SCAN_CODE_0, IKEY_UNKNOWN, SCAN_CODE_0, WIIUKEY_UNKNOWN); + + DIGITAL_INPUT_EVENT_DEF(CAR_BRAKE_KBD, SCAN_CODE_BACKWARD, XKEY_S, X1KEY_S, PS3KEY_S, PS4KEY_S, AKEY_UNKNOWN, SCAN_CODE_BACKWARD, IKEY_UNKNOWN, SCAN_CODE_BACKWARD, GAMEPAD_LEFT_SHOULDER_BOT); + DIGITAL_INPUT_EVENT_DEF(CAR_HANDBRAKE_KBD, SCAN_CODE_L, XKEY_L, X1KEY_L, PS3KEY_L, PS4KEY_L, AKEY_UNKNOWN, SCAN_CODE_L, IKEY_UNKNOWN, SCAN_CODE_L, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CAR_STEER_LEFT_KBD, SCAN_CODE_LEFT, XKEY_A, X1KEY_A, PS3KEY_A, PS4KEY_A, AKEY_UNKNOWN, SCAN_CODE_LEFT, IKEY_UNKNOWN, SCAN_CODE_LEFT, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CAR_STEER_RIGHT_KBD, SCAN_CODE_RIGHT, XKEY_D, X1KEY_D, PS3KEY_D, PS4KEY_D, AKEY_UNKNOWN, SCAN_CODE_RIGHT, IKEY_UNKNOWN, SCAN_CODE_RIGHT, WIIUKEY_UNKNOWN); + } + + //Driving gamepad controls + if(ePLAYER_VEHICLE_TYPE_TANK4W==mPlayerVehicleType || ePLAYER_VEHICLE_TYPE_TANK6W==mPlayerVehicleType) + { + DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_PAD, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_EAST); + DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_PAD, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_NORTH); + + if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel) + { + ANALOG_INPUT_EVENT_DEF(TANK_THRUST_LEFT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y); + ANALOG_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y); + ANALOG_INPUT_EVENT_DEF(TANK_BRAKE_LEFT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN); + ANALOG_INPUT_EVENT_DEF(TANK_BRAKE_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN); + } + else + { + ANALOG_INPUT_EVENT_DEF(VEH_ACCELERATE_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN); + ANALOG_INPUT_EVENT_DEF(TANK_THRUST_LEFT_PAD , GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y); + ANALOG_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y); + } + + ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_RIGHT_PAD,GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X); + } + else + { + DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_PAD, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_EAST); + DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_PAD, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_NORTH); + DIGITAL_INPUT_EVENT_DEF(CAR_HANDBRAKE_PAD, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_SOUTH); + + ANALOG_INPUT_EVENT_DEF(VEH_ACCELERATE_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN); + ANALOG_INPUT_EVENT_DEF(CAR_BRAKE_PAD , GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN); + ANALOG_INPUT_EVENT_DEF(CAR_STEER_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_X); + + ANALOG_INPUT_EVENT_DEF(CAR_ACCELERATE_BRAKE, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN); + + ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_RIGHT_PAD,GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X); + ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_UP_DOWN_PAD, GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y); + } + + //Camera keyboard control on keybord + DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_KBD, WKEY_NUMPAD4, XKEY_NUMPAD4, X1KEY_NUMPAD4, PS3KEY_NUMPAD4, PS4KEY_NUMPAD4, AKEY_UNKNOWN, OSXKEY_NUMPAD4, IKEY_UNKNOWN, LINUXKEY_NUMPAD4, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_RIGHT_KBD, WKEY_NUMPAD6, XKEY_NUMPAD6, X1KEY_NUMPAD6, PS3KEY_NUMPAD6, PS4KEY_NUMPAD6, AKEY_UNKNOWN, OSXKEY_NUMPAD6, IKEY_UNKNOWN, LINUXKEY_NUMPAD6, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_UP_KBD, WKEY_NUMPAD8, XKEY_NUMPAD8, X1KEY_NUMPAD8, PS3KEY_NUMPAD8, PS4KEY_NUMPAD8, AKEY_UNKNOWN, OSXKEY_NUMPAD8, IKEY_UNKNOWN, LINUXKEY_NUMPAD8, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_DOWN_KBD, WKEY_NUMPAD2, XKEY_NUMPAD2, X1KEY_NUMPAD2, PS3KEY_NUMPAD2, PS4KEY_NUMPAD2, AKEY_UNKNOWN, OSXKEY_NUMPAD2, IKEY_UNKNOWN, LINUXKEY_NUMPAD2, WIIUKEY_UNKNOWN); + + //General control events on keyboard. + DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_FLAG, WKEY_F9, XKEY_F9, X1KEY_F9, PS3KEY_F9, PS4KEY_F9, AKEY_UNKNOWN, OSXKEY_T, IKEY_UNKNOWN, LINUXKEY_F9, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_ENGINE, WKEY_2, XKEY_2, X1KEY_2, PS3KEY_2, PS4KEY_2, AKEY_UNKNOWN, OSXKEY_2, IKEY_UNKNOWN, LINUXKEY_2, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_WHEEL, WKEY_1, XKEY_1, X1KEY_1, PS3KEY_1, PS4KEY_1, AKEY_UNKNOWN, OSXKEY_1, IKEY_UNKNOWN, LINUXKEY_1, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(FIX_CAR, WKEY_K, XKEY_K, X1KEY_K, PS3KEY_K, PS4KEY_K, AKEY_UNKNOWN, OSXKEY_K, IKEY_UNKNOWN, LINUXKEY_K, WIIUKEY_UNKNOWN); + + //General control events on gamepad. + DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_FLAG, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_WEST); + DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_ENGINE, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_SHOULDER_TOP); + DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_WHEEL, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_SHOULDER_TOP); + DIGITAL_INPUT_EVENT_DEF(FIX_CAR, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK); + + //General control events on touch + TOUCH_INPUT_EVENT_DEF(FIX_CAR, "Reset Car", ABUTTON_5, IBUTTON_5); + TOUCH_INPUT_EVENT_DEF(CAR_HANDBRAKE_PAD, "Handbrake", AQUICK_BUTTON_1, IQUICK_BUTTON_1); +} + +void SampleVehicle::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val) +{ + switch (ie.m_Id) + { + case VEH_SAVE_KBD: + { + if(val) + { +#if defined(SERIALIZE_VEHICLE_RPEX) || defined(SERIALIZE_VEHICLE_BINARY) + PxSerializationRegistry* sr = mVehicleManager.getSerializationRegistry(); + PxVehicleWheels& focusVehicle = *mVehicleManager.getVehicle(mPlayerVehicle); + PxCollection* c = PxCreateCollection(); + c->add( focusVehicle, 1 ); + PxSerialization::complete(*c, *sr, NULL); + PxDefaultFileOutputStream theStream(mVehicleFilePath); +#if defined(SERIALIZE_VEHICLE_RPEX) + PxSerialization::serializeCollectionToXml(theStream, *c, *sr, &getCooking()); +#elif defined(SERIALIZE_VEHICLE_BINARY) + PxSerialization::serializeCollectionToBinary(theStream, *c, *sr); +#endif + c->release(); +#endif + } + } + break; + case VEH_ACCELERATE_KBD: + { + mControlInputs.setAccelKeyPressed(val); + } + break; + case VEH_GEAR_DOWN_KBD: + { + mControlInputs.setGearDownKeyPressed(val); + } + break; + case VEH_GEAR_UP_KBD: + { + mControlInputs.setGearUpKeyPressed(val); + } + break; + case CAR_BRAKE_KBD: + { + mControlInputs.setBrakeKeyPressed(val); + } + break; + case CAR_STEER_LEFT_KBD: + { + mControlInputs.setSteerRightKeyPressed(val); + } + break; + case CAR_STEER_RIGHT_KBD: + { + mControlInputs.setSteerLeftKeyPressed(val); + } + break; + case CAR_HANDBRAKE_KBD: + { + mControlInputs.setHandbrakeKeyPressed(val); + } + break; + + case TANK_THRUST_LEFT_KBD: + { + if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel) + { + mControlInputs.setThrustLeftKeyPressed(val); + mControlInputs.setAccelKeyPressed(val); + } + else if(val) + { + mControlInputs.setThrustLeftKeyPressed(val); + mControlInputs.setAccelKeyPressed(val); + } + else + { + mControlInputs.setThrustLeftKeyPressed(val); + } + } + break; + case TANK_THRUST_RIGHT_KBD: + { + if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel) + { + mControlInputs.setThrustRightKeyPressed(val); + mControlInputs.setAccelKeyPressed(val); + } + else if(val) + { + mControlInputs.setThrustRightKeyPressed(val); + mControlInputs.setAccelKeyPressed(val); + } + else + { + mControlInputs.setThrustRightKeyPressed(val); + } + } + break; + case TANK_BRAKE_LEFT_KBD: + { + if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel) + { + mControlInputs.setBrakeLeftKeyPressed(val); + mControlInputs.setAccelKeyPressed(val); + } + else if(val) + { + mControlInputs.setBrakeLeftKeyPressed(val); + } + else + { + mControlInputs.setBrakeLeftKeyPressed(val); + } + } + break; + case TANK_BRAKE_RIGHT_KBD: + { + if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel) + { + mControlInputs.setBrakeRightKeyPressed(val); + mControlInputs.setAccelKeyPressed(val); + } + else if(val) + { + mControlInputs.setBrakeRightKeyPressed(val); + } + else + { + mControlInputs.setBrakeRightKeyPressed(val); + } + } + break; + case VEH_GEAR_DOWN_PAD: + { + mControlInputs.setGearDown(val); + } + break; + case VEH_GEAR_UP_PAD: + { + mControlInputs.setGearUp(val); + } + break; + case CAR_HANDBRAKE_PAD: + { + mControlInputs.setHandbrake(val); + } + break; + case AUTOMATIC_GEAR: + { + if(val) + { + mVehicleController.toggleAutoGearFlag(); + } + } + break; + case DEBUG_RENDER_FLAG: + { + if(val) + { + mDebugRenderFlag = !mDebugRenderFlag; + } + } + break; + case DEBUG_RENDER_WHEEL: + { + if(val) + { +#if PX_DEBUG_VEHICLE_ON + mDebugRenderActiveGraphChannelWheel++; + if(mDebugRenderActiveGraphChannelWheel==PxVehicleWheelGraphChannel::eMAX_NB_WHEEL_CHANNELS) + { + mDebugRenderActiveGraphChannelWheel=0; + } +#endif + } + } + break; + case DEBUG_RENDER_ENGINE: + { + if(val) + { +#if PX_DEBUG_VEHICLE_ON + mDebugRenderActiveGraphChannelEngine++; + if(mDebugRenderActiveGraphChannelEngine==PxVehicleDriveGraphChannel::eMAX_NB_DRIVE_CHANNELS) + { + mDebugRenderActiveGraphChannelEngine=0; + } +#endif + } + } + break; + case RETRY: + { + if(val) + mBackToStart=true; + } + break; + case FIX_CAR: + { + if(val) + mFixCar = true; + } + break; + case CAMERA_ROTATE_LEFT_KBD: + { + mControlInputs.setRotateY(val ? -0.5f : 0.0f); + } + break; + case CAMERA_ROTATE_RIGHT_KBD: + { + mControlInputs.setRotateY(val ? 0.5f : 0.0f); + } + break; + case CAMERA_ROTATE_UP_KBD: + { + mControlInputs.setRotateZ(val ? 0.5f : 0.0f); + } + break; + case CAMERA_ROTATE_DOWN_KBD: + { + mControlInputs.setRotateZ(val ? -0.5f : 0.0f); + } + break; + case W3MODE: + { + if(val) + { + m3WModeIncremented=true; + } + } + break; + default: + break; + } + + PhysXSample::onDigitalInputEvent(ie,val); +} + +void SampleVehicle::onAnalogInputEvent(const SampleFramework::InputEvent& ie, float val) +{ + switch(mPlayerVehicleType) + { + case ePLAYER_VEHICLE_TYPE_VEHICLE4W: + case ePLAYER_VEHICLE_TYPE_VEHICLE6W: + + switch (ie.m_Id) + { + case VEH_ACCELERATE_PAD: + { + mControlInputs.setAccel(val); + } + break; + case CAR_BRAKE_PAD: + { + mControlInputs.setBrake(val); + } + break; + case CAR_ACCELERATE_BRAKE: + { + if (val >= 0.0f) + { + mControlInputs.setAccel(val); + mControlInputs.setBrake(0.0f); + } + else + { + mControlInputs.setBrake(-val); + mControlInputs.setAccel(0.0f); + } + } + break; + case CAR_STEER_PAD: + { + mControlInputs.setSteer(-val); + } + break; + case CAMERA_ROTATE_LEFT_RIGHT_PAD: + { + mControlInputs.setRotateY(-val); + } + break; + case CAMERA_ROTATE_UP_DOWN_PAD: + { + mControlInputs.setRotateZ(-val); + } + break; + default: + break; + } + + break; + + case ePLAYER_VEHICLE_TYPE_TANK4W: + case ePLAYER_VEHICLE_TYPE_TANK6W: + + switch (ie.m_Id) + { + case VEH_ACCELERATE_PAD: + { + PX_ASSERT(PxVehicleDriveTankControlModel::eSTANDARD==mTankDriveModel); + mControlInputs.setAccel(val); + } + break; + case TANK_THRUST_RIGHT_PAD: + { + if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel) + { + mControlInputs.setThrustLeft(val); + mControlInputs.setAccel(val ? 1.0f : 0.0f); + } + else if(val>0) + { + mControlInputs.setThrustLeft(val); + mControlInputs.setBrakeLeft(0.0f); + } + else + { + mControlInputs.setThrustLeft(0.0f); + mControlInputs.setBrakeLeft(-val); + } + } + break; + case TANK_THRUST_LEFT_PAD: + { + if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel) + { + mControlInputs.setThrustRight(val); + mControlInputs.setAccel(val ? 1.0f : 0.0f); + } + else if(val>0) + { + mControlInputs.setThrustRight(val); + mControlInputs.setBrakeRight(0.0f); + } + else + { + mControlInputs.setThrustRight(0.0f); + mControlInputs.setBrakeRight(-val); + } + } + break; + case TANK_BRAKE_LEFT_PAD: + { + PX_ASSERT(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel); + mControlInputs.setBrakeLeft(val); + } + break; + case TANK_BRAKE_RIGHT_PAD: + { + PX_ASSERT(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel); + mControlInputs.setBrakeRight(val); + } + break; + case CAMERA_ROTATE_LEFT_RIGHT_PAD: + { + mControlInputs.setRotateY(-val); + } + break; + default: + break; + } + break; + + default: + PX_ASSERT(false); + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_DEBUG_VEHICLE_ON +void SampleVehicle::clearTelemetryData() +{ + mTelemetryData4W->clear(); + mTelemetryData6W->clear(); +} +#endif + +void SampleVehicle::updateCameraController(const PxF32 dtime, PxScene& scene) +{ + mCameraController.update(dtime,*mVehicleManager.getVehicle(mPlayerVehicle),scene); +} + +void SampleVehicle::updateVehicleController(const PxF32 dtime) +{ + PxSceneReadLock scopedLock(*mScene); + mVehicleController.update(dtime, mVehicleManager.getVehicleWheelQueryResults(mPlayerVehicle), *mVehicleManager.getVehicle(mPlayerVehicle)); +} + +void SampleVehicle::updateVehicleManager(const PxF32 dtime, const PxVec3& gravity) +{ + switch(mPlayerVehicleType) + { + case ePLAYER_VEHICLE_TYPE_VEHICLE4W: + case ePLAYER_VEHICLE_TYPE_TANK4W: +#if PX_DEBUG_VEHICLE_ON + mVehicleManager.updateAndRecordTelemetryData(dtime,gravity,mVehicleManager.getVehicle(mPlayerVehicle),mTelemetryData4W); +#else + mVehicleManager.update(dtime,gravity); +#endif + break; + case ePLAYER_VEHICLE_TYPE_VEHICLE6W: + case ePLAYER_VEHICLE_TYPE_TANK6W: +#if PX_DEBUG_VEHICLE_ON + mVehicleManager.updateAndRecordTelemetryData(dtime,gravity,mVehicleManager.getVehicle(mPlayerVehicle),mTelemetryData6W); +#else + mVehicleManager.update(dtime,gravity); +#endif + break; + default: + PX_ASSERT(false); + break; + } +} + +void SampleVehicle::resetFocusVehicleAtWaypoint() +{ + mVehicleManager.resetNWCar(mWayPoints.getResetTransform(),mPlayerVehicle); +} + +PxRigidDynamic* SampleVehicle::getFocusVehicleRigidDynamicActor() +{ + return mVehicleManager.getVehicle(mPlayerVehicle)->getRigidDynamicActor(); +} + +void SampleVehicle::drawFocusVehicleGraphsAndPrintTireSurfaces() +{ + drawGraphsAndPrintTireSurfaceTypes(*mVehicleManager.getVehicle(mPlayerVehicle), mVehicleManager.getVehicleWheelQueryResults(mPlayerVehicle)); +} + +bool SampleVehicle::getFocusVehicleUsesAutoGears() +{ + PxVehicleWheels* vehWheels=mVehicleManager.getVehicle(mPlayerVehicle); + PxVehicleDriveDynData* driveDynData=NULL; + switch(vehWheels->getVehicleType()) + { + case PxVehicleTypes::eDRIVE4W: + { + PxVehicleDrive4W* vehDrive4W=(PxVehicleDrive4W*)vehWheels; + driveDynData=&vehDrive4W->mDriveDynData; + } + break; + case PxVehicleTypes::eDRIVENW: + { + PxVehicleDriveNW* vehDriveNW=(PxVehicleDriveNW*)vehWheels; + driveDynData=&vehDriveNW->mDriveDynData; + } + break; + case PxVehicleTypes::eDRIVETANK: + { + PxVehicleDriveTank* vehDriveTank=(PxVehicleDriveTank*)vehWheels; + driveDynData=&vehDriveTank->mDriveDynData; + } + break; + default: + PX_ASSERT(false); + break; + } + + return driveDynData->getUseAutoGears(); +} diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.h new file mode 100644 index 00000000..e77a116f --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.h @@ -0,0 +1,198 @@ +// 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. + + +#ifndef SAMPLE_VEHICLE_H +#define SAMPLE_VEHICLE_H + +#include "PhysXSample.h" +#include "SampleVehicle_ControlInputs.h" +#include "SampleVehicle_CameraController.h" +#include "SampleVehicle_VehicleController.h" +#include "SampleVehicle_VehicleManager.h" +#include "SampleVehicle_GameLogic.h" +#include "vehicle/PxVehicleTireFriction.h" + +class SampleVehicle : public PhysXSample +{ + +public: + + SampleVehicle(PhysXSampleApplication& app); + virtual ~SampleVehicle(); + + + /////////////////////////////////////////////////////////////////////////////// + + // Implements RAWImportCallback + virtual void newMesh(const RAWMesh&); + + /////////////////////////////////////////////////////////////////////////////// + + // Implements SampleApplication + virtual void onInit(); + virtual void onInit(bool restart) { onInit(); } + virtual void onShutdown(); + + virtual void onTickPreRender(PxF32 dtime); + virtual void onTickPostRender(PxF32 dtime); + + virtual void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val); + virtual void onAnalogInputEvent(const SampleFramework::InputEvent& , float val); + + /////////////////////////////////////////////////////////////////////////////// + + // Implements PhysXSampleApplication + virtual void helpRender(PxU32 x, PxU32 y, PxU8 textAlpha); + virtual void descriptionRender(PxU32 x, PxU32 y, PxU8 textAlpha); + virtual void customizeSample(SampleSetup&); + virtual void customizeSceneDesc(PxSceneDesc&); + virtual void customizeRender(); + virtual void onSubstep(PxF32 dtime); + virtual void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents); + +private: + + SampleVehicle_ControlInputs mControlInputs; + SampleVehicle_CameraController mCameraController; + SampleVehicle_VehicleController mVehicleController; + + + //Terrain + + PxF32* mTerrainVB; + PxU32 mNbTerrainVerts; + + enum + { + MAX_NUM_INDEX_BUFFERS = 16 + }; + PxU32 mNbIB; + PxU32* mIB[MAX_NUM_INDEX_BUFFERS]; + PxU32 mNbTriangles[MAX_NUM_INDEX_BUFFERS]; + PxU32 mRenderMaterial[MAX_NUM_INDEX_BUFFERS]; + + //Materials + + PxVehicleDrivableSurfaceType mVehicleDrivableSurfaceTypes[MAX_NUM_INDEX_BUFFERS]; + PxMaterial* mStandardMaterials[MAX_NUM_INDEX_BUFFERS]; + PxMaterial* mChassisMaterialDrivable; + PxMaterial* mChassisMaterialNonDrivable; + + + RenderMaterial* mTerrainMaterial; + RenderMaterial* mRoadMaterial; + RenderMaterial* mRoadIceMaterial; + RenderMaterial* mRoadGravelMaterial; + + void createStandardMaterials(); + + enum eFocusVehicleType + { + ePLAYER_VEHICLE_TYPE_VEHICLE4W=0, + ePLAYER_VEHICLE_TYPE_VEHICLE6W, + ePLAYER_VEHICLE_TYPE_TANK4W, + ePLAYER_VEHICLE_TYPE_TANK6W, + eMAX_NUM_FOCUS_VEHICLE_TYPES + }; + + // Vehicles + SampleVehicle_VehicleManager mVehicleManager; + std::vector<RenderMeshActor*> mVehicleGraphics; + PxU32 mPlayerVehicle; + eFocusVehicleType mPlayerVehicleType; + PxVehicleDriveTankControlModel::Enum mTankDriveModel; + + const char* getFocusVehicleName(); + void createVehicles(); + + PxU32 mTerrainSize; + PxF32 mTerrainWidth; + PxRigidActor* mHFActor; + + void createTrack(PxU32 size, PxF32 width, PxF32 chaos); + void createTerrain(PxU32 size, PxF32 width, PxF32 chaos); + void addRenderMesh(PxF32* verts, PxU32 nVerts, PxU32* indices, PxU32 mIndices, PxU32 matID); + void addMesh(PxRigidActor* actor, PxF32* verts, PxU32 nVerts, PxU32* indices, PxU32 mIndices, PxU32 materialIndex, const char* filename); + void createLandscapeMesh(); + + //Obstacles + + void createObstacles(); + PxRigidStatic* addStaticObstacle(const PxTransform& transform, const PxU32 numShapes, PxTransform* shapeTransforms, PxGeometry** shapeGeometries, PxMaterial** shapeMaterials); + PxRigidDynamic* addDynamicObstacle(const PxTransform& transform, const PxF32 mass, const PxU32 numShapes, PxTransform* transforms, PxGeometry** geometries, PxMaterial** materials); + PxRigidDynamic* addDynamicDrivableObstacle(const PxTransform& transform, const PxF32 mass, const PxU32 numShapes, PxTransform* transforms, PxGeometry** geometries, PxMaterial** materials); + void createStack(PxU32 size, PxF32 boxSize, const PxVec3& pos, const PxQuat& quat); + void createWall(const PxU32 numHorizontalBoxes, const PxU32 numVerticalBoxes, const PxF32 boxSize, const PxVec3& pos, const PxQuat& quat); + + //Debug render + + bool mHideScreenText; + bool mDebugRenderFlag; +#if PX_DEBUG_VEHICLE_ON + PxU32 mDebugRenderActiveGraphChannelWheel; + PxU32 mDebugRenderActiveGraphChannelEngine; + PxVehicleTelemetryData* mTelemetryData4W; + PxVehicleTelemetryData* mTelemetryData6W; +#endif + void setupTelemetryData(); + void clearTelemetryData(); + + void drawWheels(); + void drawVehicleDebug(); + void drawHud(); + void drawGraphsAndPrintTireSurfaceTypes(const PxVehicleWheels& focusVehicle, const PxVehicleWheelQueryResult& focusVehicleWheelQueryResults); + void drawFocusVehicleGraphsAndPrintTireSurfaces(); + + //Waypoints + SampleVehicleWayPoints mWayPoints; + bool mFixCar; + bool mBackToStart; + + //3W and 4W modes + bool m3WModeIncremented; + PxU32 m3WMode; + + PxF32 mForwardSpeedHud; + +#if defined(SERIALIZE_VEHICLE_BINARY) + void* mMemory; +#endif + + void updateCameraController(const PxF32 dtime, PxScene& scene); + void updateVehicleController(const PxF32 dtime); + void updateVehicleManager(const PxF32 dtime, const PxVec3& gravity); + + void resetFocusVehicleAtWaypoint(); + PxRigidDynamic* getFocusVehicleRigidDynamicActor(); + bool getFocusVehicleUsesAutoGears(); + char mVehicleFilePath[256]; +}; + +#endif diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicleDebugRender.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleDebugRender.cpp new file mode 100644 index 00000000..233bad36 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleDebugRender.cpp @@ -0,0 +1,367 @@ +// 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 "RenderPhysX3Debug.h" +#include "PxRigidDynamic.h" +#include "SampleVehicle_VehicleManager.h" + +using namespace SampleRenderer; + +// PT: this file contains the part of SampleVehicle dealing with cars' debug rendering + +void SampleVehicle::drawWheels() +{ + PxSceneReadLock scopedLock(*mScene); + const RendererColor colorPurple(255, 0, 255); + + for(PxU32 i=0;i<mVehicleManager.getNbVehicles();i++) + { + //Draw a rotating arrow to get an idea of the wheel rotation speed. + PxVehicleWheels* veh=mVehicleManager.getVehicle(i); + const PxRigidDynamic* actor=veh->getRigidDynamicActor(); + PxShape* shapeBuffer[PX_MAX_NB_WHEELS]; + actor->getShapes(shapeBuffer,veh->mWheelsSimData.getNbWheels()); + const PxTransform vehGlobalPose=actor->getGlobalPose(); + const PxU32 numWheels=veh->mWheelsSimData.getNbWheels(); + for(PxU32 j=0;j<numWheels;j++) + { + const PxTransform wheelTransform=vehGlobalPose.transform(shapeBuffer[j]->getLocalPose()); + const PxF32 wheelRadius=veh->mWheelsSimData.getWheelData(j).mRadius; + const PxF32 wheelHalfWidth=veh->mWheelsSimData.getWheelData(j).mWidth*0.5f; + PxVec3 offset=wheelTransform.q.getBasisVector0()*wheelHalfWidth; + offset*= (veh->mWheelsSimData.getWheelCentreOffset(j).x > 0) ? 1.0f : -1.0f; + const PxVec3 arrow=wheelTransform.rotate(PxVec3(0,0,1)); + getDebugRenderer()->addLine(wheelTransform.p+offset, wheelTransform.p+offset+arrow*wheelRadius, colorPurple); + } + } +} + +void SampleVehicle::drawVehicleDebug() +{ + PxSceneReadLock scopedLock(*mScene); + const RendererColor colorColl(255, 0, 0); + const RendererColor colorCol2(0, 255, 0); + const RendererColor colorCol3(0, 0, 255); + +#if PX_DEBUG_VEHICLE_ON + const PxVec3* tireForceAppPoints=NULL; + const PxVec3* suspForceAppPoints=NULL; + switch(mPlayerVehicleType) + { + case ePLAYER_VEHICLE_TYPE_VEHICLE4W: + case ePLAYER_VEHICLE_TYPE_TANK4W: + tireForceAppPoints=mTelemetryData4W->getTireforceAppPoints(); + suspForceAppPoints=mTelemetryData4W->getSuspforceAppPoints(); + break; + case ePLAYER_VEHICLE_TYPE_VEHICLE6W: + case ePLAYER_VEHICLE_TYPE_TANK6W: + tireForceAppPoints=mTelemetryData6W->getTireforceAppPoints(); + suspForceAppPoints=mTelemetryData6W->getSuspforceAppPoints(); + break; + default: + PX_ASSERT(false); + break; + } +#endif + + const PxVehicleWheels& vehicle4W=*mVehicleManager.getVehicle(mPlayerVehicle); + const PxVehicleWheelQueryResult& vehicleWheelQueryResults=mVehicleManager.getVehicleWheelQueryResults(mPlayerVehicle); + const PxRigidDynamic* actor=vehicle4W.getRigidDynamicActor(); + const PxU32 numWheels=vehicle4W.mWheelsSimData.getNbWheels(); + PxVec3 v[8]; + PxVec3 w[8]; + PxF32 l[8]; + for(PxU32 i=0;i<numWheels;i++) + { + v[i] = vehicleWheelQueryResults.wheelQueryResults[i].suspLineStart; + w[i] = vehicleWheelQueryResults.wheelQueryResults[i].suspLineDir; + l[i] = vehicleWheelQueryResults.wheelQueryResults[i].suspLineLength; + } + + + const PxTransform t=actor->getGlobalPose().transform(actor->getCMassLocalPose()); + const PxVec3 dirs[3]={t.rotate(PxVec3(1,0,0)),t.rotate(PxVec3(0,1,0)),t.rotate(PxVec3(0,0,1))}; + getDebugRenderer()->addLine(t.p, t.p + dirs[0]*4.0f, colorColl); + getDebugRenderer()->addLine(t.p, t.p + dirs[1]*4.0f, colorColl); + getDebugRenderer()->addLine(t.p, t.p + dirs[2]*4.0f, colorColl); + + for(PxU32 j=0;j<numWheels;j++) + { + getDebugRenderer()->addLine(v[j], v[j]+w[j]*l[j], colorColl); + +#if PX_DEBUG_VEHICLE_ON + //Draw all tire force app points. + const PxVec3& appPoint = tireForceAppPoints[j]; + getDebugRenderer()->addLine(appPoint - dirs[0], appPoint + dirs[0], colorCol2); + getDebugRenderer()->addLine(appPoint - dirs[2], appPoint + dirs[2], colorCol2); + + //Draw all susp force app points. + const PxVec3& appPoint2 = suspForceAppPoints[j]; + getDebugRenderer()->addLine(appPoint2 - dirs[0], appPoint2 + dirs[0], colorCol3); + getDebugRenderer()->addLine(appPoint2 - dirs[2], appPoint2 + dirs[2], colorCol3); +#endif + } +} + +static void drawBox2D(Renderer* renderer, PxF32 minX, PxF32 maxX, PxF32 minY, PxF32 maxY, const RendererColor& color, PxF32 alpha) +{ + ScreenQuad sq; + sq.mX0 = minX; + sq.mY0 = 1.0f - minY; + sq.mX1 = maxX; + sq.mY1 = 1.0f - maxY; + sq.mLeftUpColor = color; + sq.mRightUpColor = color; + sq.mLeftDownColor = color; + sq.mRightDownColor = color; + sq.mAlpha = alpha; + + renderer->drawScreenQuad(sq); +} + +static void print(Renderer* renderer, PxF32 x, PxF32 y, PxF32 scale_, const char* text) +{ + PxU32 width, height; + renderer->getWindowSize(width, height); + + y = 1.0f - y; + + const PxReal scale = scale_*20.0f; + const PxReal shadowOffset = 6.0f; + const RendererColor textColor(255, 255, 255, 255); + + renderer->print(PxU32(x*PxF32(width)), PxU32(y*PxF32(height)), text, scale, shadowOffset, textColor); +} + +void SampleVehicle::drawHud() +{ + const PxVehicleWheels& focusVehicle = *mVehicleManager.getVehicle(mPlayerVehicle); + PxVehicleDriveDynData* driveDynData=NULL; + PxVehicleDriveSimData* driveSimData=NULL; + switch(focusVehicle.getVehicleType()) + { + case PxVehicleTypes::eDRIVE4W: + { + PxVehicleDrive4W& vehDrive4W=(PxVehicleDrive4W&)focusVehicle; + driveDynData=&vehDrive4W.mDriveDynData; + driveSimData=&vehDrive4W.mDriveSimData; + } + break; + case PxVehicleTypes::eDRIVENW: + { + PxVehicleDriveNW& vehDriveNW=(PxVehicleDriveNW&)focusVehicle; + driveDynData=&vehDriveNW.mDriveDynData; + driveSimData=&vehDriveNW.mDriveSimData; + } + break; + case PxVehicleTypes::eDRIVETANK: + { + PxVehicleDriveTank& vehDriveTank=(PxVehicleDriveTank&)focusVehicle; + driveDynData=&vehDriveTank.mDriveDynData; + driveSimData=&vehDriveTank.mDriveSimData; + } + break; + default: + PX_ASSERT(false); + break; + } + + const PxU32 currentGear=driveDynData->getCurrentGear(); + const PxF32 vz=mForwardSpeedHud*3.6f; + const PxF32 revs=driveDynData->getEngineRotationSpeed(); + const PxF32 maxRevs=driveSimData->getEngineData().mMaxOmega*60*0.5f/PxPi;//Convert from radians per second to rpm + const PxF32 invMaxRevs=driveSimData->getEngineData().getRecipMaxOmega(); + + //Draw gears and speed. + + const PxF32 x=0.5f; + const PxF32 y=0.18f; + const PxF32 length=0.1f; + const PxF32 textheight=0.02f; + + Renderer* renderer = getRenderer(); + drawBox2D(renderer, x-length-textheight, x+length+textheight, y, y+length+textheight, RendererColor(255, 255, 255), 0.5f); + + //Gear + char gear[PxVehicleGearsData::eGEARSRATIO_COUNT][64]= + { + "R","N","1","2","3","4","5" + }; + print(renderer, x-0.25f*textheight, y+0.02f, 0.02f, gear[currentGear]); + + //Speed + char speed[64]; + sprintf(speed, "%1.0f %s", PxAbs(vz), "kmph"); + print(renderer, x-textheight, y+length-textheight, textheight, speed); + + //Revs + { + const PxF32 xy[4]={x, 1.0f-y, x-length, 1.0f-(y+length)}; + renderer->drawLines2D(2, xy, RendererColor(0, 0, 255)); + + char buffer[64]; + sprintf(buffer, "%d \n", 0); + print(renderer, x-length, y+length, textheight, buffer); + } + { + const PxF32 xy[4]={x, 1.0f-y, x+length, 1.0f-(y+length)}; + renderer->drawLines2D(2, xy, RendererColor(0, 0, 255)); + + char buffer[64]; + sprintf(buffer, "%1.0f \n", maxRevs); + print(renderer, x+length-2*textheight, y+length, textheight, buffer); + } + { + const PxF32 alpha=revs*invMaxRevs; + const PxF32 dx=-(1.0f-alpha)*length + alpha*length; + const PxF32 xy[4]={x, 1.0f-y, x+dx, 1.0f-(y+length)}; + renderer->drawLines2D(2, xy, RendererColor(255, 0, 0)); + } +} + +#if PX_DEBUG_VEHICLE_ON + +static PX_FORCE_INLINE RendererColor getColor(const PxVec3& c) +{ + return RendererColor(PxU8(c.x), PxU8(c.y), PxU8(c.z)); +} + +static PX_FORCE_INLINE void convertColors(const PxVec3* src, RendererColor* dst) +{ + for(PxU32 i=0;i<PxVehicleGraph::eMAX_NB_SAMPLES;i++) + *dst++ = getColor(src[i]); +} + +static void convertY(PxF32* xy) +{ + for(PxU32 i=0;i<PxVehicleGraph::eMAX_NB_SAMPLES;i++) + xy[2*i+1]=1.0f-xy[2*i+1]; +} + +#endif //PX_DEBUG_VEHICLE_ON + +#if PX_DEBUG_VEHICLE_ON + +void drawGraphsAndPrintTireSurfaceTypesN +(const PxVehicleTelemetryData& telemetryData, const PxU32* tireTypes, const PxU32* surfaceTypes, + const PxU32 activeEngineGraphChannel, const PxU32 activeWheelGraphChannel, + SampleRenderer::Renderer* renderer) +{ + + PxF32 xy[2*PxVehicleGraph::eMAX_NB_SAMPLES]; + PxVec3 color[PxVehicleGraph::eMAX_NB_SAMPLES]; + RendererColor rendererColor[PxVehicleGraph::eMAX_NB_SAMPLES]; + char title[PxVehicleGraph::eMAX_NB_TITLE_CHARS]; + + const PxU32 numWheelGraphs=telemetryData.getNbWheelGraphs(); + + for(PxU32 i=0;i<numWheelGraphs;i++) + { + PxF32 xMin,xMax,yMin,yMax; + telemetryData.getWheelGraph(i).getBackgroundCoords(xMin,yMin,xMax,yMax); + const PxVec3& backgroundColor=telemetryData.getWheelGraph(i).getBackgroundColor(); + const PxF32 alpha=telemetryData.getWheelGraph(i).getBackgroundAlpha(); + drawBox2D(renderer, xMin,xMax,yMin,yMax, getColor(backgroundColor),alpha); + + telemetryData.getWheelGraph(i).computeGraphChannel(activeWheelGraphChannel,xy,color,title); + convertY(xy); + convertColors(color, rendererColor); + renderer->drawLines2D(PxVehicleGraph::eMAX_NB_SAMPLES, xy, rendererColor); + + print(renderer, xMin,yMax-0.02f, 0.02f, title); + + const PxU32 tireType=tireTypes[i]; + const PxU32 tireSurfaceType=surfaceTypes[i]; + + if (PxVehicleDrivableSurfaceType::eSURFACE_TYPE_UNKNOWN!=tireSurfaceType) + { + const char* surfaceType= SurfaceTypeNames::getName(tireSurfaceType); + const PxF32 friction=TireFrictionMultipliers::getValue(tireSurfaceType, tireType); + char surfaceDetails[64]; + sprintf(surfaceDetails, "%s %1.2f \n", surfaceType, friction); + print(renderer, xMin+0.1f, yMax-0.12f, 0.02f, surfaceDetails); + } + } + + PxF32 xMin,xMax,yMin,yMax; + telemetryData.getEngineGraph().getBackgroundCoords(xMin,yMin,xMax,yMax); + const PxVec3& backgroundColor=telemetryData.getEngineGraph().getBackgroundColor(); + const PxF32 alpha=telemetryData.getEngineGraph().getBackgroundAlpha(); + drawBox2D(renderer, xMin,xMax,yMin,yMax, getColor(backgroundColor),alpha); + + telemetryData.getEngineGraph().computeGraphChannel(activeEngineGraphChannel,xy,color,title); + convertY(xy); + convertColors(color, rendererColor); + renderer->drawLines2D(PxVehicleGraph::eMAX_NB_SAMPLES, xy, rendererColor); + + print(renderer, xMin,yMax-0.02f,0.02f,title); +} + +#endif //PX_DEBUG_VEHICLE_GRAPH_ON + +void SampleVehicle::drawGraphsAndPrintTireSurfaceTypes(const PxVehicleWheels& focusVehicle, const PxVehicleWheelQueryResult& focusVehicleWheelQueryResults) +{ +#if PX_DEBUG_VEHICLE_ON + + PxU32 tireTypes[8]; + PxU32 surfaceTypes[8]; + const PxU32 numWheels=focusVehicle.mWheelsSimData.getNbWheels(); + PX_ASSERT(numWheels<=8); + for(PxU32 i=0;i<numWheels;i++) + { + tireTypes[i]=focusVehicle.mWheelsSimData.getTireData(i).mType; + surfaceTypes[i]=focusVehicleWheelQueryResults.wheelQueryResults[i].tireSurfaceType; + } + + PxVehicleTelemetryData* vehTelData=NULL; + switch(mPlayerVehicleType) + { + case ePLAYER_VEHICLE_TYPE_VEHICLE4W: + case ePLAYER_VEHICLE_TYPE_TANK4W: + vehTelData=mTelemetryData4W; + break; + case ePLAYER_VEHICLE_TYPE_VEHICLE6W: + case ePLAYER_VEHICLE_TYPE_TANK6W: + vehTelData=mTelemetryData6W; + break; + default: + PX_ASSERT(false); + break; + } + + drawGraphsAndPrintTireSurfaceTypesN( + *vehTelData,tireTypes,surfaceTypes, + mDebugRenderActiveGraphChannelEngine,mDebugRenderActiveGraphChannelWheel, + getRenderer()); + +#endif +} + + diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicleInputEventIds.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleInputEventIds.h new file mode 100644 index 00000000..29781d77 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleInputEventIds.h @@ -0,0 +1,98 @@ +// 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. +#ifndef _SAMPLE_VEHICLE_INPUT_EVENT_IDS_H +#define _SAMPLE_VEHICLE_INPUT_EVENT_IDS_H + +#include <SampleBaseInputEventIds.h> + +// InputEvents used by SampleVehicle +enum SampleVehicleInputEventIds +{ + SAMPLE_VEHICLE_FIRST_ID = NUM_SAMPLE_BASE_INPUT_EVENT_IDS, + + CAR_ACCELERATE_BRAKE, + + //KEYBOARD (car+tank) + VEH_ACCELERATE_KBD, + VEH_GEAR_UP_KBD, + VEH_GEAR_DOWN_KBD, + + VEH_SAVE_KBD, + + //KEYBOARD (car) + CAR_BRAKE_KBD, + CAR_HANDBRAKE_KBD, + CAR_STEER_LEFT_KBD, + CAR_STEER_RIGHT_KBD, + + //KEYBOARD (tank) + TANK_THRUST_LEFT_KBD, + TANK_THRUST_RIGHT_KBD, + TANK_BRAKE_LEFT_KBD, + TANK_BRAKE_RIGHT_KBD, + + //KEYBOARD (camera) + CAMERA_ROTATE_LEFT_KBD, + CAMERA_ROTATE_RIGHT_KBD, + CAMERA_ROTATE_UP_KBD, + CAMERA_ROTATE_DOWN_KBD, + + //GAMEPAD (car+tank) + VEH_ACCELERATE_PAD, + VEH_GEAR_UP_PAD, + VEH_GEAR_DOWN_PAD, + + //GAMEPAD (car) + CAR_BRAKE_PAD, + CAR_HANDBRAKE_PAD, + CAR_STEER_PAD, + + //GAMEPAD (tank) + TANK_THRUST_LEFT_PAD, + TANK_THRUST_RIGHT_PAD, + TANK_BRAKE_LEFT_PAD, + TANK_BRAKE_RIGHT_PAD, + + //GAMEPAD (camera) + CAMERA_ROTATE_LEFT_RIGHT_PAD, + CAMERA_ROTATE_UP_DOWN_PAD, + + // + AUTOMATIC_GEAR, + DEBUG_RENDER_FLAG, + DEBUG_RENDER_WHEEL , + DEBUG_RENDER_ENGINE, + RETRY, + FIX_CAR, + CAMERA_LOCK, + W3MODE, + + + NUM_SAMPLE_VEHICLE_INPUT_EVENT_IDS, +}; + +#endif diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicleTerrain.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleTerrain.cpp new file mode 100644 index 00000000..e5d57c3a --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleTerrain.cpp @@ -0,0 +1,547 @@ +// 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_SceneQuery.h" +#include "SampleRandomPrecomputed.h" +#include "SampleAllocatorSDKClasses.h" +#include "RendererMemoryMacros.h" +#include "RenderMaterial.h" +#include "RenderMeshActor.h" +#include "cooking/PxTriangleMeshDesc.h" +#include "geometry/PxHeightFieldGeometry.h" +#include "geometry/PxHeightFieldSample.h" +#include "geometry/PxHeightFieldDesc.h" +#include "cooking/PxCooking.h" +#include "PxScene.h" +#include "PxRigidStatic.h" +#include "PxTkStream.h" +#include "PxTkFile.h" + +//using namespace physx; +using namespace PxToolkit; + +//Use a mesh (instead of a height field) +static bool gRecook = false; + +enum MaterialID +{ + MATERIAL_TERRAIN_MUD = 1000, + MATERIAL_ROAD_TARMAC = 1001, + MATERIAL_ROAD_SNOW = 1002, + MATERIAL_ROAD_GRASS = 1003, +}; + +static void computeTerrain(bool* done, float* pVB, PxU32 x0, PxU32 y0, PxU32 currentSize, float value, PxU32 initSize, SampleRandomPrecomputed& randomPrecomputed) +{ + // Compute new size + currentSize>>=1; + if(currentSize > 0) + { + const PxU32 x1 = (x0+currentSize) % initSize; + const PxU32 x2 = (x0+currentSize+currentSize) % initSize; + const PxU32 y1 = (y0+currentSize) % initSize; + const PxU32 y2 = (y0+currentSize+currentSize) % initSize; + + if(!done[x1 + y0*initSize]) pVB[(x1 + y0*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y0*initSize)*9+1] + pVB[(x2 + y0*initSize)*9+1]); + if(!done[x0 + y1*initSize]) pVB[(x0 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y0*initSize)*9+1] + pVB[(x0 + y2*initSize)*9+1]); + if(!done[x2 + y1*initSize]) pVB[(x2 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x2 + y0*initSize)*9+1] + pVB[(x2 + y2*initSize)*9+1]); + if(!done[x1 + y2*initSize]) pVB[(x1 + y2*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y2*initSize)*9+1] + pVB[(x2 + y2*initSize)*9+1]); + if(!done[x1 + y1*initSize]) pVB[(x1 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y1*initSize)*9+1] + pVB[(x2 + y1*initSize)*9+1]); + + done[x1 + y0*initSize] = true; + done[x0 + y1*initSize] = true; + done[x2 + y1*initSize] = true; + done[x1 + y2*initSize] = true; + done[x1 + y1*initSize] = true; + + // Recurse through 4 corners + value *= 0.5f; + computeTerrain(done, pVB, x0, y0, currentSize, value, initSize, randomPrecomputed); + computeTerrain(done, pVB, x0, y1, currentSize, value, initSize, randomPrecomputed); + computeTerrain(done, pVB, x1, y0, currentSize, value, initSize, randomPrecomputed); + computeTerrain(done, pVB, x1, y1, currentSize, value, initSize, randomPrecomputed); + } +} + +void SampleVehicle::createTerrain(PxU32 size, float width, float chaos) +{ + mNbTerrainVerts = size*size; + + // Vertex buffer + mTerrainVB = (float*)SAMPLE_ALLOC(sizeof(float)*mNbTerrainVerts*3*3); + for(PxU32 y=0;y<size;y++) + { + for(PxU32 x=0;x<size;x++) + { + mTerrainVB[(x+y*size)*9+0] = (float(x)-(float(size-1)*0.5f))* width; + mTerrainVB[(x+y*size)*9+1] = 0.0f; + mTerrainVB[(x+y*size)*9+2] = (float(y)-(float(size-1)*0.5f))* width; + mTerrainVB[(x+y*size)*9+3] = 0.0f; mTerrainVB[(x+y*size)*9+4] = 1.0f; mTerrainVB[(x+y*size)*9+5] = 0.0f; + mTerrainVB[(x+y*size)*9+6] = 0.5f; mTerrainVB[(x+y*size)*9+7] = 0.4f; mTerrainVB[(x+y*size)*9+8] = 0.2f; + } + } + + // Fractalize + bool* doneBuffer = (bool*)SAMPLE_ALLOC(sizeof(bool)*mNbTerrainVerts); + PxU32* tagBuffer = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*mNbTerrainVerts); + for(PxU32 i=0;i<mNbTerrainVerts;i++) + { + doneBuffer[i] = false; + tagBuffer[i] = 0; + } + mTerrainVB[1] = 10.0f; + mTerrainVB[(size-1)*9+1] = 10.0f; + mTerrainVB[(size*(size-1))*9+1] = 10.0f; + mTerrainVB[(mNbTerrainVerts-1)*9+1] = 10.0f; + + SampleRandomPrecomputed randomPrecomputed(*this); + computeTerrain(doneBuffer, mTerrainVB, 0, 0, size, chaos/16.0f, size, randomPrecomputed); + + const PxU32 street0 = (PxU32)(size/3.0f); + const PxU32 streetSize = (PxU32)(size/30.0f); + float ay = 0.0f; + + for(PxU32 y=0;y<size;y++) + { + for(PxU32 x=street0;x<street0+streetSize;x++) + { + ay+=mTerrainVB[(x+y*size)*9+1]; + ay+=mTerrainVB[(y+x*size)*9+1]; + } + } + + const float cx = size/2.0f; + const float cy = size/2.0f; + const float r = size/3.0f; + const float g = streetSize/2.0f; + + for(PxU32 i=0;i<mNbTerrainVerts;i++) + tagBuffer[i] = false; + + ay/=streetSize*size; + ay-=streetSize; + for(PxU32 y=15;y<size-15;y++) + { + bool smoothBorder = true; + + for(PxU32 x=street0;x<street0+streetSize;x++) + { + if(y > size*0.5f && y < size*0.7f) + { + mTerrainVB[(x+y*size)*9+1]=ay+sinf(((float)y)*12.0f+4.0f)*2.0f; + smoothBorder = false; + } + else + { + mTerrainVB[(x+y*size)*9+1]=ay; + } + + if(y > size*0.55f && y < size*0.75f) + { + mTerrainVB[(y+x*size)*9+1]=ay+sinf(y*12.0f)*0.75f; + //mTerrainVB[(y+x*size)*9+1]=ay; + tagBuffer[y+x*size] = 3; + tagBuffer[x+y*size] = 3; + smoothBorder = false; + } + else if(y < size*0.15f) + { + const float s = size*0.15f-(float)y; + mTerrainVB[(y+x*size)*9+1]=ay+s*0.25f; + smoothBorder = false; + } + else if(y > size*0.85f) + { + const float s = (float)y-size*0.85f; + mTerrainVB[(y+x*size)*9+1]=ay+s*0.7f; + smoothBorder = false; + } + else + { + mTerrainVB[(y+x*size)*9+1]=ay; + tagBuffer[y+x*size] = 1; + tagBuffer[x+y*size] = 1; + } + + } + if(smoothBorder) + { + mTerrainVB[((street0-1)+y*size)*9+1]=ay*0.5f+mTerrainVB[((street0-1)+y*size)*9+1]*0.5f; + mTerrainVB[(y+(street0-1)*size)*9+1]=ay*0.5f+mTerrainVB[(y+(street0-1)*size)*9+1]*0.5f; + mTerrainVB[((street0+1)+y*size)*9+1]=ay*0.5f+mTerrainVB[((street0+1)+y*size)*9+1]*0.5f; + mTerrainVB[(y+(street0+1)*size)*9+1]=ay*0.5f+mTerrainVB[(y+(street0+1)*size)*9+1]*0.5f; + } + } + + // Circle street + for(PxU32 y=0;y<size;y++) + { + for(PxU32 x=0;x<size;x++) + { + const float x0 = x-cx; + const float y0 = y-cy; + const float d = sqrtf(x0*x0+y0*y0); + if(d >= r && d < r+streetSize) + { + mTerrainVB[(y+x*size)*9+1]=ay; + + if(y > size*0.55f && y < size*0.75f) + tagBuffer[y+x*size] = 2; + else + tagBuffer[y+x*size] = 1; + + } + else if(d >= r+streetSize && d < r+streetSize+g) + { + const float a = (d-(r+streetSize))/g; + mTerrainVB[(y+x*size)*9+1]=ay*(1.0f-a) + mTerrainVB[(y+x*size)*9+1]*a; + } + else if(d >= r-g && d < r) + { + const float a = (d-(r-g))/g; + mTerrainVB[(y+x*size)*9+1]=ay*a+mTerrainVB[(y+x*size)*9+1]*(1.0f-a); + } + } + } + + // Borders + const float b = size/25.0f; + const float bd = size/2.0f-b; + for(PxU32 y=0;y<size;y++) + { + for(PxU32 x=0;x<size;x++) + { + const float x0 = fabsf(x-cx); + const float y0 = fabsf(y-cy); + if(x0 > bd || y0 > bd) + { + float a0 = (x0-bd)/b; + float a1 = (y0-bd)/b; + if(a1 > a0) + a0 = a1; + mTerrainVB[(y+x*size)*9+1]=20.0f*a0 + mTerrainVB[(y+x*size)*9+1]*(1-a0); + } + } + } + + // Sobel filter + for(PxU32 y=1;y<size-1;y++) + { + for(PxU32 x=1;x<size-1;x++) + { + // 1 0 -1 + // 2 0 -2 + // 1 0 -1 + float dx; + dx = mTerrainVB[((x-1)+(y-1)*size)*9+1]; + dx -= mTerrainVB[((x+1)+(y-1)*size)*9+1]; + dx += 2.0f*mTerrainVB[((x-1)+(y+0)*size)*9+1]; + dx -= 2.0f*mTerrainVB[((x+1)+(y+0)*size)*9+1]; + dx += mTerrainVB[((x-1)+(y+1)*size)*9+1]; + dx -= mTerrainVB[((x+1)+(y+1)*size)*9+1]; + + // 1 2 1 + // 0 0 0 + // -1 -2 -1 + float dy; + dy = mTerrainVB[((x-1)+(y-1)*size)*9+1]; + dy += 2.0f*mTerrainVB[((x+0)+(y-1)*size)*9+1]; + dy += mTerrainVB[((x+1)+(y-1)*size)*9+1]; + dy -= mTerrainVB[((x-1)+(y+1)*size)*9+1]; + dy -= 2.0f*mTerrainVB[((x+0)+(y+1)*size)*9+1]; + dy -= mTerrainVB[((x+1)+(y+1)*size)*9+1]; + + const float nx = dx/width*0.15f; + const float ny = 1.0f; + const float nz = dy/width*0.15f; + + const float len = sqrtf(nx*nx+ny*ny+nz*nz); + + mTerrainVB[(x+y*size)*9+3] = nx/len; + mTerrainVB[(x+y*size)*9+4] = ny/len; + mTerrainVB[(x+y*size)*9+5] = nz/len; + } + } + + // Static lighting (two directional lights) + const float l0[3] = {0.25f/0.8292f, 0.75f/0.8292f, 0.25f/0.8292f}; + const float l1[3] = {0.65f/0.963f, 0.55f/0.963f, 0.45f/0.963f}; + //const float len = sqrtf(l1[0]*l1[0]+l1[1]*l1[1]+l1[2]*l1[2]); + for(PxU32 y=0;y<size;y++) + { + for(PxU32 x=0;x<size;x++) + { + const float nx = mTerrainVB[(x+y*size)*9+3], ny = mTerrainVB[(x+y*size)*9+4], nz = mTerrainVB[(x+y*size)*9+5]; + + const float a = 0.3f; + float dot0 = l0[0]*nx + l0[1]*ny + l0[2]*nz; + float dot1 = l1[0]*nx + l1[1]*ny + l1[2]*nz; + if(dot0 < 0.0f) { dot0 = 0.0f; } + if(dot1 < 0.0f) { dot1 = 0.0f; } + + const float l = dot0*0.7f + dot1*0.3f; + + mTerrainVB[(x+y*size)*9+6] = mTerrainVB[(x+y*size)*9+6]*(l + a); + mTerrainVB[(x+y*size)*9+7] = mTerrainVB[(x+y*size)*9+7]*(l + a); + mTerrainVB[(x+y*size)*9+8] = mTerrainVB[(x+y*size)*9+8]*(l + a); + + /*mTerrainVB[(x+y*size)*9+3] = 0.0f; + mTerrainVB[(x+y*size)*9+4] = -1.0f; + mTerrainVB[(x+y*size)*9+5] = 0.0f;*/ + } + } + + // Index buffers + const PxU32 maxNbTerrainTriangles = (size-1)*(size-1)*2; + + mNbIB = 4; + mRenderMaterial[0] = MATERIAL_TERRAIN_MUD; + mRenderMaterial[1] = MATERIAL_ROAD_TARMAC; + mRenderMaterial[2] = MATERIAL_ROAD_SNOW; + mRenderMaterial[3] = MATERIAL_ROAD_GRASS; + + for(PxU32 i=0;i<mNbIB;i++) + { + mIB[i] = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*maxNbTerrainTriangles*3); + mNbTriangles[i] = 0; + } + + for(PxU32 j=0;j<size-1;j++) + { + for(PxU32 i=0;i<size-1;i++) + { + PxU32 tris[6]; + tris[0] = i + j*size; tris[1] = i + (j+1)*size; tris[2] = i+1 + (j+1)*size; + tris[3] = i + j*size; tris[4] = i+1 + (j+1)*size; tris[5] = i+1 + j*size; + + for(PxU32 t=0;t<2;t++) + { + const PxU32 vt0 = tagBuffer[tris[t*3+0]]; + const PxU32 vt1 = tagBuffer[tris[t*3+1]]; + const PxU32 vt2 = tagBuffer[tris[t*3+2]]; + + PxU32 buffer = 0; + if(vt0 == vt1 && vt0 == vt2) + buffer = vt0; + + mIB[buffer][mNbTriangles[buffer]*3+0] = tris[t*3+0]; + mIB[buffer][mNbTriangles[buffer]*3+1] = tris[t*3+1]; + mIB[buffer][mNbTriangles[buffer]*3+2] = tris[t*3+2]; + mNbTriangles[buffer]++; + } + } + } + + SAMPLE_FREE(tagBuffer); + SAMPLE_FREE(doneBuffer); +} + +void SampleVehicle::addMesh(PxRigidActor* actor, float* verts, PxU32 nVerts, PxU32* indices, PxU32 mIndices, PxU32 materialIndex, const char* filename) +{ + const char* filenameCooked = getSampleOutputFilePath(filename, ""); + PX_ASSERT(NULL != filenameCooked); + + bool ok = false; + if(!gRecook) + { + SampleFramework::File* fp = NULL; + PxToolkit::fopen_s(&fp, filenameCooked, "rb"); + if(fp) + { + fseek(fp, 0, SEEK_END); + PxU32 filesize = (PxU32)ftell(fp); + + fclose(fp); + + + ok = (filesize != 0); + } + } + + if(!ok) + { + PxTriangleMeshDesc meshDesc; + meshDesc.points.count = nVerts; + meshDesc.triangles.count = mIndices; + meshDesc.points.stride = sizeof(float)*3*3; + meshDesc.triangles.stride = sizeof(PxU32)*3; + meshDesc.points.data = verts; + meshDesc.triangles.data = indices; + meshDesc.flags = PxMeshFlags(0); + + // + shdfnd::printFormatted("Cooking object... %s", filenameCooked); + PxDefaultFileOutputStream stream(filenameCooked); + ok = getCooking().cookTriangleMesh(meshDesc, stream); + shdfnd::printFormatted(" - Done\n"); + } + + { + PxDefaultFileInputData stream(filenameCooked); + PxTriangleMesh* triangleMesh = getPhysics().createTriangleMesh(stream); + + if(triangleMesh) + { + PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(triangleMesh), *mStandardMaterials[materialIndex] /**mStandardMaterial*/); + } + } +} + +// PT: the renderer also expects 16bit indices so we still have to cut a big mesh to pieces +void SampleVehicle::addRenderMesh(float* verts, PxU32 nVerts, PxU32* indices, PxU32 mIndices, PxU32 matID) +{ + float minX=1000000.0f; + float minZ=1000000.0f; + float maxX=-1000000.0f; + float maxZ=-1000000.0f; + + // PT: the VB uses interleaved data so we need a temp buffer + PxVec3Alloc* v = SAMPLE_NEW(PxVec3Alloc)[nVerts]; + float* curVerts = verts; + PxBounds3 meshBound = PxBounds3::empty(); + for(PxU32 i=0;i<nVerts;i++) + { + v[i].x = curVerts[0]; + v[i].y = curVerts[1]; + v[i].z = curVerts[2]; + if (v[i].x < minX) { minX = v[i].x; } + if (v[i].z < minZ) { minZ = v[i].z; } + if (v[i].x > maxX) { maxX = v[i].x; } + if (v[i].z > maxZ) { maxZ = v[i].z; } + curVerts += 3*3; + + meshBound.include(v[i]); + } + + PxReal* uv = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*nVerts*2); + curVerts = verts; + const float scaleX = (maxX-minX)/64.0f; + const float scaleZ = (maxZ-minZ)/64.0f; + for(PxU32 i=0;i<nVerts;i++) + { + uv[i*2+0] = (curVerts[0]-minX)/scaleX; + uv[i*2+1] = (curVerts[2]-minZ)/scaleZ; + curVerts += 3*3; + } + + RAWMesh data; + data.mMaterialID = matID; + data.mNbVerts = nVerts; + data.mNbFaces = mIndices; + data.mVerts = v; + data.mUVs = uv; + data.mIndices = indices; + RenderMeshActor* renderActor = createRenderMeshFromRawMesh(data); + if( renderActor != NULL ) + { + renderActor->setWorldBounds(meshBound); + renderActor->setEnableCameraCull(true); + } + + SAMPLE_FREE(uv); + DELETEARRAY(v); +} + +void SampleVehicle::createTrack(PxU32 size, float width, float chaos) +{ + createTerrain(size, width, chaos); + createLandscapeMesh(); +} + +void SampleVehicle::createLandscapeMesh() +{ + RAWTexture data; + data.mName = "gravel_diffuse.dds"; + RenderTexture* gravelTexture = createRenderTextureFromRawTexture(data); + + mTerrainMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.5f, 0.25f, 0.125f), 1.0f, false, MATERIAL_TERRAIN_MUD, gravelTexture); + mRenderMaterials.push_back(mTerrainMaterial); + + data.mName = "asphalt_diffuse.dds"; + RenderTexture* asphaltTexture = createRenderTextureFromRawTexture(data); + + mRoadMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_ROAD_TARMAC, asphaltTexture); + mRenderMaterials.push_back(mRoadMaterial); + + data.mName = "ice_diffuse.dds"; + RenderTexture* snowTexture = createRenderTextureFromRawTexture(data); + + mRoadIceMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.05f, 0.05f, 0.75f), 1.0f, false, MATERIAL_ROAD_SNOW, snowTexture); + mRenderMaterials.push_back(mRoadIceMaterial); + + data.mName = "grass_diffuse.dds"; + RenderTexture* grassTexture = createRenderTextureFromRawTexture(data); + + mRoadGravelMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_ROAD_GRASS, grassTexture); + mRenderMaterials.push_back(mRoadGravelMaterial); + + PxTransform pose; + pose = PxTransform(PxIdentity); +// pose.p.y -= 10.0f; + mHFActor = getPhysics().createRigidStatic(pose); + + for(PxU32 i=0;i<mNbIB;i++) + { + if(mNbTriangles[i] > 0) + { + char filename[512]; + sprintf(filename, "SampleVehicleGroundMeshes_Part%d", i); + addMesh(mHFActor, mTerrainVB, mNbTerrainVerts, mIB[i], mNbTriangles[i], i, filename); + if (mNbTriangles[i] > (1<<16)) + { + PxU32 firstBatch = mNbTriangles[i]/2; + addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i], firstBatch, MATERIAL_TERRAIN_MUD); + addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i]+(firstBatch*3), mNbTriangles[i]-firstBatch, mRenderMaterial[i]); + } + else + { + addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i], mNbTriangles[i], mRenderMaterial[i]); + } + } + } + + PxSceneWriteLock scopedLock(*mScene); + mScene->addActor(*mHFActor); + + PxShape* shapeBuffer[MAX_NUM_INDEX_BUFFERS]; + mHFActor->getShapes(shapeBuffer, MAX_NUM_INDEX_BUFFERS); + PxFilterData simulationFilterData; + simulationFilterData.word0=COLLISION_FLAG_GROUND; + simulationFilterData.word1=COLLISION_FLAG_GROUND_AGAINST; + PxFilterData queryFilterData; + SampleVehicleSetupDrivableShapeQueryFilterData(&queryFilterData); + + for(PxU32 i=0;i<mNbIB;i++) + { + shapeBuffer[i]->setSimulationFilterData(simulationFilterData); + shapeBuffer[i]->setQueryFilterData(queryFilterData); + shapeBuffer[i]->setFlag(PxShapeFlag::eVISUALIZATION,false); + } +} diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.cpp new file mode 100644 index 00000000..2bd6691d --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.cpp @@ -0,0 +1,164 @@ +// 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_CameraController.h" +#include "PhysXSampleApplication.h" +#include "PxRigidDynamic.h" +#include "PxQueryFiltering.h" +#include "PxScene.h" +#include "PxSceneLock.h" +#include "vehicle/PxVehicleWheels.h" + +using namespace SampleRenderer; +using namespace SampleFramework; + +/////////////////////////////////////////////////////////////////////////////// + + + +SampleVehicle_CameraController::SampleVehicle_CameraController() +: mRotateInputY (0.0f), + mRotateInputZ (0.0f), + mMaxCameraRotateSpeed (5.0f), + mCameraRotateAngleY (0.0f), + mCameraRotateAngleZ (0.33f), + mCameraPos (PxVec3(0,0,0)), + mCameraTargetPos (PxVec3(0,0,0)), + mLastCarPos (PxVec3(0,0,0)), + mLastCarVelocity (PxVec3(0,0,0)), + mCameraInit (false), + mLockOnFocusVehTransform (true), + mLastFocusVehTransform (PxTransform(PxIdentity)) +{ +} + +SampleVehicle_CameraController::~SampleVehicle_CameraController() +{ +} + +static void dampVec3(const PxVec3& oldPosition, PxVec3& newPosition, PxF32 timestep) +{ + PxF32 t = 0.7f * timestep * 8.0f; + t = PxMin(t, 1.0f); + newPosition = oldPosition * (1 - t) + newPosition * t; +} + +void SampleVehicle_CameraController::update(const PxReal dtime, const PxRigidDynamic* actor, PxScene& scene) +{ + PxSceneReadLock scopedLock(scene); + PxTransform carChassisTransfm; + if(mLockOnFocusVehTransform) + { + carChassisTransfm = actor->getGlobalPose(); + mLastFocusVehTransform = carChassisTransfm; + } + else + { + carChassisTransfm = mLastFocusVehTransform; + } + + PxF32 camDist = 15.0f; + PxF32 cameraYRotExtra = 0.0f; + + PxVec3 velocity = mLastCarPos-carChassisTransfm.p; + + if (mCameraInit) + { + //Work out the forward and sideways directions. + PxVec3 unitZ(0,0,1); + PxVec3 carDirection = carChassisTransfm.q.rotate(unitZ); + PxVec3 unitX(1,0,0); + PxVec3 carSideDirection = carChassisTransfm.q.rotate(unitX); + + //Acceleration (note that is not scaled by time). + PxVec3 acclVec = mLastCarVelocity-velocity; + + //Higher forward accelerations allow the car to speed away from the camera. + PxF32 acclZ = carDirection.dot(acclVec); + camDist = PxMax(camDist+acclZ*400.0f, 5.0f); + + //Higher sideways accelerations allow the car's rotation to speed away from the camera's rotation. + PxF32 acclX = carSideDirection.dot(acclVec); + cameraYRotExtra = -acclX*10.0f; + //At very small sideways speeds the camera greatly amplifies any numeric error in the body and leads to a slight jitter. + //Scale cameraYRotExtra by a value in range (0,1) for side speeds in range (0.1,1.0) and by zero for side speeds less than 0.1. + PxFixedSizeLookupTable<4> table; + table.addPair(0.0f, 0.0f); + table.addPair(0.1f*dtime, 0); + table.addPair(1.0f*dtime, 1); + PxF32 velX = carSideDirection.dot(velocity); + cameraYRotExtra *= table.getYVal(PxAbs(velX)); + } + + mCameraRotateAngleY+=mRotateInputY*mMaxCameraRotateSpeed*dtime; + mCameraRotateAngleY=physx::intrinsics::fsel(mCameraRotateAngleY-10*PxPi, mCameraRotateAngleY-10*PxPi, physx::intrinsics::fsel(-mCameraRotateAngleY-10*PxPi, mCameraRotateAngleY + 10*PxPi, mCameraRotateAngleY)); + mCameraRotateAngleZ+=mRotateInputZ*mMaxCameraRotateSpeed*dtime; + mCameraRotateAngleZ=PxClamp(mCameraRotateAngleZ,-PxPi*0.05f,PxPi*0.45f); + + PxVec3 cameraDir=PxVec3(0,0,1)*PxCos(mCameraRotateAngleY+cameraYRotExtra) + PxVec3(1,0,0)*PxSin(mCameraRotateAngleY+cameraYRotExtra); + + cameraDir=cameraDir*PxCos(mCameraRotateAngleZ)-PxVec3(0,1,0)*PxSin(mCameraRotateAngleZ); + + const PxVec3 direction = carChassisTransfm.q.rotate(cameraDir); + PxVec3 target = carChassisTransfm.p; + target.y+=0.5f; + + PxRaycastBuffer hit; + PxQueryFilterData filterData(PxQueryFlag::eSTATIC); + scene.raycast(target, -direction, camDist, hit, PxHitFlag::eDISTANCE, filterData); + if (hit.hasBlock && hit.block.shape != NULL) + { + camDist = hit.block.distance-0.25f; + } + + camDist = PxMax(5.0f, PxMin(camDist, 50.0f)); + + PxVec3 position = target-direction*camDist; + + if (mCameraInit) + { + dampVec3(mCameraPos, position, dtime); + dampVec3(mCameraTargetPos, target, dtime); + } + + mCameraPos = position; + mCameraTargetPos = target; + mCameraInit = true; + + mLastCarVelocity = velocity; + mLastCarPos = carChassisTransfm.p; +} + +void SampleVehicle_CameraController::update(const PxReal dtime, const PxVehicleWheels& focusVehicle, PxScene& scene) +{ + const PxRigidDynamic* actor=focusVehicle.getRigidDynamicActor(); + update(dtime,actor,scene); +} + + diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.h new file mode 100644 index 00000000..fb00d0e7 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.h @@ -0,0 +1,92 @@ +// 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. + + +#ifndef SAMPLE_VEHICLE_CAMERA_CONTROLLER_H +#define SAMPLE_VEHICLE_CAMERA_CONTROLLER_H + +#include "common/PxPhysXCommonConfig.h" +#include "foundation/PxVec3.h" +#include "foundation/PxTransform.h" + +using namespace physx; + +namespace physx +{ + class PxScene; + class PxVehicleWheels; + class PxRigidDynamic; +} + +class Camera; + +class SampleVehicle_CameraController +{ +public: + + SampleVehicle_CameraController(); + ~SampleVehicle_CameraController(); + + void setInputs(const PxF32 rotateInputY, const PxF32 rotateInputZ) + { + mRotateInputY=rotateInputY; + mRotateInputZ=rotateInputZ; + } + + void update(const PxF32 dtime, const PxVehicleWheels& focusVehicle, PxScene& scene); + + void restart() {} + + bool getIsLockedOnVehicleTransform() const {return mLockOnFocusVehTransform;} + void toggleLockOnVehTransform() {mLockOnFocusVehTransform = !mLockOnFocusVehTransform;} + + const PxVec3& getCameraPos() const {return mCameraPos;} + const PxVec3& getCameraTar() const {return mCameraTargetPos;} + +private: + + PxF32 mRotateInputY; + PxF32 mRotateInputZ; + + PxF32 mMaxCameraRotateSpeed; + PxF32 mCameraRotateAngleY; + PxF32 mCameraRotateAngleZ; + PxVec3 mCameraPos; + PxVec3 mCameraTargetPos; + PxVec3 mLastCarPos; + PxVec3 mLastCarVelocity; + bool mCameraInit; + + bool mLockOnFocusVehTransform; + PxTransform mLastFocusVehTransform; + + void update(const PxReal dtime, const PxRigidDynamic* actor, PxScene& scene); +}; + +#endif //SAMPLE_VEHICLE_CAMERA_CONTROLLER_H
\ No newline at end of file diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.cpp new file mode 100644 index 00000000..648db019 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.cpp @@ -0,0 +1,68 @@ +// 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_ControlInputs.h" +#include "PhysXSampleApplication.h" + +using namespace SampleRenderer; +using namespace SampleFramework; + +/////////////////////////////////////////////////////////////////////////////// + +SampleVehicle_ControlInputs::SampleVehicle_ControlInputs() +: mCameraRotateInputY (0.0f), + mCameraRotateInputZ (0.0f), + mAccelKeyPressed (false), + mGearUpKeyPressed (false), + mGearDownKeyPressed (false), + mBrakeKeyPressed (false), + mHandbrakeKeyPressed (false), + mSteerLeftKeyPressed (false), + mSteerRightKeyPressed (false), + mBrakeLeftKeyPressed (false), + mBrakeRightKeyPressed (false), + mThrustLeftKeyPressed (false), + mThrustRightKeyPressed (false), + mAccel (0.0f), + mGearup (false), + mGeardown (false), + mBrake (0.0f), + mSteer (0.0f), + mHandbrake (false), + mThrustLeft (0.0f), + mThrustRight (0.0f), + mBrakeLeft (0.0f), + mBrakeRight (0.0f) +{ +} + +SampleVehicle_ControlInputs::~SampleVehicle_ControlInputs() +{ +} + diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.h new file mode 100644 index 00000000..3327cc8b --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.h @@ -0,0 +1,145 @@ +// 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. + + +#ifndef SAMPLE_VEHICLE_CONTROL_INPUTS_H +#define SAMPLE_VEHICLE_CONTROL_INPUTS_H + +#include "common/PxPhysXCommonConfig.h" + +using namespace physx; + +class SampleVehicle_ControlInputs +{ +public: + + SampleVehicle_ControlInputs(); + ~SampleVehicle_ControlInputs(); + + //Camera inputs + void setRotateY(const PxF32 f) {mCameraRotateInputY=f;} + void setRotateZ(const PxF32 f) {mCameraRotateInputZ=f;} + PxF32 getRotateY() const {return mCameraRotateInputY;} + PxF32 getRotateZ() const {return mCameraRotateInputZ;} + + //Keyboard driving inputs - (car + tank) + void setAccelKeyPressed(const bool b) {mAccelKeyPressed=b;} + void setGearUpKeyPressed(const bool b) {mGearUpKeyPressed=b;} + void setGearDownKeyPressed(const bool b) {mGearDownKeyPressed=b;} + bool getAccelKeyPressed() const {return mAccelKeyPressed;} + bool getGearUpKeyPressed() const {return mGearUpKeyPressed;} + bool getGearDownKeyPressed() const {return mGearDownKeyPressed;} + + //Keyboard driving inputs - (car only) + void setBrakeKeyPressed(const bool b) {mBrakeKeyPressed=b;} + void setHandbrakeKeyPressed(const bool b) {mHandbrakeKeyPressed=b;} + void setSteerLeftKeyPressed(const bool b) {mSteerLeftKeyPressed=b;} + void setSteerRightKeyPressed(const bool b) {mSteerRightKeyPressed=b;} + bool getBrakeKeyPressed() const {return mBrakeKeyPressed;} + bool getHandbrakeKeyPressed() const {return mHandbrakeKeyPressed;} + bool getSteerLeftKeyPressed() const {return mSteerLeftKeyPressed;} + bool getSteerRightKeyPressed() const {return mSteerRightKeyPressed;} + + //Keyboard driving inputs - (tank only) + void setBrakeLeftKeyPressed(const bool b) {mBrakeLeftKeyPressed=b;} + void setBrakeRightKeyPressed(const bool b) {mBrakeRightKeyPressed=b;} + void setThrustLeftKeyPressed(const bool b) {mThrustLeftKeyPressed=b;} + void setThrustRightKeyPressed(const bool b) {mThrustRightKeyPressed=b;} + bool getBrakeLeftKeyPressed() const {return mBrakeLeftKeyPressed;} + bool getBrakeRightKeyPressed() const {return mBrakeRightKeyPressed;} + bool getThrustLeftKeyPressed() const {return mThrustLeftKeyPressed;} + bool getThrustRightKeyPressed() const {return mThrustRightKeyPressed;} + + //Gamepad driving inputs (car + tank) + void setAccel(const PxF32 f) {mAccel=f;} + void setGearUp(const bool b) {mGearup=b;} + void setGearDown(const bool b) {mGeardown=b;} + PxF32 getAccel() const {return mAccel;} + bool getGearUp() const {return mGearup;} + bool getGearDown() const {return mGeardown;} + + //Gamepad driving inputs (car only) + void setBrake(const PxF32 f) {mBrake=f;} + void setSteer(const PxF32 f) {mSteer=f;} + void setHandbrake(const bool b) {mHandbrake=b;} + PxF32 getBrake() const {return mBrake;} + PxF32 getSteer() const {return mSteer;} + bool getHandbrake() const {return mHandbrake;} + + //Gamepad driving inputs (tank only) + void setThrustLeft(const PxF32 f) {mThrustLeft=f;} + void setThrustRight(const PxF32 f) {mThrustRight=f;} + PxF32 getThrustLeft() const {return mThrustLeft;} + PxF32 getThrustRight() const {return mThrustRight;} + void setBrakeLeft(const PxF32 f) {mBrakeLeft=f;} + void setBrakeRight(const PxF32 f) {mBrakeRight=f;} + PxF32 getBrakeLeft() const {return mBrakeLeft;} + PxF32 getBrakeRight() const {return mBrakeRight;} + +private: + + //Camera inputs. + PxF32 mCameraRotateInputY; + PxF32 mCameraRotateInputZ; + + //keyboard inputs (car and tank) + bool mAccelKeyPressed; + bool mGearUpKeyPressed; + bool mGearDownKeyPressed; + + //keyboard inputs (car only) + bool mBrakeKeyPressed; + bool mHandbrakeKeyPressed; + bool mSteerLeftKeyPressed; + bool mSteerRightKeyPressed; + + //keyboard inputs (tank only) + bool mBrakeLeftKeyPressed; + bool mBrakeRightKeyPressed; + bool mThrustLeftKeyPressed; + bool mThrustRightKeyPressed; + + //gamepad inputs (car and tank) + PxF32 mAccel; + bool mGearup; + bool mGeardown; + + //gamepad inputs (car only) + PxF32 mBrake; + PxF32 mSteer; + bool mHandbrake; + + //gamepad inputs (tank only) + PxF32 mThrustLeft; + PxF32 mThrustRight; + PxF32 mBrakeLeft; + PxF32 mBrakeRight; +}; + +#endif //SAMPLE_VEHICLE_CONTROL_INPUTS_H
\ No newline at end of file diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.cpp new file mode 100644 index 00000000..60864b4e --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.cpp @@ -0,0 +1,91 @@ +// 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_GameLogic.h" + +void SampleVehicleWayPoints::getNextWayPointsAndLineDirs(PxU32& numPoints, PxVec3& v0, PxVec3& v1, PxVec3& v2, PxVec3& w0, PxVec3& w1, PxVec3& w2) const +{ + numPoints=0; + if((mProgress+1) < mNumWayPoints) + { + v0=mWayPoints[mProgress+1].p; + w0=mWayPoints[mProgress+1].q.getBasisVector0(); + numPoints++; + + if((mProgress+2) < mNumWayPoints) + { + v1=mWayPoints[mProgress+2].p; + w1=mWayPoints[mProgress+2].q.getBasisVector0(); + numPoints++; + + if((mProgress+3) < mNumWayPoints) + { + v2=mWayPoints[mProgress+3].p; + w2=mWayPoints[mProgress+3].q.getBasisVector0(); + numPoints++; + } + } + } +} + +#define LINEWIDTH 8 +#define LINEDISTANCE2 3*3 +void SampleVehicleWayPoints::update(const PxTransform& playerTransform, const PxF32 timestep) +{ + //Increment the elapsed time + mTimeElapsed+=timestep; + + //Work out the point on the crossing line of the next way-point that is closest to the player. + const PxTransform& nextWayPoint=mWayPoints[mProgress+1]; + const PxVec3 v=nextWayPoint.p; + const PxVec3 w=nextWayPoint.q.getBasisVector0(); + const PxVec3 p=playerTransform.p; + const PxVec3 pv=p-v; + const PxF32 t=pv.dot(w); + + //Test if the player's position is inside the width of the line crossing the next way-point. + if(PxAbs(t) < LINEWIDTH) + { + //Now test if the shortest distance to the next crossing line is smaller than a threshold. + const PxVec3 linePos=v+w*t; + const PxVec3 diff=p-linePos; + const PxF32 dist2=diff.magnitudeSquared(); + if(dist2<LINEDISTANCE2) + { + mProgress++; + } + } + + if(mProgress == mNumWayPoints-1) + { + mMinTimeElapsed=PxMin(mTimeElapsed, mMinTimeElapsed); + mTimeElapsed=0; + mProgress=0; + } +} diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.h new file mode 100644 index 00000000..c7870ce5 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.h @@ -0,0 +1,97 @@ +// 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. + + +#ifndef SAMPLE_VEHICLE_GAME_LOGIC_H +#define SAMPLE_VEHICLE_GAME_LOGIC_H + +#include "common/PxPhysXCommonConfig.h" +#include "foundation/PxTransform.h" + +using namespace physx; + +class SampleVehicleWayPoints +{ +public: + + SampleVehicleWayPoints() + : mWayPoints(NULL), + mNumWayPoints(0), + mProgress(0), + mTimeElapsed(0), + mMinTimeElapsed(100000) + { + } + + ~SampleVehicleWayPoints() + { + } + + //Setup. + void setWayPoints(const PxTransform* wayPoints, const PxU32 numWayPoints) + { + mWayPoints=wayPoints; + mNumWayPoints=numWayPoints; + } + + //Update. + void update(const PxTransform& playerTransform, const PxF32 timestep); + + //Imagine we are starting the lap again. + PxTransform setBackAtStart() + { + mTimeElapsed=0; + mProgress=0; + return mWayPoints[0]; + } + + //Get the next three points and the crossing line of each way-point. + void getNextWayPointsAndLineDirs(PxU32& numPoints, PxVec3& v0, PxVec3& v1, PxVec3& v2, PxVec3& w0, PxVec3& w1, PxVec3& w2) const; + + //Get lap time and best lap time. + PxF32 getTimeElapsed() const {return mTimeElapsed;} + PxF32 getMinTimeElapsed() const {return mMinTimeElapsed;} + + //Get the transform to reset the car at the last passed way-point. + PxTransform getResetTransform() const {return mWayPoints[mProgress];} + +private: + + //Array of way points. + const PxTransform* mWayPoints; + PxU32 mNumWayPoints; + + //Progress and time elapsed. + PxU32 mProgress; + PxF32 mTimeElapsed; + PxF32 mMinTimeElapsed; +}; + + +#endif //SAMPLE_VEHICLE_GAME_LOGIC_H
\ No newline at end of file diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.cpp new file mode 100644 index 00000000..bd3a6896 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.cpp @@ -0,0 +1,90 @@ +// 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_SceneQuery.h" +#include "vehicle/PxVehicleSDK.h" +#include "PxFiltering.h" +#include "PsFoundation.h" +#include "PsUtilities.h" + +#define CHECK_MSG(exp, msg) (!!(exp) || (physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, msg), 0) ) +#define SIZEALIGN16(size) (((unsigned)(size)+15)&((unsigned)(~15))); + +void SampleVehicleSetupDrivableShapeQueryFilterData(PxFilterData* qryFilterData) +{ + CHECK_MSG(0==qryFilterData->word3, "word3 is reserved for filter data for vehicle raycast queries"); + qryFilterData->word3 = (PxU32)SAMPLEVEHICLE_DRIVABLE_SURFACE; +} + +void SampleVehicleSetupNonDrivableShapeQueryFilterData(PxFilterData* qryFilterData) +{ + CHECK_MSG(0==qryFilterData->word3, "word3 is reserved for filter data for vehicle raycast queries"); + qryFilterData->word3 = (PxU32)SAMPLEVEHICLE_UNDRIVABLE_SURFACE; +} + +void SampleVehicleSetupVehicleShapeQueryFilterData(PxFilterData* qryFilterData) +{ + CHECK_MSG(0==qryFilterData->word3, "word3 is reserved for filter data for vehicle raycast queries"); + qryFilterData->word3 = (PxU32)SAMPLEVEHICLE_UNDRIVABLE_SURFACE; +} + +SampleVehicleSceneQueryData* SampleVehicleSceneQueryData::allocate(const PxU32 maxNumWheels) +{ + const PxU32 size0 = SIZEALIGN16(sizeof(SampleVehicleSceneQueryData)); + const PxU32 size1 = SIZEALIGN16(sizeof(PxRaycastQueryResult)*maxNumWheels); + const PxU32 size2 = SIZEALIGN16(sizeof(PxRaycastHit)*maxNumWheels); + const PxU32 size = size0 + size1 + size2; + SampleVehicleSceneQueryData* sqData = (SampleVehicleSceneQueryData*)PX_ALLOC(size, "PxVehicleNWSceneQueryData"); + sqData->init(); + PxU8* ptr = (PxU8*) sqData; + ptr += size0; + sqData->mSqResults = (PxRaycastQueryResult*)ptr; + sqData->mNbSqResults = maxNumWheels; + ptr += size1; + sqData->mSqHitBuffer = (PxRaycastHit*)ptr; + ptr += size2; + sqData->mNumQueries = maxNumWheels; + return sqData; +} + +void SampleVehicleSceneQueryData::free() +{ + PX_FREE(this); +} + +PxBatchQuery* SampleVehicleSceneQueryData::setUpBatchedSceneQuery(PxScene* scene) +{ + PxBatchQueryDesc sqDesc(mNbSqResults, 0, 0); + sqDesc.queryMemory.userRaycastResultBuffer = mSqResults; + sqDesc.queryMemory.userRaycastTouchBuffer = mSqHitBuffer; + sqDesc.queryMemory.raycastTouchBufferSize = mNumQueries; + sqDesc.preFilterShader = mPreFilterShader; + return scene->createBatchQuery(sqDesc); +} + diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.h new file mode 100644 index 00000000..a13f3c41 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.h @@ -0,0 +1,132 @@ +// 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. + +#ifndef SAMPLEVEHICLE_UTILSCENEQUERY_H +#define SAMPLEVEHICLE_UTILSCENEQUERY_H + +#include "common/PxPhysXCommonConfig.h" +#include "vehicle/PxVehicleSDK.h" +#include "foundation/PxPreprocessor.h" +#include "PxScene.h" +#include "PxBatchQueryDesc.h" + +using namespace physx; + +//Make sure that suspension raycasts only consider shapes flagged as drivable that don't belong to the owner vehicle. +enum +{ + SAMPLEVEHICLE_DRIVABLE_SURFACE = 0xffff0000, + SAMPLEVEHICLE_UNDRIVABLE_SURFACE = 0x0000ffff +}; + +static PxQueryHitType::Enum SampleVehicleWheelRaycastPreFilter( + PxFilterData filterData0, + PxFilterData filterData1, + const void* constantBlock, PxU32 constantBlockSize, + PxHitFlags& queryFlags) +{ + //filterData0 is the vehicle suspension raycast. + //filterData1 is the shape potentially hit by the raycast. + PX_UNUSED(queryFlags); + PX_UNUSED(constantBlockSize); + PX_UNUSED(constantBlock); + PX_UNUSED(filterData0); + return ((0 == (filterData1.word3 & SAMPLEVEHICLE_DRIVABLE_SURFACE)) ? PxQueryHitType::eNONE : PxQueryHitType::eBLOCK); +} + + +//Set up query filter data so that vehicles can drive on shapes with this filter data. +//Note that we have reserved word3 of the PxFilterData for vehicle raycast query filtering. +void SampleVehicleSetupDrivableShapeQueryFilterData(PxFilterData* qryFilterData); + +//Set up query filter data so that vehicles cannot drive on shapes with this filter data. +//Note that we have reserved word3 of the PxFilterData for vehicle raycast query filtering. +void SampleVehicleSetupNonDrivableShapeQueryFilterData(PxFilterData* qryFilterData); + +//Set up query filter data for the shapes of a vehicle to ensure that vehicles cannot drive on themselves +//but can drive on the shapes of other vehicles. +//Note that we have reserved word3 of the PxFilterData for vehicle raycast query filtering. +void SampleVehicleSetupVehicleShapeQueryFilterData(PxFilterData* qryFilterData); + +//Data structure for quick setup of scene queries for suspension raycasts. +class SampleVehicleSceneQueryData +{ +public: + + //Allocate scene query data for up to maxNumWheels suspension raycasts. + static SampleVehicleSceneQueryData* allocate(const PxU32 maxNumWheels); + + //Free allocated buffer for scene queries of suspension raycasts. + void free(); + + //Create a PxBatchQuery instance that will be used as a single batched raycast of multiple suspension lines of multiple vehicles + PxBatchQuery* setUpBatchedSceneQuery(PxScene* scene); + + //Get the buffer of scene query results that will be used by PxVehicleNWSuspensionRaycasts + PxRaycastQueryResult* getRaycastQueryResultBuffer() {return mSqResults;} + + //Get the number of scene query results that have been allocated for use by PxVehicleNWSuspensionRaycasts + PxU32 getRaycastQueryResultBufferSize() const {return mNumQueries;} + + //Set the pre-filter shader + void setPreFilterShader(PxBatchQueryPreFilterShader preFilterShader) {mPreFilterShader=preFilterShader;} + +private: + + //One result for each wheel. + PxRaycastQueryResult* mSqResults; + PxU32 mNbSqResults; + + //One hit for each wheel. + PxRaycastHit* mSqHitBuffer; + + //Filter shader used to filter drivable and non-drivable surfaces + PxBatchQueryPreFilterShader mPreFilterShader; + + //Maximum number of suspension raycasts that can be supported by the allocated buffers + //assuming a single query and hit per suspension line. + PxU32 mNumQueries; + + void init() + { + mPreFilterShader=SampleVehicleWheelRaycastPreFilter; + } + + SampleVehicleSceneQueryData() + { + init(); + } + + ~SampleVehicleSceneQueryData() + { + } +}; + + +#endif //SAMPLEVEHICLE_UTILSCENEQUERY_H diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.cpp new file mode 100644 index 00000000..469b824c --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.cpp @@ -0,0 +1,840 @@ +// 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_VehicleController.h" +#include "PhysXSample.h" +#include "vehicle/PxVehicleDrive4W.h" +#include "vehicle/PxVehicleDriveNW.h" +#include "vehicle/PxVehicleUtilControl.h" +#include "vehicle/PxVehicleUtil.h" + +using namespace SampleRenderer; +using namespace SampleFramework; + +PxVehicleKeySmoothingData gKeySmoothingData= +{ + { + 3.0f, //rise rate eANALOG_INPUT_ACCEL + 3.0f, //rise rate eANALOG_INPUT_BRAKE + 10.0f, //rise rate eANALOG_INPUT_HANDBRAKE + 2.5f, //rise rate eANALOG_INPUT_STEER_LEFT + 2.5f, //rise rate eANALOG_INPUT_STEER_RIGHT + }, + { + 5.0f, //fall rate eANALOG_INPUT__ACCEL + 5.0f, //fall rate eANALOG_INPUT__BRAKE + 10.0f, //fall rate eANALOG_INPUT__HANDBRAKE + 5.0f, //fall rate eANALOG_INPUT_STEER_LEFT + 5.0f //fall rate eANALOG_INPUT_STEER_RIGHT + } +}; + +PxVehiclePadSmoothingData gCarPadSmoothingData= +{ + { + 6.0f, //rise rate eANALOG_INPUT_ACCEL + 6.0f, //rise rate eANALOG_INPUT_BRAKE + 12.0f, //rise rate eANALOG_INPUT_HANDBRAKE + 2.5f, //rise rate eANALOG_INPUT_STEER_LEFT + 2.5f, //rise rate eANALOG_INPUT_STEER_RIGHT + }, + { + 10.0f, //fall rate eANALOG_INPUT_ACCEL + 10.0f, //fall rate eANALOG_INPUT_BRAKE + 12.0f, //fall rate eANALOG_INPUT_HANDBRAKE + 5.0f, //fall rate eANALOG_INPUT_STEER_LEFT + 5.0f //fall rate eANALOG_INPUT_STEER_RIGHT + } +}; + +PxF32 gSteerVsForwardSpeedData[2*8]= +{ + 0.0f, 0.75f, + 5.0f, 0.75f, + 30.0f, 0.125f, + 120.0f, 0.1f, + PX_MAX_F32, PX_MAX_F32, + PX_MAX_F32, PX_MAX_F32, + PX_MAX_F32, PX_MAX_F32, + PX_MAX_F32, PX_MAX_F32 +}; +PxFixedSizeLookupTable<8> gSteerVsForwardSpeedTable(gSteerVsForwardSpeedData,4); + +//Tank smoothing data. +PxVehiclePadSmoothingData gTankPadSmoothingData= +{ + { + 6.0f, //rise rate eTANK_ANALOG_INPUT_ACCEL + 6.0f, //rise rate eTANK_ANALOG_INPUT_BRAKE_LEFT + 6.0f, //rise rate eTANK_ANALOG_INPUT_BRAKE_RIGHT + 2.5f, //rise rate eTANK_ANALOG_INPUT_THRUST_LEFT + 2.5f, //rise rate eTANK_ANALOG_INPUT_THRUST_RIGHT + }, + { + 10.0f, //fall rate eTANK_ANALOG_INPUT_ACCEL + 10.0f, //fall rate eTANK_ANALOG_INPUT_BRAKE_LEFT + 10.0f, //fall rate eTANK_ANALOG_INPUT_BRAKE_RIGHT + 5.0f, //fall rate eTANK_ANALOG_INPUT_THRUST_LEFT + 5.0f //fall rate eTANK_ANALOG_INPUT_THRUST_RIGHT + } +}; + + +/////////////////////////////////////////////////////////////////////////////// + +SampleVehicle_VehicleController::SampleVehicle_VehicleController() +{ + clear(); +} + +SampleVehicle_VehicleController::~SampleVehicle_VehicleController() +{ +} + +void SampleVehicle_VehicleController::clear() +{ + mKeyPressedAccel = false; + mKeyPressedGearUp = false; + mKeyPressedGearDown = false; + + mKeyPressedBrake = false; + mKeyPressedHandbrake = false; + mKeyPressedSteerLeft = false; + mKeyPressedSteerRight = false; + + mKeyPressedThrustLeft = false; + mKeyPressedThrustRight = false; + mKeyPressedBrakeLeft = false; + mKeyPressedBrakeRight = false; + + mGamepadAccel = 0.0f; + mGamepadGearup = false; + mGamepadGeardown = false; + + mGamepadCarBrake = 0.0f; + mGamepadCarSteer = 0.0f; + mGamepadCarHandbrake = false; + + mTankThrustLeft = 0.0f; + mTankThrustRight = 0.0f; + mTankBrakeLeft = 0.0f; + mTankBrakeRight = 0.0f; + + mRecord = false; + mReplay = false; + mNumSamples = 0; + mNumRecordedSamples = 0; + mUseKeyInputs = true; + mToggleAutoGears = false; + mIsMovingForwardSlowly = true; + mInReverseMode = false; +} + + +/* +bool SampleVehicle_VehicleController::processAutoReverse +(const PxF32 timestep, const bool isInAir, const PxF32 forwardSpeed, const PxF32 sidewaysSpeed, const PxVehicleDriveTankRawInputData& rawInputData) +{ + //Keyboard controls for tank not implemented yet. + bool brakeLeft,brakeRight,accelLeft,accelRight; + if(mUseKeyInputs) + { + //Keyboard controls for tank not implemented yet. + brakeLeft=false; + brakeRight=false; + accelLeft=false; + accelRight=false; + } + else if(PxVehicleDriveTank::eDRIVE_MODEL_STANDARD==rawInputData.getDriveModel()) + { + brakeLeft = mInReverseMode ? rawInputData.getAnalogLeftThrust() > 0 : rawInputData.getAnalogLeftBrake() > 0.0f; + brakeRight = mInReverseMode ? rawInputData.getAnalogRightThrust() > 0 : rawInputData.getAnalogRightBrake() > 0.0f; + accelLeft = mInReverseMode ? rawInputData.getAnalogLeftBrake() > 0 : rawInputData.getAnalogLeftThrust() > 0.0f; + accelRight = mInReverseMode ? rawInputData.getAnalogRightBrake() > 0 : rawInputData.getAnalogRightThrust() > 0.0f; + } + else + { + //Not much point in auto-reverse for tanks that can just spin both wheels backwards. + return false; + } + + //If the car has been brought to rest by pressing the brake then raise a flag. + bool justRaisedFlag=false; + if(brakeLeft && brakeRight && !mAtRestUnderBraking) + { + if(!isInAir && forwardSpeed < THRESHOLD_FORWARD_SPEED && sidewaysSpeed < THRESHOLD_SIDEWAYS_SPEED) + { + justRaisedFlag=true; + mAtRestUnderBraking = true; + mTimeElapsedSinceAtRestUnderBraking = 0.0f; + } + } + + //If the flag is raised and the player pressed accelerate then lower the flag. + if(mAtRestUnderBraking && (accelLeft || accelRight)) + { + mAtRestUnderBraking = false; + mTimeElapsedSinceAtRestUnderBraking = 0.0f; + } + + //If the flag is raised and the player doesn't press brake then increment the timer. + if(!brakeLeft && !brakeRight && mAtRestUnderBraking && !justRaisedFlag) + { + mTimeElapsedSinceAtRestUnderBraking += timestep; + } + + //If the flag is raised and the player pressed brake again then switch auto-reverse. + if(brakeLeft && brakeRight && mAtRestUnderBraking && !justRaisedFlag && mTimeElapsedSinceAtRestUnderBraking > 0.0f) + { + mAtRestUnderBraking = false; + mTimeElapsedSinceAtRestUnderBraking = 0.0f; + return true; + } + + return false; +} +*/ + +void SampleVehicle_VehicleController::processRawInputs +(const PxF32 dtime, const bool useAutoGears, PxVehicleDrive4WRawInputData& rawInputData) +{ + // Keyboard + { + if(mRecord) + { + if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES) + { + mKeyboardAccelValues[mNumSamples] = mKeyPressedAccel; + mKeyboardBrakeValues[mNumSamples] = mKeyPressedBrake; + mKeyboardHandbrakeValues[mNumSamples] = mKeyPressedHandbrake; + mKeyboardSteerLeftValues[mNumSamples] = mKeyPressedSteerLeft; + mKeyboardSteerRightValues[mNumSamples] = mKeyPressedSteerRight; + mKeyboardGearupValues[mNumSamples] = mKeyPressedGearUp; + mKeyboardGeardownValues[mNumSamples] = mKeyPressedGearDown; + } + } + else if(mReplay) + { + if(mNumSamples<mNumRecordedSamples) + { + mKeyPressedAccel = mKeyboardAccelValues[mNumSamples]; + mKeyPressedBrake = mKeyboardBrakeValues[mNumSamples]; + mKeyPressedHandbrake = mKeyboardHandbrakeValues[mNumSamples]; + mKeyPressedSteerLeft = mKeyboardSteerLeftValues[mNumSamples]; + mKeyPressedSteerRight = mKeyboardSteerRightValues[mNumSamples]; + mKeyPressedGearUp = mKeyboardGearupValues[mNumSamples]; + mKeyPressedGearDown = mKeyboardGeardownValues[mNumSamples]; + } + } + + rawInputData.setDigitalAccel(mKeyPressedAccel); + rawInputData.setDigitalBrake(mKeyPressedBrake); + rawInputData.setDigitalHandbrake(mKeyPressedHandbrake); + rawInputData.setDigitalSteerLeft(mKeyPressedSteerLeft); + rawInputData.setDigitalSteerRight(mKeyPressedSteerRight); + rawInputData.setGearUp(mKeyPressedGearUp); + rawInputData.setGearDown(mKeyPressedGearDown); + + mUseKeyInputs= + (mKeyPressedAccel || mKeyPressedBrake || mKeyPressedHandbrake || + mKeyPressedSteerLeft || mKeyPressedSteerRight || + mKeyPressedGearUp || mKeyPressedGearDown); + } + + // Gamepad + { + if(mRecord) + { + if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES) + { + mGamepadAccelValues[mNumSamples] = mGamepadAccel; + mGamepadCarBrakeValues[mNumSamples] = mGamepadCarBrake; + mGamepadCarSteerValues[mNumSamples] = mGamepadCarSteer; + mGamepadGearupValues[mNumSamples] = mGamepadGearup; + mGamepadGeardownValues[mNumSamples] = mGamepadGeardown; + mGamepadCarHandbrakeValues[mNumSamples] = mGamepadCarHandbrake; + } + } + else if(mReplay) + { + if(mNumSamples<mNumRecordedSamples) + { + mGamepadAccel = mGamepadAccelValues[mNumSamples]; + mGamepadCarBrake = mGamepadCarBrakeValues[mNumSamples]; + mGamepadCarSteer = mGamepadCarSteerValues[mNumSamples]; + mGamepadGearup = mGamepadGearupValues[mNumSamples]; + mGamepadGeardown = mGamepadGeardownValues[mNumSamples]; + mGamepadCarHandbrake = mGamepadCarHandbrakeValues[mNumSamples]; + } + } + + if(mGamepadAccel<0.0f || mGamepadAccel>1.01f) + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal accel value from gamepad", __FILE__, __LINE__); + + if(mGamepadCarBrake<0.0f || mGamepadCarBrake>1.01f) + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal brake value from gamepad", __FILE__, __LINE__); + + if(PxAbs(mGamepadCarSteer)>1.01f) + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal steer value from gamepad", __FILE__, __LINE__); + + if(mUseKeyInputs && ((mGamepadAccel+mGamepadCarBrake+mGamepadCarSteer)!=0.0f || mGamepadGearup || mGamepadGeardown || mGamepadCarHandbrake)) + { + mUseKeyInputs=false; + } + + if(!mUseKeyInputs) + { + rawInputData.setAnalogAccel(mGamepadAccel); + rawInputData.setAnalogBrake(mGamepadCarBrake); + rawInputData.setAnalogHandbrake(mGamepadCarHandbrake ? 1.0f : 0.0f); + rawInputData.setAnalogSteer(mGamepadCarSteer); + rawInputData.setGearUp(mGamepadGearup); + rawInputData.setGearDown(mGamepadGeardown); + } + } + + if(useAutoGears && (rawInputData.getGearDown() || rawInputData.getGearUp())) + { + rawInputData.setGearDown(false); + rawInputData.setGearUp(false); + } + + mNumSamples++; +} + +void SampleVehicle_VehicleController::processRawInputs +(const PxF32 dtime, const bool useAutoGears, PxVehicleDriveTankRawInputData& rawInputData) +{ + // Keyboard + //Keyboard controls for tank not implemented yet. + { + /* + if(mRecord) + { + if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES) + { + mKeyboardAccelValues[mNumSamples] = mAccelKeyPressed; + mKeyboardBrakeValues[mNumSamples] = mBrakeKeyPressed; + mKeyboardHandbrakeValues[mNumSamples] = mHandbrakeKeyPressed; + mKeyboardSteerLeftValues[mNumSamples] = mSteerLeftKeyPressed; + mKeyboardSteerRightValues[mNumSamples] = mSteerRightKeyPressed; + mKeyboardGearupValues[mNumSamples] = mGearUpKeyPressed; + mKeyboardGeardownValues[mNumSamples] = mGearDownKeyPressed; + } + } + else if(mReplay) + { + if(mNumSamples<mNumRecordedSamples) + { + mAccelKeyPressed = mKeyboardAccelValues[mNumSamples]; + mBrakeKeyPressed = mKeyboardBrakeValues[mNumSamples]; + mHandbrakeKeyPressed = mKeyboardHandbrakeValues[mNumSamples]; + mSteerLeftKeyPressed = mKeyboardSteerLeftValues[mNumSamples]; + mSteerRightKeyPressed = mKeyboardSteerRightValues[mNumSamples]; + mGearUpKeyPressed = mKeyboardGearupValues[mNumSamples]; + mGearDownKeyPressed = mKeyboardGeardownValues[mNumSamples]; + } + } + */ + + rawInputData.setDigitalAccel(mKeyPressedAccel); + rawInputData.setDigitalLeftThrust(mKeyPressedThrustLeft); + rawInputData.setDigitalRightThrust(mKeyPressedThrustRight); + rawInputData.setDigitalLeftBrake(mKeyPressedBrakeLeft); + rawInputData.setDigitalRightBrake(mKeyPressedBrakeRight); + rawInputData.setGearUp(mKeyPressedGearUp); + rawInputData.setGearDown(mKeyPressedGearDown); + + mUseKeyInputs= + (mKeyPressedAccel || mKeyPressedThrustLeft || mKeyPressedThrustRight || + mKeyPressedBrakeLeft || mKeyPressedBrakeRight || + mKeyPressedGearUp || mKeyPressedGearDown); + } + + + // Gamepad + { + if(mRecord) + { + if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES) + { + mGamepadAccelValues[mNumSamples] = mGamepadAccel; + mGamepadTankThrustLeftValues[mNumSamples] = mTankThrustLeft; + mGamepadTankThrustRightValues[mNumSamples] = mTankThrustRight; + mGamepadGearupValues[mNumSamples] = mGamepadGearup; + mGamepadGeardownValues[mNumSamples] = mGamepadGeardown; + } + } + else if(mReplay) + { + if(mNumSamples<mNumRecordedSamples) + { + mGamepadAccel = mGamepadAccelValues[mNumSamples]; + mTankThrustLeft = mGamepadTankThrustLeftValues[mNumSamples]; + mTankThrustRight= mGamepadTankThrustRightValues[mNumSamples]; + mGamepadGearup = mGamepadGearupValues[mNumSamples]; + mGamepadGeardown = mGamepadGeardownValues[mNumSamples]; + } + } + + if(mGamepadAccel<0.0f || mGamepadAccel>1.01f) + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal accel value from gamepad", __FILE__, __LINE__); + + if(mTankThrustLeft<-1.01f || mTankThrustLeft>1.01f) + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal brake value from gamepad", __FILE__, __LINE__); + + if(mTankThrustRight<-1.01f || mTankThrustRight>1.01f) + getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal steer value from gamepad", __FILE__, __LINE__); + + if(mUseKeyInputs && ((mGamepadAccel+mTankThrustLeft+mTankThrustRight)!=0.0f || mGamepadGearup || mGamepadGeardown)) + { + mUseKeyInputs=false; + } + + if(!mUseKeyInputs) + { + rawInputData.setAnalogAccel(mGamepadAccel); + rawInputData.setAnalogLeftThrust(mTankThrustLeft); + rawInputData.setAnalogRightThrust(mTankThrustRight); + rawInputData.setAnalogLeftBrake(mTankBrakeLeft); + rawInputData.setAnalogRightBrake(mTankBrakeRight); + rawInputData.setGearUp(mGamepadGearup); + rawInputData.setGearDown(mGamepadGeardown); + } + } + + if(useAutoGears && (rawInputData.getGearDown() || rawInputData.getGearUp())) + { + rawInputData.setGearDown(false); + rawInputData.setGearUp(false); + } + + mNumSamples++; +} + +#define THRESHOLD_FORWARD_SPEED (0.1f) +#define THRESHOLD_SIDEWAYS_SPEED (0.2f) +#define THRESHOLD_ROLLING_BACKWARDS_SPEED (0.1f) + +void SampleVehicle_VehicleController::processAutoReverse +(const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, + const PxVehicleDrive4WRawInputData& carRawInputs, + bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const +{ + newIsMovingForwardSlowly = false; + toggleAutoReverse = false; + + if(driveDynData.getUseAutoGears()) + { + //If the car is travelling very slowly in forward gear without player input and the player subsequently presses the brake then we want the car to go into reverse gear + //If the car is travelling very slowly in reverse gear without player input and the player subsequently presses the accel then we want the car to go into forward gear + //If the car is in forward gear and is travelling backwards then we want to automatically put the car into reverse gear. + //If the car is in reverse gear and is travelling forwards then we want to automatically put the car into forward gear. + //(If the player brings the car to rest with the brake the player needs to release the brake then reapply it + //to indicate they want to toggle between forward and reverse.) + + const bool prevIsMovingForwardSlowly=mIsMovingForwardSlowly; + bool isMovingForwardSlowly=false; + bool isMovingBackwards=false; + const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults); + if(!isInAir) + { + bool accelRaw,brakeRaw,handbrakeRaw; + if(mUseKeyInputs) + { + accelRaw=carRawInputs.getDigitalAccel(); + brakeRaw=carRawInputs.getDigitalBrake(); + handbrakeRaw=carRawInputs.getDigitalHandbrake(); + } + else + { + accelRaw=carRawInputs.getAnalogAccel() > 0 ? true : false; + brakeRaw=carRawInputs.getAnalogBrake() > 0 ? true : false; + handbrakeRaw=carRawInputs.getAnalogHandbrake() > 0 ? true : false; + } + + const PxF32 forwardSpeed = focusVehicle.computeForwardSpeed(); + const PxF32 forwardSpeedAbs = PxAbs(forwardSpeed); + const PxF32 sidewaysSpeedAbs = PxAbs(focusVehicle.computeSidewaysSpeed()); + const PxU32 currentGear = driveDynData.getCurrentGear(); + const PxU32 targetGear = driveDynData.getTargetGear(); + + //Check if the car is rolling against the gear (backwards in forward gear or forwards in reverse gear). + if(PxVehicleGearsData::eFIRST == currentGear && forwardSpeed < -THRESHOLD_ROLLING_BACKWARDS_SPEED) + { + isMovingBackwards = true; + } + else if(PxVehicleGearsData::eREVERSE == currentGear && forwardSpeed > THRESHOLD_ROLLING_BACKWARDS_SPEED) + { + isMovingBackwards = true; + } + + //Check if the car is moving slowly. + if(forwardSpeedAbs < THRESHOLD_FORWARD_SPEED && sidewaysSpeedAbs < THRESHOLD_SIDEWAYS_SPEED) + { + isMovingForwardSlowly=true; + } + + //Now work if we need to toggle from forwards gear to reverse gear or vice versa. + if(isMovingBackwards) + { + if(!accelRaw && !brakeRaw && !handbrakeRaw && (currentGear == targetGear)) + { + //The car is rolling against the gear and the player is doing nothing to stop this. + toggleAutoReverse = true; + } + } + else if(prevIsMovingForwardSlowly && isMovingForwardSlowly) + { + if((currentGear > PxVehicleGearsData::eNEUTRAL) && brakeRaw && !accelRaw && (currentGear == targetGear)) + { + //The car was moving slowly in forward gear without player input and is now moving slowly with player input that indicates the + //player wants to switch to reverse gear. + toggleAutoReverse = true; + } + else if(currentGear == PxVehicleGearsData::eREVERSE && accelRaw && !brakeRaw && (currentGear == targetGear)) + { + //The car was moving slowly in reverse gear without player input and is now moving slowly with player input that indicates the + //player wants to switch to forward gear. + toggleAutoReverse = true; + } + } + + //If the car was brought to rest through braking then the player needs to release the brake then reapply + //to indicate that the gears should toggle between reverse and forward. + if(isMovingForwardSlowly && !brakeRaw && !accelRaw && !handbrakeRaw) + { + newIsMovingForwardSlowly = true; + } + } + } +} + +void SampleVehicle_VehicleController::processAutoReverse +(const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, + const PxVehicleDriveTankRawInputData& tankRawInputs, + bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const +{ + newIsMovingForwardSlowly = false; + toggleAutoReverse = false; + + if(driveDynData.getUseAutoGears()) + { + //If the car is travelling very slowly in forward gear without player input and the player subsequently presses the brake then we want the car to go into reverse gear + //If the car is travelling very slowly in reverse gear without player input and the player subsequently presses the accel then we want the car to go into forward gear + //If the car is in forward gear and is travelling backwards then we want to automatically put the car into reverse gear. + //If the car is in reverse gear and is travelling forwards then we want to automatically put the car into forward gear. + //(If the player brings the car to rest with the brake the player needs to release the brake then reapply it + //to indicate they want to toggle between forward and reverse.) + + const bool prevIsMovingForwardSlowly=mIsMovingForwardSlowly; + bool isMovingForwardSlowly=false; + bool isMovingBackwards=false; + const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults); + if(!isInAir) + { + bool accelLeft,accelRight,brakeLeft,brakeRight; + if(mUseKeyInputs) + { + accelLeft=tankRawInputs.getDigitalLeftThrust(); + accelRight=tankRawInputs.getDigitalRightThrust(); + brakeLeft=tankRawInputs.getDigitalLeftBrake(); + brakeRight=tankRawInputs.getDigitalRightBrake(); + } + else + { + accelLeft = tankRawInputs.getAnalogLeftThrust() > 0 ? true : false; + accelRight = tankRawInputs.getAnalogRightThrust() > 0 ? true : false; + brakeLeft = tankRawInputs.getAnalogLeftBrake() > 0 ? true : false; + brakeRight = tankRawInputs.getAnalogRightBrake() > 0 ? true : false; + + /* + if(accelLeft && accelLeft==accelRight && !brakeLeft && !brakeRight) + { + shdfnd::printFormatted("aligned accel\n"); + } + + if(brakeLeft && brakeLeft==brakeRight && !accelLeft && !accelRight) + { + shdfnd::printFormatted("aligned brake\n"); + } + */ + + } + + const PxF32 forwardSpeed = focusVehicle.computeForwardSpeed(); + const PxF32 forwardSpeedAbs = PxAbs(forwardSpeed); + const PxF32 sidewaysSpeedAbs = PxAbs(focusVehicle.computeSidewaysSpeed()); + const PxU32 currentGear = driveDynData.getCurrentGear(); + const PxU32 targetGear = driveDynData.getTargetGear(); + + //Check if the car is rolling against the gear (backwards in forward gear or forwards in reverse gear). + if(PxVehicleGearsData::eFIRST == currentGear && forwardSpeed < -THRESHOLD_ROLLING_BACKWARDS_SPEED) + { + isMovingBackwards = true; + } + else if(PxVehicleGearsData::eREVERSE == currentGear && forwardSpeed > THRESHOLD_ROLLING_BACKWARDS_SPEED) + { + isMovingBackwards = true; + } + + //Check if the car is moving slowly. + if(forwardSpeedAbs < THRESHOLD_FORWARD_SPEED && sidewaysSpeedAbs < THRESHOLD_SIDEWAYS_SPEED) + { + isMovingForwardSlowly=true; + } + + //Now work if we need to toggle from forwards gear to reverse gear or vice versa. + if(isMovingBackwards) + { + if(!accelLeft && !accelRight && !brakeLeft && !brakeRight && (currentGear == targetGear)) + { + //The car is rolling against the gear and the player is doing nothing to stop this. + toggleAutoReverse = true; + } + } + else if(prevIsMovingForwardSlowly && isMovingForwardSlowly) + { + if((currentGear > PxVehicleGearsData::eNEUTRAL) && brakeLeft && brakeRight && !accelLeft && !accelRight && (currentGear == targetGear)) + { + //The car was moving slowly in forward gear without player input and is now moving slowly with player input that indicates the + //player wants to switch to reverse gear. + toggleAutoReverse = true; + } + else if(currentGear == PxVehicleGearsData::eREVERSE && accelLeft && accelRight && !brakeLeft && !brakeRight && (currentGear == targetGear)) + { + //The car was moving slowly in reverse gear without player input and is now moving slowly with player input that indicates the + //player wants to switch to forward gear. + toggleAutoReverse = true; + } + } + + //If the car was brought to rest through braking then the player needs to release the brake then reapply + //to indicate that the gears should toggle between reverse and forward. + if(isMovingForwardSlowly && (!brakeLeft || !brakeRight) && (!accelLeft || !accelRight)) + { + newIsMovingForwardSlowly = true; + } + } + } +} + +void SampleVehicle_VehicleController::update(const PxF32 timestep, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, PxVehicleWheels& focusVehicle) +{ + PxVehicleDriveDynData* driveDynData=NULL; + bool isTank=false; + PxVehicleDriveTankControlModel::Enum tankDriveModel=PxVehicleDriveTankControlModel::eSTANDARD; + switch(focusVehicle.getVehicleType()) + { + case PxVehicleTypes::eDRIVE4W: + { + PxVehicleDrive4W& vehDrive4W=(PxVehicleDrive4W&)focusVehicle; + driveDynData=&vehDrive4W.mDriveDynData; + isTank=false; + } + break; + case PxVehicleTypes::eDRIVENW: + { + PxVehicleDriveNW& vehDriveNW=(PxVehicleDriveNW&)focusVehicle; + driveDynData=&vehDriveNW.mDriveDynData; + isTank=false; + } + break; + case PxVehicleTypes::eDRIVETANK: + { + PxVehicleDriveTank& vehDriveTank=(PxVehicleDriveTank&)focusVehicle; + driveDynData=&vehDriveTank.mDriveDynData; + isTank=true; + tankDriveModel=vehDriveTank.getDriveModel(); + } + break; + default: + PX_ASSERT(false); + break; + } + + //Toggle autogear flag + if(mToggleAutoGears) + { + driveDynData->toggleAutoGears(); + mToggleAutoGears = false; + } + + //Store raw inputs in replay stream if in recording mode. + //Set raw inputs from replay stream if in replay mode. + //Store raw inputs from active stream in handy arrays so we don't need to worry + //about which stream (live input or replay) is active. + //Work out if we are using keys or gamepad controls depending on which is being used + //(gamepad selected if both are being used). + PxVehicleDrive4WRawInputData carRawInputs; + PxVehicleDriveTankRawInputData tankRawInputs(tankDriveModel); + if(!isTank) + { + processRawInputs(timestep,driveDynData->getUseAutoGears(),carRawInputs); + } + else + { + processRawInputs(timestep,driveDynData->getUseAutoGears(),tankRawInputs); + } + + //Work out if the car is to flip from reverse to forward gear or from forward gear to reverse. + bool toggleAutoReverse = false; + bool newIsMovingForwardSlowly = false; + if(!isTank) + { + processAutoReverse(focusVehicle, *driveDynData, vehicleWheelQueryResults, carRawInputs, toggleAutoReverse, newIsMovingForwardSlowly); + } + else + { + processAutoReverse(focusVehicle, *driveDynData, vehicleWheelQueryResults, tankRawInputs, toggleAutoReverse, newIsMovingForwardSlowly); + } + mIsMovingForwardSlowly = newIsMovingForwardSlowly; + + + //If the car is to flip gear direction then switch gear as appropriate. + if(toggleAutoReverse) + { + mInReverseMode = !mInReverseMode; + + if(mInReverseMode) + { + driveDynData->forceGearChange(PxVehicleGearsData::eREVERSE); + } + else + { + driveDynData->forceGearChange(PxVehicleGearsData::eFIRST); + } + } + + //If in reverse mode then swap the accel and brake. + if(mInReverseMode) + { + if(mUseKeyInputs) + { + if(!isTank) + { + const bool accel=carRawInputs.getDigitalAccel(); + const bool brake=carRawInputs.getDigitalBrake(); + carRawInputs.setDigitalAccel(brake); + carRawInputs.setDigitalBrake(accel); + } + else + { + //Keyboard controls for tank not implemented yet. + const bool accelLeft=tankRawInputs.getDigitalLeftThrust(); + const bool accelRight=tankRawInputs.getDigitalRightThrust(); + const bool brakeLeft=tankRawInputs.getDigitalLeftBrake(); + const bool brakeRight=tankRawInputs.getDigitalRightBrake(); + tankRawInputs.setDigitalLeftThrust(brakeLeft); + tankRawInputs.setDigitalRightThrust(brakeRight); + tankRawInputs.setDigitalLeftBrake(accelLeft); + tankRawInputs.setDigitalRightBrake(accelRight); + } + } + else + { + if(!isTank) + { + const PxF32 accel=carRawInputs.getAnalogAccel(); + const PxF32 brake=carRawInputs.getAnalogBrake(); + carRawInputs.setAnalogAccel(brake); + carRawInputs.setAnalogBrake(accel); + } + else if(PxVehicleDriveTankControlModel::eSPECIAL==tankDriveModel) + { + const PxF32 thrustLeft=tankRawInputs.getAnalogLeftThrust(); + const PxF32 thrustRight=tankRawInputs.getAnalogRightThrust(); + tankRawInputs.setAnalogLeftThrust(-thrustLeft); + tankRawInputs.setAnalogRightThrust(-thrustRight); + } + else + { + const PxF32 thrustLeft=tankRawInputs.getAnalogLeftThrust(); + const PxF32 thrustRight=tankRawInputs.getAnalogRightThrust(); + const PxF32 brakeLeft=tankRawInputs.getAnalogLeftBrake(); + const PxF32 brakeRight=tankRawInputs.getAnalogRightBrake(); + tankRawInputs.setAnalogLeftThrust(brakeLeft); + tankRawInputs.setAnalogLeftBrake(thrustLeft); + tankRawInputs.setAnalogRightThrust(brakeRight); + tankRawInputs.setAnalogRightBrake(thrustRight); + } + } + } + + // Now filter the raw input values and apply them to focus vehicle + // as floats for brake,accel,handbrake,steer and bools for gearup,geardown. + if(mUseKeyInputs) + { + if(!isTank) + { + const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults); + PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs + (gKeySmoothingData,gSteerVsForwardSpeedTable,carRawInputs,timestep,isInAir,(PxVehicleDrive4W&)focusVehicle); + } + else + { + PxVehicleDriveTankSmoothDigitalRawInputsAndSetAnalogInputs + (gKeySmoothingData,tankRawInputs,timestep,(PxVehicleDriveTank&)focusVehicle); + } + } + else + { + if(!isTank) + { + const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults); + PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs + (gCarPadSmoothingData,gSteerVsForwardSpeedTable,carRawInputs,timestep,isInAir,(PxVehicleDrive4W&)focusVehicle); + } + else + { + PxVehicleDriveTankSmoothAnalogRawInputsAndSetAnalogInputs + (gTankPadSmoothingData,tankRawInputs,timestep,(PxVehicleDriveTank&)focusVehicle); + } + } +} + +void SampleVehicle_VehicleController::restart() +{ + const bool record=mRecord; + const bool replay=mReplay; + const PxU32 numSamples=mNumSamples; + const PxU32 numRecordedSamples=mNumRecordedSamples; + clear(); + mRecord=record; + mReplay=replay; + mNumRecordedSamples=numRecordedSamples; + + if(record) + { + PX_ASSERT(!replay); + mNumRecordedSamples = numSamples; + mRecord = false; + mReplay = true; + } +} diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.h new file mode 100644 index 00000000..d823ad5e --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.h @@ -0,0 +1,226 @@ +// 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. + + +#ifndef SAMPLE_VEHICLE_VEHICLE_CONTROLLER_H +#define SAMPLE_VEHICLE_VEHICLE_CONTROLLER_H + +#include "common/PxPhysXCommonConfig.h" +#include "foundation/PxVec3.h" +#include "vehicle/PxVehicleSDK.h" +#include "vehicle/PxVehicleUpdate.h" +#include "vehicle/PxVehicleUtilControl.h" + +using namespace physx; + +class SampleVehicle_VehicleController +{ +public: + + SampleVehicle_VehicleController(); + ~SampleVehicle_VehicleController(); + + void setCarKeyboardInputs + (const bool accel, const bool brake, const bool handbrake, + const bool steerleft, const bool steerright, + const bool gearup, const bool geardown) + { + mKeyPressedAccel=accel; + mKeyPressedBrake=brake; + mKeyPressedHandbrake=handbrake; + mKeyPressedSteerLeft=steerleft; + mKeyPressedSteerRight=steerright; + mKeyPressedGearUp=gearup; + mKeyPressedGearDown=geardown; + } + + void setCarGamepadInputs + (const PxF32 accel, const PxF32 brake, + const PxF32 steer, + const bool gearup, const bool geardown, + const bool handbrake) + { + mGamepadAccel=accel; + mGamepadCarBrake=brake; + mGamepadCarSteer=steer; + mGamepadGearup=gearup; + mGamepadGeardown=geardown; + mGamepadCarHandbrake=handbrake; + } + + void setTankKeyboardInputs + (const bool accel, const bool thrustLeft, const bool thrustRight, const bool brakeLeft, const bool brakeRight, const bool gearUp, const bool gearDown) + { + mKeyPressedAccel=accel; + mKeyPressedThrustLeft=thrustLeft; + mKeyPressedThrustRight=thrustRight; + mKeyPressedBrakeLeft=brakeLeft; + mKeyPressedBrakeRight=brakeRight; + mKeyPressedGearUp=gearUp; + mKeyPressedGearDown=gearDown; + } + + void setTankGamepadInputs + (const PxF32 accel, const PxF32 thrustLeft, const PxF32 thrustRight, const PxF32 brakeLeft, const PxF32 brakeRight, const bool gearUp, const bool gearDown) + { + mGamepadAccel=accel; + mTankThrustLeft=thrustLeft; + mTankThrustRight=thrustRight; + mTankBrakeLeft=brakeLeft; + mTankBrakeRight=brakeRight; + mGamepadGearup=gearUp; + mGamepadGeardown=gearDown; + } + + void toggleAutoGearFlag() + { + mToggleAutoGears = true; + } + + void update(const PxF32 dtime, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, PxVehicleWheels& focusVehicle); + + void clear(); + +private: + + //Raw driving inputs - keys (car + tank) + bool mKeyPressedAccel; + bool mKeyPressedGearUp; + bool mKeyPressedGearDown; + + //Raw driving inputs - keys (car only) + bool mKeyPressedBrake; + bool mKeyPressedHandbrake; + bool mKeyPressedSteerLeft; + bool mKeyPressedSteerRight; + + //Raw driving inputs - keys (tank only) + bool mKeyPressedThrustLeft; + bool mKeyPressedThrustRight; + bool mKeyPressedBrakeLeft; + bool mKeyPressedBrakeRight; + + //Raw driving inputs - gamepad (car + tank) + PxF32 mGamepadAccel; + bool mGamepadGearup; + bool mGamepadGeardown; + + //Raw driving inputs - gamepad (car only) + PxF32 mGamepadCarBrake; + PxF32 mGamepadCarSteer; + bool mGamepadCarHandbrake; + + //Raw driving inputs - (tank only) + PxF32 mTankThrustLeft; + PxF32 mTankThrustRight; + PxF32 mTankBrakeLeft; + PxF32 mTankBrakeRight; + + //Record and replay using raw driving inputs. + bool mRecord; + bool mReplay; + enum + { + MAX_NUM_RECORD_REPLAY_SAMPLES=8192 + }; + // Keyboard + bool mKeyboardAccelValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mKeyboardBrakeValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mKeyboardHandbrakeValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mKeyboardSteerLeftValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mKeyboardSteerRightValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mKeyboardGearupValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mKeyboardGeardownValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + // Gamepad - (tank + car) + PxF32 mGamepadAccelValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mGamepadGearupValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mGamepadGeardownValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + // Gamepad - car only + PxF32 mGamepadCarBrakeValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + PxF32 mGamepadCarSteerValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + bool mGamepadCarHandbrakeValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + //Gamepad - tank only. + PxF32 mGamepadTankThrustLeftValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + PxF32 mGamepadTankThrustRightValues[MAX_NUM_RECORD_REPLAY_SAMPLES]; + + PxU32 mNumSamples; + PxU32 mNumRecordedSamples; + + // Raw data taken from the correct stream (live input stream or replay stream) + bool mUseKeyInputs; + + // Toggle autogears flag on focus vehicle + bool mToggleAutoGears; + + //Auto-reverse mode. + bool mIsMovingForwardSlowly; + bool mInReverseMode; + + //Update + void processRawInputs(const PxF32 timestep, const bool useAutoGears, PxVehicleDrive4WRawInputData& rawInputData); + void processRawInputs(const PxF32 timestep, const bool useAutoGears, PxVehicleDriveTankRawInputData& rawInputData); + void processAutoReverse( + const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, + const PxVehicleDrive4WRawInputData& rawInputData, + bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const; + void processAutoReverse( + const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, + const PxVehicleDriveTankRawInputData& rawInputData, + bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const; + + //////////////////////////////// + //Record and replay deprecated at the moment. + //Setting functions as private to avoid them being used. + /////////////////////////////// + bool getIsInRecordReplayMode() const {return (mRecord || mReplay);} + bool getIsRecording() const {return mRecord;} + bool getIsReplaying() const {return mReplay;} + + void enableRecordReplayMode() + { + PX_ASSERT(!getIsInRecordReplayMode()); + mRecord=true; + mReplay=false; + mNumRecordedSamples=0; + } + + void disableRecordReplayMode() + { + PX_ASSERT(getIsInRecordReplayMode()); + mRecord=false; + mReplay=false; + mNumRecordedSamples=0; + } + + void restart(); + //////////////////////////// + +}; + +#endif //SAMPLE_VEHICLE_VEHICLE_CONTROLLER_H
\ No newline at end of file diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.cpp new file mode 100644 index 00000000..3eacceaf --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.cpp @@ -0,0 +1,171 @@ +// 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_VehicleCooking.h" +#include "PxTkStream.h" +#include "extensions/PxDefaultStreams.h" + + +PxConvexMesh* createConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking) +{ + // Create descriptor for convex mesh + PxConvexMeshDesc convexDesc; + convexDesc.points.count = numVerts; + convexDesc.points.stride = sizeof(PxVec3); + convexDesc.points.data = verts; + convexDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX; + + PxConvexMesh* convexMesh = NULL; + PxDefaultMemoryOutputStream buf; + if(cooking.cookConvexMesh(convexDesc, buf)) + { + PxDefaultMemoryInputData id(buf.getData(), buf.getSize()); + convexMesh = physics.createConvexMesh(id); + } + + return convexMesh; +} + +PxConvexMesh* createCuboidConvexMesh(const PxVec3& halfExtents, PxPhysics& physics, PxCooking& cooking) +{ + PxVec3 verts[8]= + { + PxVec3(-halfExtents.x, -halfExtents.y, -halfExtents.z), + PxVec3(-halfExtents.x, -halfExtents.y, +halfExtents.z), + PxVec3(-halfExtents.x, +halfExtents.y, -halfExtents.z), + PxVec3(-halfExtents.x, +halfExtents.y, +halfExtents.z), + PxVec3(+halfExtents.x, -halfExtents.y, -halfExtents.z), + PxVec3(+halfExtents.x, -halfExtents.y, +halfExtents.z), + PxVec3(+halfExtents.x, +halfExtents.y, -halfExtents.z), + PxVec3(+halfExtents.x, +halfExtents.y, +halfExtents.z) + }; + PxU32 numVerts=8; + + return createConvexMesh(verts,numVerts,physics,cooking); +} + +PxConvexMesh* createWedgeConvexMesh(const PxVec3& halfExtents, PxPhysics& physics, PxCooking& cooking) +{ + PxVec3 verts[6]= + { + PxVec3(-halfExtents.x, -halfExtents.y, -halfExtents.z), + PxVec3(-halfExtents.x, -halfExtents.y, +halfExtents.z), + PxVec3(-halfExtents.x, +halfExtents.y, -halfExtents.z), + PxVec3(+halfExtents.x, -halfExtents.y, -halfExtents.z), + PxVec3(+halfExtents.x, -halfExtents.y, +halfExtents.z), + PxVec3(+halfExtents.x, +halfExtents.y, -halfExtents.z) + }; + PxU32 numVerts=6; + + return createConvexMesh(verts,numVerts,physics,cooking); +} + +PxConvexMesh* createCylinderConvexMesh(const PxF32 width, const PxF32 radius, const PxU32 numCirclePoints, PxPhysics& physics, PxCooking& cooking) +{ +#define MAX_NUM_VERTS_IN_CIRCLE 16 + PX_ASSERT(numCirclePoints<MAX_NUM_VERTS_IN_CIRCLE); + PxVec3 verts[2*MAX_NUM_VERTS_IN_CIRCLE]; + PxU32 numVerts=2*numCirclePoints; + const PxF32 dtheta=2*PxPi/(1.0f*numCirclePoints); + for(PxU32 i=0;i<MAX_NUM_VERTS_IN_CIRCLE;i++) + { + const PxF32 theta=dtheta*i; + const PxF32 cosTheta=radius*PxCos(theta); + const PxF32 sinTheta=radius*PxSin(theta); + verts[2*i+0]=PxVec3(-0.5f*width, cosTheta, sinTheta); + verts[2*i+1]=PxVec3(+0.5f*width, cosTheta, sinTheta); + } + + return createConvexMesh(verts,numVerts,physics,cooking); +} + +PxConvexMesh* createSquashedCuboidMesh(const PxF32 baseLength, const PxF32 baseDepth, const PxF32 height1, const PxF32 height2, PxPhysics& physics, PxCooking& cooking) +{ + const PxF32 x=baseLength*0.5f; + const PxF32 z=baseDepth*0.5f; + PxVec3 verts[8]= + { + PxVec3(-x,-0.5f*height1,-z), + PxVec3(-x,-0.5f*height1,+z), + PxVec3(+x,-0.5f*height1,-z), + PxVec3(+x,-0.5f*height1,+z), + PxVec3(-x,-0.5f*height1+height2,-z), + PxVec3(-x,+0.5f*height1,+z), + PxVec3(+x,-0.5f*height1+height2,-z), + PxVec3(+x,+0.5f*height1,+z) + }; + PxU32 numVerts=8; + + return createConvexMesh(verts,numVerts,physics,cooking); +} + + +PxConvexMesh* createPrismConvexMesh(const PxF32 baseLength, const PxF32 baseDepth, const PxF32 height, PxPhysics& physics, PxCooking& cooking) +{ + const PxF32 x=baseLength*0.5f; + const PxF32 z=baseDepth*0.5f; + + PxVec3 verts[6]= + { + PxVec3(-x, 0, -z), + PxVec3(-x, 0, +z), + PxVec3(+x, 0, -z), + PxVec3(+x, 0, +z), + PxVec3(-x, height, 0), + PxVec3(+x, height, 0), + }; + PxU32 numVerts=6; + + return createConvexMesh(verts,numVerts,physics,cooking); +} + +PxConvexMesh* createChassisConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking) +{ + return createConvexMesh(verts,numVerts,physics,cooking); +} + +PxConvexMesh* createWheelConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking) +{ + //Extract the wheel radius and width from the aabb of the wheel convex mesh. + PxVec3 wheelMin(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32); + PxVec3 wheelMax(-PX_MAX_F32,-PX_MAX_F32,-PX_MAX_F32); + for(PxU32 i=0;i<numVerts;i++) + { + wheelMin.x=PxMin(wheelMin.x,verts[i].x); + wheelMin.y=PxMin(wheelMin.y,verts[i].y); + wheelMin.z=PxMin(wheelMin.z,verts[i].z); + wheelMax.x=PxMax(wheelMax.x,verts[i].x); + wheelMax.y=PxMax(wheelMax.y,verts[i].y); + wheelMax.z=PxMax(wheelMax.z,verts[i].z); + } + const PxF32 wheelWidth=wheelMax.x-wheelMin.x; + const PxF32 wheelRadius=PxMax(wheelMax.y,wheelMax.z); + + return createCylinderConvexMesh(wheelWidth,wheelRadius,8,physics,cooking); +} diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.h new file mode 100644 index 00000000..053909c2 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef VEHICLE_COOKING_H +#define VEHICLE_COOKING_H + +#include "PxPhysicsAPI.h" + +using namespace physx; + + +PxConvexMesh* createConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking); +PxConvexMesh* createCuboidConvexMesh(const PxVec3& halfExtents, PxPhysics& physics, PxCooking& cooking); +PxConvexMesh* createWedgeConvexMesh(const PxVec3& halfExtents, PxPhysics& physics, PxCooking& cooking); +PxConvexMesh* createCylinderConvexMesh(const PxF32 width, const PxF32 radius, const PxU32 numCirclePoints, PxPhysics& physics, PxCooking& cooking); +PxConvexMesh* createSquashedCuboidMesh(const PxF32 baseLength, const PxF32 baseDepth, const PxF32 height1, const PxF32 height2, PxPhysics& physics, PxCooking& cooking); +PxConvexMesh* createPrismConvexMesh(const PxF32 baseLength, const PxF32 baseDepth, const PxF32 height, PxPhysics& physics, PxCooking& cooking); +PxConvexMesh* createWheelConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking); +PxConvexMesh* createChassisConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking); + + +#endif //VEHICLE_COOKING_H 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; +} + + + diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.h new file mode 100644 index 00000000..e1c1bc86 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.h @@ -0,0 +1,226 @@ +// 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. + +#ifndef SAMPLE_VEHICLE_VEHICLE_MANAGER_H +#define SAMPLE_VEHICLE_VEHICLE_MANAGER_H + +#include "vehicle/PxVehicleSDK.h" +#include "vehicle/PxVehicleDrive4W.h" +#include "vehicle/PxVehicleDriveNW.h" +#include "vehicle/PxVehicleDriveTank.h" +#include "vehicle/PxVehicleUpdate.h" +#include "foundation/PxFoundation.h" + +#if PX_DEBUG_VEHICLE_ON +#include "vehicle/PxVehicleUtilTelemetry.h" +#endif + +using namespace physx; + +namespace physx +{ + class PxScene; + class PxBatchQuery; + class PxCooking; + class PxMaterial; + class PxConvexMesh; + struct PxVehicleDrivableSurfaceType; +} + +class SampleVehicleSceneQueryData; +class SampleVehicleWheelQueryResults; + +class PxVehicle4WAlloc; + +//Collision types and flags describing collision interactions of each collision type. +enum +{ + COLLISION_FLAG_GROUND = 1 << 0, + COLLISION_FLAG_WHEEL = 1 << 1, + COLLISION_FLAG_CHASSIS = 1 << 2, + COLLISION_FLAG_OBSTACLE = 1 << 3, + COLLISION_FLAG_DRIVABLE_OBSTACLE= 1 << 4, + + COLLISION_FLAG_GROUND_AGAINST = COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE | COLLISION_FLAG_DRIVABLE_OBSTACLE, + COLLISION_FLAG_WHEEL_AGAINST = COLLISION_FLAG_WHEEL | COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE, + COLLISION_FLAG_CHASSIS_AGAINST = COLLISION_FLAG_GROUND | COLLISION_FLAG_WHEEL | COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE | COLLISION_FLAG_DRIVABLE_OBSTACLE, + COLLISION_FLAG_OBSTACLE_AGAINST = COLLISION_FLAG_GROUND | COLLISION_FLAG_WHEEL | COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE | COLLISION_FLAG_DRIVABLE_OBSTACLE, + COLLISION_FLAG_DRIVABLE_OBSTACLE_AGAINST= COLLISION_FLAG_GROUND | COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE | COLLISION_FLAG_DRIVABLE_OBSTACLE, +}; + +//Id of drivable surface (used by suspension raycast filtering). +enum +{ + DRIVABLE_SURFACE_ID=0xffffffff +}; + +//Drivable surface types. +enum +{ + SURFACE_TYPE_MUD=0, + SURFACE_TYPE_TARMAC, + SURFACE_TYPE_SNOW, + SURFACE_TYPE_GRASS, + MAX_NUM_SURFACE_TYPES +}; + +struct SurfaceTypeNames +{ + static const char* getName(PxU32 type) + { + static char surfaceTypes[MAX_NUM_SURFACE_TYPES+1][64]= + { + "mud", + "tarmac", + "ice", + "grass", + }; + + return surfaceTypes[type]; + } +}; + +//Tire types. +enum +{ + TIRE_TYPE_WETS=0, + TIRE_TYPE_SLICKS, + TIRE_TYPE_ICE, + TIRE_TYPE_MUD, + MAX_NUM_TIRE_TYPES +}; + +struct TireFrictionMultipliers +{ + static float getValue(PxU32 surfaceType, PxU32 tireType) + { + //Tire model friction for each combination of drivable surface type and tire type. + static PxF32 tireFrictionMultipliers[MAX_NUM_SURFACE_TYPES][MAX_NUM_TIRE_TYPES]= + { + //WETS SLICKS ICE MUD + {0.95f, 0.95f, 0.95f, 0.95f}, //MUD + {1.10f, 1.15f, 1.10f, 1.10f}, //TARMAC + {0.70f, 0.70f, 0.70f, 0.70f}, //ICE + {0.80f, 0.80f, 0.80f, 0.80f} //GRASS + }; + return tireFrictionMultipliers[surfaceType][tireType]; + } +}; + +class SampleVehicle_VehicleManager +{ +public: + + enum + { + MAX_NUM_4W_VEHICLES=8, + MAX_NUM_6W_VEHICLES=2, + MAX_NUM_4W_TANKS=2 + }; + + SampleVehicle_VehicleManager(); + ~SampleVehicle_VehicleManager(); + + void init(PxPhysics& physics, const PxMaterial** drivableSurfaceMaterials, const PxVehicleDrivableSurfaceType* drivableSurfaceTypes); + + void shutdown(); + + //Create a vehicle ready to drive. + void 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); + void 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); + void 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); + void 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); + + PX_FORCE_INLINE PxU32 getNbVehicles() const { return mNumVehicles; } + PX_FORCE_INLINE PxVehicleWheels* getVehicle(const PxU32 i) { return mVehicles[i]; } + PX_FORCE_INLINE const PxVehicleWheelQueryResult& getVehicleWheelQueryResults(const PxU32 i) const { return mVehicleWheelQueryResults[i]; } + void addVehicle(const PxU32 i, PxVehicleWheels* vehicle); + + //Start the suspension raycasts (always call before calling update) + void suspensionRaycasts(PxScene* scene); + + //Update vehicle dynamics and compute forces/torques to apply to sdk rigid bodies. +#if PX_DEBUG_VEHICLE_ON + void updateAndRecordTelemetryData(const PxF32 timestep, const PxVec3& gravity, PxVehicleWheels* focusVehicleNW, PxVehicleTelemetryData* telemetryDataNW); +#else + void update(const PxF32 timestep, const PxVec3& gravity); +#endif + + //Reset the car back to its rest state with a specified transform. + void resetNWCar(const PxTransform& transform, const PxU32 vehicleId); + + //Switch the player's vehicle to 3-wheeled modes and back to 4-wheeled mode. + void switchTo3WDeltaMode(const PxU32 vehicleId); + void switchTo3WTadpoleMode(const PxU32 vehicleId); + void switchTo4WMode(const PxU32 vehicleId); + + PxSerializationRegistry* getSerializationRegistry() { return mSerializationRegistry; } +private: + + //Array of all cars and report data for each car. + PxVehicleWheels* mVehicles[MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES]; + PxVehicleWheelQueryResult mVehicleWheelQueryResults[MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES]; + PxU32 mNumVehicles; + + //sdk raycasts (for the suspension lines). + SampleVehicleSceneQueryData* mSqData; + PxBatchQuery* mSqWheelRaycastBatchQuery; + + //Reports for each wheel. + SampleVehicleWheelQueryResults* mWheelQueryResults; + + //Cached simulation data of focus vehicle in 4W mode. + PxVehicleWheelsSimData* mWheelsSimData4W; + PxVehicleDriveSimData4W mDriveSimData4W; + bool mIsIn3WMode; + + //Friction from combinations of tire and surface types. + PxVehicleDrivableSurfaceToTireFrictionPairs* mSurfaceTirePairs; + + + //Initialise a car back to its start transform and state. + void resetNWCar(const PxTransform& startTransform, PxVehicleWheels* car); + + //Serialization + PxSerializationRegistry* mSerializationRegistry; +}; + +#endif //SAMPLE_VEHICLE_VEHICLE_MANAGER_H diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.cpp new file mode 100644 index 00000000..858a7bd4 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.cpp @@ -0,0 +1,73 @@ +// 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_WheelQueryResults.h" +#include "vehicle/PxVehicleSDK.h" +#include "PsFoundation.h" +#include "PsUtilities.h" + + +//#define CHECK_MSG(exp, msg) (!!(exp) || (physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, msg), 0) ) + + +SampleVehicleWheelQueryResults* SampleVehicleWheelQueryResults::allocate(const PxU32 maxNumWheels) +{ + const PxU32 size = sizeof(SampleVehicleWheelQueryResults) + sizeof(PxWheelQueryResult)*maxNumWheels; + SampleVehicleWheelQueryResults* resData = (SampleVehicleWheelQueryResults*)PX_ALLOC(size, "SampleVehicleWheelQueryResults"); + resData->init(); + PxU8* ptr = (PxU8*) resData; + ptr += sizeof(SampleVehicleWheelQueryResults); + resData->mWheelQueryResults = (PxWheelQueryResult*)ptr; + ptr += sizeof(PxWheelQueryResult)*maxNumWheels; + resData->mMaxNumWheels=maxNumWheels; + for(PxU32 i=0;i<maxNumWheels;i++) + { + new(&resData->mWheelQueryResults[i]) PxWheelQueryResult(); + } + return resData; +} + +void SampleVehicleWheelQueryResults::free() +{ + PX_FREE(this); +} + +PxWheelQueryResult* SampleVehicleWheelQueryResults::addVehicle(const PxU32 numWheels) +{ + PX_ASSERT((mNumWheels + numWheels) <= mMaxNumWheels); + PxWheelQueryResult* r = &mWheelQueryResults[mNumWheels]; + mNumWheels += numWheels; + return r; +} + + + + + + diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.h new file mode 100644 index 00000000..fc5dc032 --- /dev/null +++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.h @@ -0,0 +1,82 @@ +// 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. + +#ifndef SAMPLEVEHICLE_WHEELQUERYRESULTS_H +#define SAMPLEVEHICLE_WHEELQUERYRESULTS_H + +#include "vehicle/PxVehicleSDK.h" +#include "vehicle/PxVehicleUpdate.h" + +using namespace physx; + +//Data structure to store reports for each wheel. +class SampleVehicleWheelQueryResults +{ +public: + + //Allocate a buffer of wheel query results for up to maxNumWheels. + static SampleVehicleWheelQueryResults* allocate(const PxU32 maxNumWheels); + + //Free allocated buffer. + void free(); + + PxWheelQueryResult* addVehicle(const PxU32 numWheels); + +private: + + //One result for each wheel. + PxWheelQueryResult* mWheelQueryResults; + + //Maximum number of wheels. + PxU32 mMaxNumWheels; + + //Number of wheels + PxU32 mNumWheels; + + + SampleVehicleWheelQueryResults() + : mWheelQueryResults(NULL),mMaxNumWheels(0), mNumWheels(0) + { + init(); + } + + ~SampleVehicleWheelQueryResults() + { + } + + void init() + { + mWheelQueryResults=NULL; + mMaxNumWheels=0; + mNumWheels=0; + } +}; + + +#endif //SAMPLEVEHICLE_WHEELQUERYRESULTS_H |