dev.nlited.com

>>

Detailed Models

<<<< prev
next >>>>

2017-12-01 21:40:20 chip Page 2076 📢 PUBLIC

Nov 30 2017

Today's task: Drive the Tiger (Importing Models) around the SimpleGrid surface.

Create the ObjTiger Class



GameObj.cpp: class ObjTiger: public GameObj { public: static HRESULT Create(GameObj *&pObj, Game *pGame, ID3D11DeviceContext *pDC); ~ObjTiger(void); void Reset(void); void Update(float secTotal, float secElapsed, Keyboard *pKB, Mouse *pMouse); void Render(ID3D11DeviceContext *pDC, const CommonStates *pStates, BasicEffect *pEffect, const XMMATRIX &view, const XMMATRIX &proj); protected: private: ObjTiger(Game *pGame); HRESULT Create2(ID3D11DeviceContext *pDC); //Data float Scale; //Scale from model units to grid units. Vector3 pos; //Position Vector3 dir; //Direction std::unique_ptr<DirectX::Model> pModel; };
/*************************************************************************/ /** Tiger tank (detailed model) **/ /*************************************************************************/ ObjTiger::ObjTiger(Game *_pGame): GameObj(_pGame) { Scale= 1.0f/4000.0f; } ObjTiger::~ObjTiger(void) { } HRESULT ObjTiger::Create(GameObj *&_pObj, Game *_pGame, ID3D11DeviceContext *pDC) { HRESULT Err= 0; ObjTiger *pObj; if(!(pObj= new ObjTiger(_pGame))) { Err= Warn(ERROR_NO_MEM,"ObjTiger:Create: NoMem(%d)",sizeof(*pObj)); } else if(FAILED(Err= pObj->Create2(pDC))) { delete pObj; } else { _pObj= pObj; } return(Err); } HRESULT ObjTiger::Create2(ID3D11DeviceContext *pDC) { HRESULT Err= 0; std::unique_ptr<DirectX::IEffectFactory> pFXfactory; ID3D11Device *pDevice; pDC->GetDevice(&pDevice); pFXfactory= std::make_unique<EffectFactory>(pDevice); pModel= Model::CreateFromSDKMESH(pDevice,L"Tiger.sdkmesh",*pFXfactory); return(Err); } void ObjTiger::Reset(void) { } void ObjTiger::Update(float secTotal, float secElapsed, Keyboard *pKB, Mouse *pMouse) { xform = Matrix::Identity; VertexPositionNormalColor vtxPos; pGame->getVertex(pos.x,pos.z,vtxPos); pos.y= vtxPos.position.y; xform*= Matrix::CreateScale(Scale); xform.Translation(pos); } void ObjTiger::Render(ID3D11DeviceContext *pDC, const CommonStates *pStates, BasicEffect *pEffect, const XMMATRIX &view, const XMMATRIX &proj) { GameObj::Render(pDC,pStates,pEffect,view,proj); pModel->Draw(pDC,*pStates,xform,view,proj); }

The Model needs to call the EffectFactory, but since this is a global object I keep a local reference to it inside ObjTiger rather than add yet another parameter to the Create().

The Tiger model is roughly 2000 units long and needs to be scaled down to fit in the 5x5 grid space.

The original Tiger.obj model uses Z=UP. I can use meshconvert to flip the axes. The textures are not right, especially around the engine compartment. This was fixed with the "-flip" option to reverse the winding order of the faces. A scaling factor of 1/20,000 makes it small enough to drive around.
meshconvert -flipz -flip -y Tiger.obj

Direct3D Models Direct3D Models Direct3D Models Direct3D Models Direct3D Models Direct3D Models

Driving the Tiger means adding a new control mode. I'll use digits to select the object being controlled, with '`' (tilde) selecting the world and '1' selecting Tiger #1. In Tiger mode, the AWSD keys will rotate left, drive forward, drive backward, and rotate right. Yaw will be the forward direction while pitch and roll will be determined by the surface normal.

Getting the Transforms Right

This took about two hours as I tried to wrap my head around matrix math. There are a couple things happening at the same time, and they are all rolled into a single transformation matrix.

This all happens in ObjTiger::Update(). First update the direction and position in the grid: the A key rotates left (counter-clockwise, +), the D key rotates right (clockwise, -). The W key moves forward, the S key moves backward. Keep in mind the grid is in the XZ plane with 0° pointing down the Z axis.

Direct3D Models

void GameObj::Move(float dist) { float hdg= dir.y; pos.x+= dist*sinf(hdg); pos.z+= dist*cosf(hdg); } ... void ObjTiger::Update(float secTotal, float secElapsed, Keyboard *pKB, Mouse *pMouse) { if(pGame->ctrlObjID==CTRL_TIGER) { Keyboard::State kb= pKB->GetState(); if(kb.A) dir.y+= secElapsed*0.10f; if(kb.D) dir.y-= secElapsed*0.20f; if(kb.W) Move(secElapsed*0.20f); if(kb.S) Move(-secElapsed*0.05f); } }

After the direction and position have been updated I can recreate the new transformation matrix:

I was confused for a while with the order for the transforms operations. The model is first rotated around the origin, then scaled, with the translation applied last. My first version of ObjTiger also included accidental duplicates of pos and dir, which helped to confound me.

This code lets me drive the tank around from a 3rd person perspective. I am applying the surface elevation but not the normals.

ObjTiger: /*************************************************************************/ /** GameObj **/ /*************************************************************************/ #define CTRL_TIGER 100 class GameObj { public: static HRESULT Create(GameObj *&pObj, const char *Type, Game *pGame, ID3D11DeviceContext *pDC); // Create a new game object. //OUT pObj Receives a ptr to the new game object. //IN Type Object type, one of "SUN", "PAWN". //IN pGame Ptr to the global Game object. //IN pDC GPU device context. //Ret Err Error code. //Notes: pGame must remain valid for the lifetime of the game object. //pDC is used only to create the object. static void Destroy(GameObj *&pObj); // Release game object resources and delete the object. virtual ~GameObj(void); // Auto-destructor. Implicitly calls Destroy() virtual void Reset(void); // Release all DirectX resources. virtual void SetPosition(const Vector3 &pos); // Sets the object's position in the world. virtual void Move(float dist); // Move a distance in the current direction. void SetWireFrame(bool doWireFrame); // Sets the draw mode. virtual void Update(float secTotal, float secElapsed, Keyboard *pKB, Mouse *pMouse); // Updates the object based on time, keyboard, and mouse. virtual void Render(ID3D11DeviceContext *pDC, const CommonStates *pStates, BasicEffect *pEffect, const XMMATRIX &view, const XMMATRIX &proj); // Renders the object. protected: GameObj(Game *pGame); Game *pGame; //Data Vector3 pos; //Current position Vector3 vel; //Current velocity Vector3 dir; //Face: x=roll y=yaw z=pitch Matrix xform; //Transform matrix bool doWireFrame; //Render as wireframe? Vector3 clrShape; //Shape color private: }; class ObjTiger: public GameObj { public: static HRESULT Create(GameObj *&pObj, Game *pGame, ID3D11DeviceContext *pDC); ~ObjTiger(void); void Reset(void); void Update(float secTotal, float secElapsed, Keyboard *pKB, Mouse *pMouse); void Render(ID3D11DeviceContext *pDC, const CommonStates *pStates, BasicEffect *pEffect, const XMMATRIX &view, const XMMATRIX &proj); protected: private: ObjTiger(Game *pGame); HRESULT Create2(ID3D11DeviceContext *pDC); //Data float Scale; //Scale from model units to grid units. std::unique_ptr<DirectX::Model> pModel; }; void GameObj::Move(float dist) { float hdg= dir.y; pos.x+= dist*sinf(hdg); pos.z+= dist*cosf(hdg); } /*************************************************************************/ /** Tiger tank (detailed model) **/ /*************************************************************************/ ObjTiger::ObjTiger(Game *_pGame): GameObj(_pGame) { Scale= 1.0f/20000.0f; } ObjTiger::~ObjTiger(void) { } HRESULT ObjTiger::Create(GameObj *&_pObj, Game *_pGame, ID3D11DeviceContext *pDC) { HRESULT Err= 0; ObjTiger *pObj; if(!(pObj= new ObjTiger(_pGame))) { Err= Warn(ERROR_NO_MEM,"ObjTiger:Create: NoMem(%d)",sizeof(*pObj)); } else if(FAILED(Err= pObj->Create2(pDC))) { delete pObj; } else { _pObj= pObj; } return(Err); } HRESULT ObjTiger::Create2(ID3D11DeviceContext *pDC) { HRESULT Err= 0; std::unique_ptr<DirectX::IEffectFactory> pFXfactory; ID3D11Device *pDevice; pDC->GetDevice(&pDevice); pFXfactory= std::make_unique<EffectFactory>(pDevice); pModel= Model::CreateFromSDKMESH(pDevice,L"Tiger.sdkmesh",*pFXfactory); return(Err); } void ObjTiger::Reset(void) { } void ObjTiger::Update(float secTotal, float secElapsed, Keyboard *pKB, Mouse *pMouse) { xform = Matrix::Identity; if(pGame->ctrlObjID==CTRL_TIGER) { Keyboard::State kb= pKB->GetState(); if(kb.A) dir.y+= secElapsed*0.10f; if(kb.D) dir.y-= secElapsed*0.20f; if(kb.W) Move(secElapsed*0.20f); if(kb.S) Move(-secElapsed*0.05f); } VertexPositionNormalColor vtxPos; pGame->getVertex(pos.x,pos.z,vtxPos); pos.y= vtxPos.position.y; xform*= Matrix::CreateFromYawPitchRoll(XMConvertToRadians(-90.0f),0,0); xform*= Matrix::CreateFromYawPitchRoll(dir.y,dir.z,dir.x); xform*= Matrix::CreateScale(Scale); xform.Translation(pos); } void ObjTiger::Render(ID3D11DeviceContext *pDC, const CommonStates *pStates, BasicEffect *pEffect, const XMMATRIX &view, const XMMATRIX &proj) { GameObj::Render(pDC,pStates,pEffect,view,proj); pModel->Draw(pDC,*pStates,xform,view,proj); }


WebV7 (C)2018 nlited | Rendered by tikope in 51.215ms | 3.137.178.122