380 likes | 487 Views
Fizikai szimul áció - járművek. Grafikus játékok fejlesztése Szécsi László Bendefy Zoltán 201 3 .05.07 . t14 a - pxvehicle. Járművek a PhysX-ben. PhysX ismétlés. A zsiráf betöltésekor egy doboz objektumot regisztrálunk a PhysX-ben. A PhysX ezen ütközést, gravitációt számol.
E N D
Fizikaiszimuláció - járművek Grafikus játékok fejlesztése Szécsi László Bendefy Zoltán 2013.05.07. t14a-pxvehicle
PhysX ismétlés A zsiráf betöltésekor egy doboz objektumot regisztrálunk a PhysX-ben A PhysX ezen ütközést, gravitációt számol Rendereléskor elkérjük a PhysX-tőla doboz helyét, és irányát majd ezzel frissítjük a zsiráf modellt A színtér animálásakor meg kell hívni a PhysXsimulate(floatdt) függvényét, ami szimulálja a fizikai világot (ütközést számol, gravitációt alkalmaz, stb.)
PhysX ismétlés PxShape PxScene PxActor 1 * 1 * PxShape
PhysX ismétlés • A fizikai actorokon erőt, impulzust is alkalmazhatunk (pl. a bowling golyón) F
PhysX ismétlés 3D motor vs. Fizikai világ
Járművek a PhysX-ben • Járművek létrehozása az eddig ismert eszközökkel (merevtestek, ízületek, erők) nehézkes (közelítések, pontatlanságok miatt).
Járművek a PhysX-ben • Első közelítésben: • Legyen egy téglatestünk, tegyünk rá 4 db hengert egy-egy forgó ízülettel.Hajtsuk meg a kerekeket forgatónyomatékkal! • És a rugózás? • És a fékek? • És a sebességváltó? • És a tankok? • Használjuk inkább aPhysXVehicleSDK-t!
Járművek felépítése - áttekintés • Mit támogat a PhysXVehicle SDK? • 4 kerekű járművek (ezzel foglalkozunk) • N kerekű járművek • N kerekű Lánctalpas járművek (tankok)
Járművek felépítése - áttekintés • Mit támogat a PhysXVehicle SDK? • Realisztikus járműszimuláció • Ackermann kormányzási geometria • Motor, fék, kézifék, sebességváltó, kuplung • Felfüggesztés (rugózás), differenciálmű, abroncstípusok (téli gumi, stb.) • Mindezeket szabadon paraméterezhetjük!
Járművek felépítése - áttekintés • Járművek a VehicleSDK-ban:
Járművek felépítése - áttekintés • A PxShape-ek tartalmazzák az egyes részek geometriáját: 4 kerék és egy karosszéria • A PxShape önmagában csak egy geometria, nem egy fizikai szereplő
Járművek felépítése - áttekintés • PxRigidDynamic– Ez az Actor, aki az járművet mint fizikai objektumot reprezentálja a fizikai világban. A PhysX az Actorokra számol fizikai hatásokat, őket ütközteti. • Az actor több PxShape-et tartalmazhat:
Járművek felépítése - áttekintés • PxVehicleDrive4W – Adatstruktúra, ez tárolja a jármű paramétereit és a dinamikus tulajdonságait • Paraméterek: motor erőssége és fordulatszáma, váltók száma, fékek ereje, stb. • Dinamikus tulajdonságok: aktuális sebesség, aktuális súrlódás a kerekeken, motor sebessége, stb.
Járművek felépítése - áttekintés • A motorban egy VehicleEntityosztályként fog megjelenni a jármű.
Járművek felépítése - áttekintés • Az actor 5 PxShape alakzatához (4 kerék + karosszéria) tartozni fog egy-egy MultiMesh, ezek fognak megjelenni a képernyőn. • A MultiMesheket, a fizikai actort, és a jármű Adatstruktúráját egy VehicleEntity nevű osztályban foglaljuk össze. • VehicleEntity->render() ez ki fogja renderelni mind az 5 MultiMesh-t • VehicleEntity->animate() ez fogja frissíteni a MultiMesh-ek pozícióját és irányát a PhysX oldalról kinyert adatokkal.
Járművek felépítése - áttekintés Fizikai világ (PxShape) 3D-s motor (MultiMesh) Pozíció, irány Pozíció, irány
Járművek felépítése – lépések 1) Vehicle SDK, filter shader és Cooking inicializálása a PhysX inicializálása után: Filter shader és Cookinglib később… physics= PxCreatePhysics(…); (…) PxSceneDescsceneDesc(physics->getTolerancesScale()); (…) sceneDesc.filterShader= VehicleFilterShader; //gDefaultFilterShader; scene = physics->createScene(sceneDesc); cookinglib = PxCreateCooking(PX_PHYSICS_VERSION, *foundation, PxCookingParams()); PxInitVehicleSDK(*physics);
Járművek felépítése – lépések 2) Luából hívható C++ függvény, amely felépít egy járművet: spawnVehicle() A következő lépésekben (3.-8.) ennek a felépítő függvénynek a tartalmát nézzük végig! 3) A járműhoz tartozó MultiMesh-ek elkészítése (a 4 kerék + karosszéria) Mesh::Multi::P echassis, ewheel; chassis= StaticPartEntity::create(echassis); wheel1 = StaticPartEntity::create(ewheel); (…) wheel4 = StaticPartEntity::create(ewheel);
Járművek felépítése – lépések 4) PxShape-k(azaz a fizikai alakzatok) elkészítése a 4 kerékhez, és a karosszériához. • Ennél a lépésnél szükség van a PhysXCookingLibrary-re. • CookingLibrary: háromszögháló vagy konvex burok alapú geometriát tud létrehozni. • A CookingaPhysX számára hatékony formátumra hozza a geometriát
Járművek felépítése – lépések • Konvex burok: • Olyan háromszögháló, amely a legszűkebben illeszkedik az eredeti háromszöghálóra úgy, hogy még konvex maradjon (csomagolófólia). • Hatékony vele számolni, könnyen generálható
Járművek felépítése – lépések • Esetünkben a 4 kerék és a karosszéria háromszöghálói konvexek, így nem fognak megváltozni a konvex burok képzés során.
Járművek felépítése – lépések • Konvex burok készítés kódja constaiScene* assScene = importer.ReadFile( name, 0); //AssImppel betöltjük a modellt PxVec3* buffer; //vertexeket tartalmazó tömb, az Assimpból kinyert vertexekkel kell feltölteni (…) PxConvexMeshDescconvexDesc; convexDesc.points.count= assScene->mMeshes[0]->mNumVertices; //Vertexek száma convexDesc.points.stride = sizeof(PxVec3); //Vertexek mérete (4*3=12 bájt) convexDesc.points.data = buffer; //Egy float tömb amely a vertexeket tartalmazza convexDesc.flags= PxConvexFlag::eCOMPUTE_CONVEX; (…) MemoryOutputStreambuf; if(cookinglib->cookConvexMesh(convexDesc, buf)) { MemoryInputDataCustom input(buf.getData(), buf.getSize()); convexMesh= scene->getPhysics().createConvexMesh(input); }
Járművek felépítése – lépések • 5) Szimulációs adatok feltöltése egy descriptorba • Ebben a lépésben adjuk meg a jármű adatait. • Például a motor erősségének megadása: PxVehicleDriveSimData4W& driveData (…) //Engineproperties PxVehicleEngineDataengine; engine.mPeakTorque = 700.0f; // Nm (Newton metre) default: 3000 engine.mMaxOmega = 600.0f; //default: 600=approx 6000 rpm driveData.setEngineData(engine); //Brakemaxtorque wheels[PxVehicleDrive4W::eFRONT_LEFT_WHEEL].mMaxBrakeTorque = 9000.0f; //Suspension PxVehicleSuspensionDatasusps[WHEEL_NUM]; susps[0].mSpringStrength= 2200.0f;
Járművek felépítése – lépések 6) Actor beállítása • Ez reprezentálja az autót mint fizikai objektumot. • Létre kell hozni, és be kell kötni a PxShape geometriákat (4 kerék + karosszéria) 7) Járművet leíró adatstruktúra elkészítése az (5.) pontban létrehozott descriptor alapján. car = PxVehicleDrive4W::allocate(4); car->setup(&(scene->getPhysics()), actor, *wheelsSimData, driveSimData, 0);
Járművek felépítése – lépések 8) Vezethető felületek beállítása A meglévő fizikai anyagtulajdonságokhoz (PxMaterial) meg lehet adni egy súrlódási tényezőt. Pl.: aszfaltút: 0.95 jégmező: 0.3 Különböző gumitípusokat is definiálhatunk, egyedi súrlódás értékekkel. Pl.: téli gumi jobban tapad a jeges úton for(int i = 0; i < materialCount; i++) { mSurfaceTirePairs->setTypePairFriction(i, 0, 0.3f); //jeges út beállítása }
Járművek felépítése – lépések • 9) Filter shader beállítása • A járművet egy rugózás (suspension) tartja szintben • A PhysX minden frissítéskor egy Raycast-tal megnézi, hogy milyen messze van a talaj az egyes kerekektől, és aszerint alkalmazza a rugóerőket. • Valahogy meg kell tiltanunk, hogy a kerék ütközzön a talajjal, hogy ez működjön! • Erre szolgál a Filter shader! • Lényegében egy C++ oldali függvény, amely lefut minden ütközés előtt az ütköző objektumpárokra, és eldönti, hogy az ütközés érvényre jut-e. • Ehhez általunk beállított flageket használhat.
Járművek felépítése – lépések Filter shaderben írhatunk egy saját függvényt, amely eldönti két objektumról (azok flagei alapján), hogy azok ütközhetnek-e. Először meg kell adni valami megkülönböztetést (flaget): A COLLISION_FLAG_xxxegy típus azonosító A COLLISION_FLAG_xxx_AGAINST adja meg, hogy az xxx típusú objektumok mivel ütközhetnek A filter shaderben ezen flagek alapján szűrjük ki az ütközéseket! enum { COLLISION_FLAG_GROUND = 1 << 0, //a talajnál ezt tesszük a word0 nevű flagbe COLLISION_FLAG_WHEEL = 1 << 1,//a kerekeknél ezt tesszüka word0 nevű flagbe COLLISION_FLAG_CHASSIS = 1 << 2,//a karosszériánál ezt tesszük a word0 nevű flagbe COLLISION_FLAG_OBSTACLE = 1 << 3,//egyéb objektumoknál ezt tesszük a word0 nevű flagbe //A talajhoz ezt a flaget rendeljük a word1 nevű flagbe. //Jelentése: a talaj csak a karosszériával és egyéb objektumokkal ütközhet. COLLISION_FLAG_GROUND_AGAINST = COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE (…) };
Járművek felépítése – lépések • Ezek után a Filter Shader kódja: • Megyjegyzés: • filterData0 és filterData1 a két objektum amely épp ütközik • Word0 és word1 az objektum két flagje(ld. Előző dia) staticPxFilterFlagsVehicleFilterShader(…) { (…) if ((filterData0.word0 != 0 && filterData1.word0 != 0) && !(filterData0.word0 & filterData1.word1 || filterData1.word0 & filterData0.word1)) returnPxFilterFlag::eSUPPRESS; (…) }
9+1) A már meglévő fizikai objektumok beállítása (pl.: talaj) PxFilterDatasimFilterData; PxFilterDataqryFilterData; //Talaj esetén (lehet rajta vezetni, nem ütközik a kerékkel) simFilterData.word0=COLLISION_FLAG_GROUND; simFilterData.word1=COLLISION_FLAG_GROUND_AGAINST; qryFilterData.word3 = (PxU32)(SAMPLEVEHICLE_DRIVABLE_SURFACE); //Dinamikus objektunok esetén (nem lehet rajta vezetni, ütközik a kerékkel) simFilterData.word0=COLLISION_FLAG_DRIVABLE_OBSTACLE; simFilterData.word1=COLLISION_FLAG_DRIVABLE_OBSTACLE_AGAINST; qryFilterData.word3 = (PxU32)(SAMPLEVEHICLE_UNDRIVABLE_SURFACE); //A fizikai actor minden shape-jére: shapes[i]->setSimulationFilterData(simFilterData); shapes[i]->setQueryFilterData(qryFilterData);
Jármű kirajzolása és animálása • Kirajzolás: Egyszerűen kirajzoljuk az 5 MultiMesh-t wheel1->render(renderParameters); wheel2->render(renderParameters); wheel3->render(renderParameters); wheel4->render(renderParameters); chassis->render(renderParameters);
Jármű kirajzolása és animálása 2) Animálás: input bekötése Ezeket a változókat Lua-ból állítjuk be. Lua-ból a billentyűeseményekre beregisztáljuk a DriveVehicle() nevű C++ oldali függvényt, amely beállítja a fenti boolértékeket: boolcontrol_accel; boolcontrol_brake; boolcontrol_steerleft; boolcontrol_steerright; vehicleControlState = { script = function(entity, state) ifkeysPressed.VK_NUMPAD8 == truethen O:driveVehicle(entity, { brake=0, accelerate = 1 } ) end end }
Jármű kirajzolása és animálása Ezután, ha megvannak a vezérlő bool értékek: A PxVehicleDrive…() függvény szűri, kisimítja a beadott értékeket, majd alkalmazza őket a járműre. PxVehicleDrive4WRawInputData rawInputData; rawInputData.setDigitalAccel(control_accel); rawInputData.setDigitalBrake(control_brake); rawInputData.setDigitalSteerLeft(control_steerleft); rawInputData.setDigitalSteerRight(control_steerright); PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs(gKeySmoothingData,gSteerVsForwardSpeedTable,rawInputData,dt,*car);
Jármű kirajzolása és animálása 3) Raycastok számítása, jármű frissítése if(NULL == mSqWheelRaycastBatchQuery) { mSqWheelRaycastBatchQuery= mSqData->setUpBatchedSceneQuery(actor->getScene()); } PxVehicleSuspensionRaycasts(…); PxVehicleUpdates(dt,actor->getScene()->getGravity(),*mSurfaceTirePairs,1,vehicles);
Jármű kirajzolása és animálása 4) MultiMesh-ek pozíciójának beállítása //Elkérjük az actortól mind az 5 Shape-t constint numShapes=actor->getNbShapes(); PxShape* carShapes[WHEEL_NUM + 1]; //4 wheels + chassis actor->getShapes(carShapes,numShapes); wheel1->setPosition(~PxShapeExt::getGlobalPose(*carShapes[0]).p); wheel1->setRotation(~PxShapeExt::getGlobalPose(*carShapes[0]).q); wheel2->setPosition(~PxShapeExt::getGlobalPose(*carShapes[1]).p); wheel2->setRotation(~PxShapeExt::getGlobalPose(*carShapes[1]).q); (…)