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
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.
After the direction and position have been updated I can recreate the
new transformation matrix:
Start with the identity matrix xform = Matrix::Identity;
The (x,z) point needs to be interpolated to a grid(x,y,z) vertex pGame->getVertex(pos.x,pos.z,vtxPos);
pos.y= vtxPos.y;
The model was constructed with the barrel facing "north". It
needs to be rotated 90° clockwise so the barrel is
pointing along the +Z axis, which corresponds to a heading of 0. xform*= Matrix::CreateFromYawPitchRoll(XMConvertToRadians(-90.0f),0,0);
Rotate again to align with the current heading. Only the heading
(yaw, rotation around the y axis) is non-zero. I am not handling pitch
and roll yet. xform*= Matrix::CreateFromYawPitchRoll(dir.y,dir.z,dir.x);
Scale the model down by a factor of 1/20,000 xform*= Matrix::CreateScale(Scale);
Translate the model to its position in the grid. xform.Translation(pos);
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 116.525ms | 18.119.122.69