PhysX járművek Szécsi László Bendefy Zoltán
• Assimp – Include könyvtár: • C:\Program Files\Assimp\Include – Lib könyvtár: • C:\Program Files\Assimp\lib\x86 • Boost – Include könyvtár: • C:\Program Files\boost\boost_1_52_0 • PhysX SDK 3.2 – Include könyvtár: • C:\Program Files\NVIDIA Corporation\PhysX SDK 3.2\Include – Lib könyvtár: • C:\Program Files\NVIDIA Corporation\PhysX SDK 3.2\Lib\win32
• Futtassuk a projektet:
• Ez az osztály konstruktora, itt épül fel a jármű. • Első lépésként hozzuk létre az 5 entitást (StaticPartEntity), amelyekből felépül az autó. A StaticPartEntity osztály egy wrappert képez a multimesh köré. chassis = StaticPartEntity::create(echassis); wheel1 = StaticPartEntity::create(ewheel); wheel2 = StaticPartEntity::create(ewheel); wheel3 = StaticPartEntity::create(ewheel); wheel4 = StaticPartEntity::create(ewheel);
• Írjuk bele egy wheelOffsets nevű tömbbe, hogy az autón belül hol legyenek a kerekek. wheelOffsets[0] = PxVec3(-3,-3, 6); //Front Left wheel wheelOffsets[1] = PxVec3( 3,-3, 6); //Front Right wheel wheelOffsets[2] = PxVec3(-3,-3,-5); //Rear left wheel wheelOffsets[3] = PxVec3( 3,-3,-5); //Rear right wheel
• Készítsük el a jármű viselkedését leíró szimulációs osztálypéldányokat! • Megyjegyzés: érdemes megnézni a createVehicle4WSimulationData() függvényben, hogy mennyi paramétert enged a PhysX állítani! PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(4); PxVehicleDriveSimData4W driveSimData; PxVehicleChassisData chassisData; createVehicle4WSimulationData (chassisWeight, chassisConvexMesh, wheelWeight,wheelConvexMeshes, wheelOffsets, *wheelsSimData,driveSimData,chassisData);
• Ez a függvény készíti el az actort, később majd ezt a függvényt is meg kell írnunk. actor = createVehicleActor4W(chassisData,wheelConvexMeshes,chassisConvexMesh,*scene,(scene->getPhysics()),*physicsMaterial);
• Ez a függvény készíti el az actort, később majd ezt a függvényt is meg kell írnunk. Ez elkészíti a geometriákat is. • Elkészítjük a PxVehicleDrive4W példányunkat actor = createVehicleActor4W(chassisData,wheelConvexMeshes,chassisConvexMesh,*scene,(scene->getPhysics()),*physicsMaterial); PxU32 n = actor->getNbShapes(); car = PxVehicleDrive4W::allocate(4); car->setup(&(scene->getPhysics()),actor,*wheelsSimData,driveSimData,0); //we won't need this anymore wheelsSimData->free();
• A talaj és a gumik közti súrlódási tényező beállítása az egyes PhysX Material-okra: int materialCount = scene->getPhysics().getNbMaterials(); PxMaterial** materials = new PxMaterial*[materialCount]; scene->getPhysics().getMaterials(materials, materialCount); // Specifying which materials will be drivable. A specific friction value can be applied using mSurfaceTirePairs- >setTypePairFriction; PxMaterial** drivableSurfaceMaterials = new PxMaterial*[materialCount]; for(int i = 0; i < materialCount; i++) { drivableSurfaceMaterials[i] = materials[i]; mVehicleDrivableSurfaceTypes[i].mType = i; } mSurfaceTirePairs=PxVehicleDrivableSurfaceToTireFrictionPairs::create(1, materialCount,(const PxMaterial**)drivableSurfaceMaterials,mVehicleDrivableSurfaceTypes); // You can specify the friction between each tire type, and each PxMaterial. for(int i = 0; i < materialCount; i++) { mSurfaceTirePairs->setTypePairFriction(i,0,1.0f); }
• Végül hozzáadjuk az actort a fizikai világhoz, és elvégezzük az utolsó simításokat. scene->addActor(*actor); PxVehicleDrive4W* vehDrive4W=(PxVehicleDrive4W*)car; vehDrive4W->setToRestState(); vehDrive4W->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); actor->setGlobalPose(PxTransform(~(position))); //sets Automatic or Manual gear switching car->mDriveDynData.setUseAutoGears(true);
• PhysX Actor elkészítését végzi //We need a rigid body actor for the vehicle. //Don't forget to add the actor to the scene after setting up the associated vehicle. PxRigidDynamic* vehActor=physics.createRigidDynamic(PxTransform::createIdentity());
• Elkészítjük a kerekekhez tartozó konvex héj geometriát,, majd betöltjük ezeket, és egyéb adatokat egy-egy 4 elemű tömbbe. PxConvexMeshGeometry frontLeftWheelGeom(wheelConvexMeshes[0]); PxConvexMeshGeometry frontRightWheelGeom(wheelConvexMeshes[1]); PxConvexMeshGeometry rearLeftWheelGeom(wheelConvexMeshes[2]); PxConvexMeshGeometry rearRightWheelGeom(wheelConvexMeshes[3]); const PxGeometry* wheelGeometries[WHEEL_NUM]={&frontLeftWheelGeom,&frontRightWheelGeom,&rearLeftWheelGeom,&rearRightWheelGeom}; const PxTransform wheelLocalPoses[WHEEL_NUM]={PxTransform(wheelOffsets[0]),PxTransform(wheelOffsets[1]),PxTransform(wheelOffsets[2]),PxTransf orm(wheelOffsets[3])}; const PxMaterial& wheelMaterial=material; PxFilterData wheelCollFilterData; wheelCollFilterData.word0=COLLISION_FLAG_WHEEL; wheelCollFilterData.word1=COLLISION_FLAG_WHEEL_AGAINST;
• Elkészítjük a karosszériához tartozó konvex héj geometriát, majd betöltjük ezt, és egyéb adatokat egy-egy 1 elemű tömbbe. PxConvexMeshGeometry chassisConvexGeom(chassisConvexMesh); const PxGeometry* chassisGeoms[1]={&chassisConvexGeom}; const PxTransform chassisLocalPoses[1]={PxTransform::createIdentity()}; const PxMaterial& chassisMaterial=material; PxFilterData chassisCollFilterData; chassisCollFilterData.word0= COLLISION_FLAG_CHASSIS; chassisCollFilterData.word1= COLLISION_FLAG_CHASSIS_AGAINST;
• Beállítjuk a raycastokhoz tartozó szűrési feltételeket. //Create a query filter data for the car to ensure that cars //do not attempt to drive on themselves. PxFilterData vehQryFilterData; SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData);
• Beállítjuk az actort a setupActor nevű függvény meghívásával. Ez lényegében inicializálja az actort, és hozzáveszi az actorhoz a 4 kerék és a karosszéria geometriáját. //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;
• VehicleApp.cpp::initializePhysX(): • VehicleApp.h::VehicleFilterShader(): // TODO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if(!sceneDesc.filterShader) sceneDesc.filterShader = VehicleFilterShader; //gDefaultFilterShader; //TODO END ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // TODO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if ((filterData0.word0 != 0 && filterData1.word0 != 0) && !(filterData0.word0&filterData1.word1 || filterData1.word0&filterData0.word1)) return PxFilterFlag::eSUPPRESS; //TODO END ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
• Kirajzoljuk az 5 multimesht wheel1->render(renderParameters); wheel2->render(renderParameters); wheel3->render(renderParameters); wheel4->render(renderParameters); chassis->render(renderParameters);
• Létrehozunk egy PxVehicleDrive4WRawInputData példányt, és feltöltjük a billentyűzet jelenlegi állásával, végül beadjuk a járműnek. PxVehicleDrive4WRawInputData rawInputData; rawInputData.setDigitalAccel(control_accel); rawInputData.setDigitalBrake(control_brake); rawInputData.setDigitalSteerLeft(control_steerleft); rawInputData.setDigitalSteerRight(control_steerright); rawInputData.setGearUp(control_gearup); rawInputData.setGearDown(control_geardown); PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs(gKeySmoothingData,gSteerVsForwardSpeedTable,rawInputData,dt,*car);
• Elvégeztetjük a raycastokat, majd szólunk a PhysX-nek, hogy frissítse a járművet az eltelt idővel. if(NULL==mSqWheelRaycastBatchQuery) { mSqWheelRaycastBatchQuery= mSqData->setUpBatchedSceneQuery(actor->getScene()); } PxVehicleSuspensionRaycasts(mSqWheelRaycastBatchQuery,1,vehicles,mSqData- >getRaycastQueryResultBufferSize(),mSqData->getRaycastQueryResultBuffer()); PxVehicleUpdates(dt,actor->getScene()->getGravity(),*mSurfaceTirePairs,1,vehicles);
• Frissítjük a multimeshek pozícióját és irányát, a hozzájuk tartozó PxShape-ből. const int numShapes=actor->getNbShapes(); PxShape* carShapes[WHEEL_NUM + 1]; //4 wheels + chassis actor->getShapes(carShapes,numShapes); if (~PxShapeExt::getGlobalPose(*carShapes[0]).isSane() && ~PxShapeExt::getGlobalPose(*carShapes[0]).isFinite()) {//1. kerék multimesh frissítése wheel1->setPosition(~PxShapeExt::getGlobalPose(*carShapes[0]).p); wheel1->setRotation(~PxShapeExt::getGlobalPose(*carShapes[0]).q); } //(…) Ez csak a wheel1 frissítése, a wheel2-4-ig is meg kell csinálni!… if (~PxShapeExt::getGlobalPose(*carShapes[4]).isSane() && ~PxShapeExt::getGlobalPose(*carShapes[4]).isFinite()) { //Karosszéria multimesh frissítése chassis->setPosition(~PxShapeExt::getGlobalPose(*carShapes[4]).p); chassis->setRotation(~PxShapeExt::getGlobalPose(*carShapes[4]).q); }
• Jármű berakása lua szkriptből: • (A lua szkript a Projects/gg017-Vehicle/Media mappában található) O:spawnVehicle(_, {name='GraphGameVehicle', controlState=clone(vehicleControlState), chassismultimesh='chassis', wheelmultimesh='wheel', material='default', wheelphysxmodel='pickup/wheel_physx.obj', chassisphysxmodel='pickup/pickup_physx.obj', position = {x=0, y=40, z=0}}, function(_) end )
Irányítás: numpadon 8: gáz 5: fék 4,6: balra/jobbra kanyarodás 1,3: le/felfelé váltás (auto) 7: jármű alaphelyzetbe állítása
• Járművet követő kamera: • ELŐSZÖR KIKOMMENTEZNI EZT A SORT: • Majd beírni ezt a sort: (nem lehet két kamera egyszerre) O:FixedCam(_, {name='default', attachTo='GraphGameVehicle', pos ={x=6, y=12, z=-24} } ) --O:FirstPersonCam(_, {name='default', position={x=50, y=50, z=50} } )
• Ugrató betevése: O:PhysicsEntity(_, {name='ramp', multiMesh='ramp', position={x=-50, y=9.8, z=0 }}, function(_) O:Shape(_, {geometryType='eBOX', material='default', orientationAngle= , orientationAxis={x=0, y=0, z=1}, halfExtents = {x=32.0, y=0.4, z=20}, position = { x=0, y=0, z=0 } } ) O:Drivable(_, {drivable = 1}) end)
• Zsiráfok betevése: for j=1,5 do for i=1,20 do for k=1,1 do O:PhysicsEntity(_, {name='giraffe'..i..'_'..j..'_'..k, multiMesh='giraffe', position={x=i*20, y=k*14, z=20 + j*20 }}, function(_) O:Shape(_, {geometryType='eBOX', material='default', orientationAngle=0, orientationAxis={x=0, y=1, z=0}, halfExtents = {x=2.8, y=7, z=1.4}, position = { x=0, y=0, z=0 } } ) O:Dynamics(_, {density=0.2} ) --Drivable must be used to specify a surface drivable or undrivable --This method must be called after calling Shape() and Dynamics() methods. O:Drivable(_, {drivable = 0}) end) end
• Labdák betevése: • Önálló feladat! – Elérhető egy labda objektum ( sphere.obj )