Motor IIII. PhysX utáni rendberakás Vezérlés Szécsi László
Űrhajók physX-xel írjuk át a korábbi xml-t PhysicsEntity-kre hasaljunk be valami közelítő geometriát (pl. NxCapsuleShape)
PhysX remote debugger nxPhysicsSDK = NxCreatePhysicsSDK( NX_PHYSICS_SDK_VERSION); // Hook the Application with the Visual Debugger nxPhysicsSDK-> getFoundationSDK(). getRemoteDebugger()-> connect ("localhost", 5425);
Entity metódusai mindet valósítsuk meg a PhysicsEntity-ben trafo lekérdezése az Actortól (lásd render metódus) ebből a kért trafó számítása kb. ugyanúgy mint az Entityben
idáig önálló munka a vezérléssel folytatjuk
Hajó közelítő geometriája
Új mechanizmus: vezérlés XML fileban definálható vezérlő Controller osztály EngineCore-ba directory PhysicsEntity-be hivatkozás egy vezérlőre Controller-ből származtatás –MotorController –TargetController betöltés
Új class: ControlStatus class ControlStatus { public: /// Array of key pressed state variables. Addressed by virtual key codes, true if key is pressed. bool keyPressed[0xff]; /// Mouse pointer position in normalized screen space. D3DXVECTOR3 mousePosition; /// Pressed state variable of left, center and right mouse buttons. bool mouseButtonPressed[3]; /// Screen width. Not set by constructor. unsigned int screenWidth; /// Screen height. Not set by constructor. unsigned int screenHeight; /// Updates input state by processing message. virtual void handleInput(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); /// Constructor. Intializes input state. ControlStatus(); };
ControlStatus.cpp #include "DXUT.h" #include "ControlStatus.h" ControlStatus::ControlStatus() { for(unsigned int i=0; i<0xff; i++) keyPressed[i] = false; mouseButtonPressed[0] = false; mouseButtonPressed[1] = false; mouseButtonPressed[2] = false; mousePosition = D3DXVECTOR3(0, 0, 0); } void ControlStatus::handleInput(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg == WM_KEYDOWN) keyPressed[wParam] = true; else if(uMsg == WM_KEYUP) keyPressed[wParam] = false; else if(uMsg == WM_KILLFOCUS) { for(unsigned int i=0; i<0xff; i++) keyPressed[i] = false; } else if(uMsg == WM_MOUSEMOVE) { POINT pixPos; if(GetCursorPos(&pixPos)) mousePosition = D3DXVECTOR3((double)pixPos.x / screenWidth * , (double)pixPos.y / screenHeight * , 0); }
Új class: ControlContext #pragma once class ControlStatus; class Node; class ControlContext { public:const ControlStatus& controlStatus; /// Time step. double dt; /// Scene graph reference for interaction computations. Node* interactors; ControlContext(const ControlStatus& controlStatus, double dt, Node* interactors) :controlStatus(controlStatus) { this->dt = dt; this->interactors = interactors; } };
EngineCore-ba tagváltozó // #include "ControlStatus.h" ControlStatus status;
EngineCore::processMessage-be status.handleInput(hWnd, uMsg, wParam, lParam);
Új inline class: Controller #pragma once class PhysicsEntity; #include "ControlContext.h" /// Base class for rigid body control mechanisms. class Controller { public: /// Applies control to the actor. Invoked from PhysicsEntity::control, directly manipulates kinematic status. virtual void apply(PhysicsEntity* controlledEntity, const ControlContext& context)=0; };
PhysicsEntity-be class Controller; class PhysicsEntity : public Entity { Controller* controller; public: void setController(Controller* controller);
PhysicsEntity.cpp void PhysicsEntity::setController( Controller* controller) { this->controller = controller; } PhysicsEntity::PhysicsEntity(…) :Entity(shadedMesh) { controller = NULL;
Alkalmazzuk #include "Controller.h" void PhysicsEntity::control(const ControlContext& context){ if(controller) controller->apply(this, context); }
Directory.h class Controller; typedef std::map ControllerDirectory; Mielőtt be tudnánk tölteni valamit kell egy konkrét vezérlő
XML: ezt szeretnénk betölteni <Motor key="5" codeType="numpad" force.x="35" force.y="0" force.z="0" /> <Motor key="0" codeType="numpad" force.x="-35" force.y="0" force.z="0" /> <Motor key="7" codeType="numpad" torque.x="1" torque.y="0" torque.z="0" /> <Motor key="9" codeType="numpad" torque.x="-1" torque.y="0" torque.z="0" /> <Motor key="6" codeType="numpad" torque.x="0" torque.y="1" torque.z="0" /> <Motor key="4" codeType="numpad" torque.x="0" torque.y="-1" torque.z="0" /> <Motor key="8" codeType="numpad" torque.x="0" torque.y="0" torque.z="1" /> <Motor key="2" codeType="numpad" torque.x="0" torque.y="0" torque.z="-1" />
XML … …
Új class: MotorController base: Controller #include "Controller.h" class Motor; class MotorController : public Controller { /// Container of Motor instances. std::vector motors; public: /// Constructor. MotorController(void); /// Destructor. Releases Motor instances. ~MotorController(void); /// Inserts a motor. void addMotor(Motor* motor); void apply(PhysicsEntity* controlledEntity, const ControlContext& context); };
Új class: Motor class Motor { friend class MotorController; friend class WheelController; /// Activating key. unsigned int key; /// Force applied by motor. NxVec3 force; /// Torque applied by motor. NxVec3 torque; public: /// Constructor. Motor(unsigned int key, const NxVec3& force, const NxVec3& torque); };
Motor.cpp Motor::Motor(unsigned int key, const NxVec3& force, const NxVec3& torque) { this->key = key; this->force = force; this->torque = torque; }
MotorController.cpp #include "MotorController.h" #include "PhysicsEntity.h" #include "PhysicsModel.h" #include "Motor.h" #include "ControlStatus.h" MotorController::MotorController(void){} MotorController::~MotorController(void) { std::vector ::iterator i = motors.begin(); while(i != motors.end()) { delete *i; i++; } void MotorController::addMotor(Motor* motor) {motors.push_back(motor); }
MotorController.cpp void MotorController::apply(PhysicsEntity* controlledEntity, const ControlContext& context) { std::vector ::iterator i = motors.begin(); while(i != motors.end()) { Motor* motor = *i; if(context.controlStatus.keyPressed[motor->key]) { NxActor* actor = controlledEntity->getActor(); actor->addLocalForce(motor->force); actor->addLocalTorque(motor->torque); } i++;}
EngineCore-ba class MotorController; //class előtt ControllerDirectory controllerDirectory; void loadMotorControllers( XMLNode& xMainNode); void loadMotors( XMLNode& motorControllerNode, MotorController* motorController);
EngineCore.cpp #include "MotorController.h" #include "Motor.h"
EngineCore.cpp void EngineCore::loadMotorControllers(XMLNode& xMainNode) { int iMotorController = 0; XMLNode motorControllerNode; while( !(motorControllerNode = xMainNode.getChildNode(L"MotorController", iMotorController)).isEmpty() ) { const wchar_t* motorControllerName = motorControllerNode|L"name"; MotorController* motorController = new MotorController(); loadMotors(motorControllerNode, motorControl); controllerDirectory[motorControllerName] = motorController; iMotorController++; }
EngineCore.cpp void EngineCore::loadMotors(XMLNode& motorControllerNode, MotorControl* motorControl) { int iMotor = 0; XMLNode motorNode; while( !(motorNode = motorControllerNode.getChildNode(L"Motor", iMotor)).isEmpty() ) { NxVec3 force = motorNode.readNxVec3(L"force"); NxVec3 torque = motorNode.readNxVec3(L"torque"); unsigned int keyCode = motorNode.readLong(L"key"); const wchar_t* codeTypeString = motorNode|L"codeType"; if(codeTypeString && wcscmp(codeTypeString, L"numpad") == 0) keyCode += VK_NUMPAD0; else if(codeTypeString && wcscmp(codeTypeString, L"function") == 0) keyCode += VK_F1; motorController->addMotor( new Motor(keyCode, force, torque)); iMotor++; }
EngineCore::loadLevel loadMotorControllers(xMainNode); //loadGroup elé
EngineCore::loadPhysicsEntities PhysicsEntity* physicsEntity = new PhysicsEntity(iShadedMesh->second, iPhysicsModel->second, nxScene, position); const wchar_t* controllerName = physicsEntityNode|L"controller"; if(controllerName){ ControllerDirectory::iterator iController = controllerDirectory.find(controllerName); if(iControler != controllerDirectory.end()) physicsEntity-> setController(iControl->second); }
Mehet! Nehéz dolog az űrhajó-irányítás…
Legyen "légellenállás" Sebességfüggő csillapítás <PhysicsModel name="ship" drag="1" angularDrag="5" />
PhysicsModel-be public: void setDrag(doubledrag); void setAngularDrag( double angularDrag);
PhysicsModel.cpp void PhysicsModel::setDrag(double drag) { nxActorDesc.body->linearDamping = drag; } void PhysicsModel::setAngularDrag( double angularDrag) { nxActorDesc.body->angularDamping = angularDrag; }
EngineCore::loadPhysicsModels physicsModel->setDrag( physicsModelNode.readDouble(L"drag") ); physicsModel->setAngularDrag( physicsModelNode. readDouble(L"angularDrag"));
Mehet! Így már könnyebb.
XML
Új class: Target class Entity; class Target { friend class TargetController; D3DXVECTOR3 position; double radius; Entity* mark; public: Target(const D3DXVECTOR3& position, double radius); void setMark(Entity* mark); };
Target.cpp Target::Target(const D3DXVECTOR3& position, double radius) { mark = NULL; this->radius = radius; this->position = position; } void Target::setMark(Entity* mark) { this->mark = mark; }
Új class: TargetController #include class Target; class TargetController : public Controller { std::vector targets; std::vector ::iterator currentTarget; double maxForce; double maxTorque; public: TargetControl(double maxForce, double maxTorque); ~TargetControl(void); void addTarget(Target* target); void apply(PhysicsEntity* controlledEntity, const ControlContext& context); };
TargetController.cpp TargetController::TargetController(do uble maxForce, double maxTorque) { currentTarget = targets.end(); this->maxForce = maxForce; this->maxTorque = maxTorque; }
TargetController.cpp void TargetController::addTarget(Target* target) { targets.push_back(target); currentTarget = targets.begin(); } TargetController::~TargetController(void) { std::vector ::iterator i = targets.begin(); while(i != targets.end()) { delete *i; i++; }
TargetController::apply void TargetController::apply(PhysicsEntity* controlledEntity, const ControlContext& context) { if(!targets.empty()) { Target* target = *currentTarget; D3DXVECTOR3 markDifference = target->position - controlledBody->position; if(target->mark) markDifference += target->mark->getPosition(); if(D3DXVec3Length(&markDifference) radius) { currentTarget++; if(currentTarget == targets.end()) currentTarget = targets.begin(); }
TargetController::apply D3DXVECTOR3 markDirection; D3DXVec3Normalize(&markDirection, &markDifference); D3DXMATRIX modelMatrix; controlledBody->getModelMatrix(modelMatrix); D3DXVECTOR3 ahead; D3DXVec3TransformNormal(&ahead, &D3DXVECTOR3(1, 0, 0), &modelMatrix); D3DXVECTOR3 turnAxis; D3DXVec3Cross(&turnAxis, &ahead, &markDirection); controlledEntity->getActor()->addTorque(*(NxVec3*)&( turnAxis * maxTorque); controlledEntity->getActor()- >addForce(*(NxVec3*)&(ahead * D3DXVec3Dot(&ahead, &markDirection) * maxForce); }
EngineCore // vezérlők legyártása entitások betöltése előtt void loadTargetControllers(XMLNode& xMainNode); // célpontok bekötése entitások betöltése után void finishTargetControllers(XMLNode& xMainNode); void loadTargets(XMLNode& targetControllerNode, TargetController* targetController);
EngineCore::loadTargetControllers void EngineCore::loadTargetControllers(XMLNode& xMainNode) { int iTargetController = 0; XMLNode targetControllerNode; while( !(targetControllerNode = xMainNode.getChildNode(L"TargetController", iTargetController)).isEmpty() ) { const wchar_t* targetControllerName = targetControllerNode|L"name"; TargetController* targetController = new TargetController( targetControllerNode.readDouble(L"maxForce"), targetControllerNode.readDouble(L"maxTorque")); controllerDirectory[targetControllerName] = targetController; iTargetController++; }
EngineCore:: finishTargetControllers void EngineCore::finishTargetControllers(XMLNode& xMainNode) { int iTargetController = 0; XMLNode targetControllerNode; while( !(targetControllerNode = xMainNode.getChildNode(L"targetController", iTargetController)).isEmpty() ) { const wchar_t* targetControllerName = targetControllerNode|L"name"; TargetController* targetController = (TargetController*)controlDirectory [targetControllerName]; loadTargets(targetControllerNode, targetController); iTargetControl++; }
EngineCore::loadTargets void EngineCore::loadTargets(XMLNode& targetControlNode, TargetController* targetController) { int iTarget = 0; XMLNode targetNode; while( !(targetNode = targetControllerNode.getChildNode(L"Target", iTarget)).isEmpty() ) { D3DXVECTOR3 pos = targetNode.readVector(L"position"); double radius = targetNode.readDouble(L"radius", 10); Target* target = new Target(pos, radius); const wchar_t* markEntityName = targetNode|L"mark"; if(markEntityName != NULL) { EntityDirectory::iterator iEntity = entityDirectory.find(markEntityName); if(iEntity != entityDirectory.end()) target->setMark(iEntity->second); } targetController->addTarget(target); iTarget++; }
EngineCore::loadLevel loadTargetControllers(xMainNode); XMLNode groupNode = xMainNode.getChildNode(L"Group"); sceneRoot = NULL; loadGroup(groupNode, sceneRoot); finishTargetControllers(xMainNode);
XML