Rotation + Translation

Started by
28 comments, last by Tiege 12 years, 7 months ago
Thanks for all the replies trying to help me out! I'm trying to piece through them now to see if I can pull out an answer.

Yogurt sorry for being unclear about those rotations around x and y. If you recall in some of my previous posts when I load and render my mesh for the very first time, he is facing downward along the negative Y axis. This is where the x and y rotation of 90 degrees comes in to play to turn him upright, then turn him into facing the correct direction. This is only being applied once in my program to set him straight before the game actual runs.

Afterwards yes the only rotation I will require will be along the Y along to flip him left and right (think about mario).

Those rotations have been moved all over the place already trying to fix this. I have had them applying during every frame and not just once but the result is the same in all aspects. The other guys are right in that I have no idea how to use world matrices properly :).

Wizard right now the variables are global for testing purposes. If I can actually get them to work I do intend to organize them much for efficiently. They're also global because I am passing and modifying them through several functions such as FrameMove().

Right now I don't have terrain but just a blank screen with a blue background to display my character. In my render function above I assume the screen is rendered at the very end.

Haegarr your post is very philosphical and very informative :) I hope I can apply it to my program


Now i'm going to try out Wizard's psuedocode, I'm sure I'll be back in 5 minutes because I have no idea what I'm doing

[color=#1C2837][size=2][color=#000000]D3DXMatrixIdentity[color=#666600](&[color=#000000]matWorld[color=#666600]); [color=#666600]works for the initalize identity right?
Advertisement
Stumped before I even start... haha
So I don't get the identity part. How do I make an identity for what I want?

I'm stumped how I move my character without using the already rotated matrix of matWorld.


Here's a rather pathetic attempt to apply Wizard's psuedocode:


void Render()
{
D3DXMATRIX matID;
D3DXMATRIXA16 matWorld;
D3DXMATRIX matRotX;
D3DXMATRIX matRotY;

//clear buffer
d3dDevice->Clear(0,NULL,D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,50,100),1.0f,0);

//begin scene
d3dDevice->BeginScene();

Advance();

checkInput();

//Matrix Identity
D3DXMatrixIdentity(&matID);

//Fix orientation of character (only needed once)
D3DXMatrixRotationX( &matRotX, D3DXToRadian(90.0f) );
D3DXMatrixRotationY( &matRotY, D3DXToRadian(90.0f) );

// Move character left or right
D3DXMatrixTranslation(&matWorld, indexx, indexy, 0);

//Transform character world
d3dDevice->SetTransform( D3DTS_WORLD, &(matWorld * matRotX * matRotY) );

//Render Model
pModel->DrawFrame(pModel->GetFrameRoot());

//Reset to Identity
d3dDevice->SetTransform( D3DTS_WORLD, &(matID) );

//end scene
d3dDevice->EndScene();

//present screen
d3dDevice->Present( NULL, NULL, NULL, NULL );
}

Haegarr your post is very philosphical and very informative :) I hope I can apply it to my program

Well, it is a way of thinking what happens when the transformation pipeline is processed. As such the authors of any 3D program need to apply it in the one or other way, at least if they don't program by trial.

It is in particular useful for
* understanding the terminology,
* composing parent-child transformations (and hence doing forward kinematics),
* understanding the commons and differences of world-objects and cameras,
* composing Euler rotations to yield in a single rotation matrix,
* rotating around arbitrary origins,
* rotating around arbitrary axes (e.g. the local axes),
* scaling along arbitrary axes,
* using incremental rotations,
* knowing where to incorporate LHS/RHS conversion,
* understanding why moving the world is mathematically the same as (inversely) moving the camera,
* and so on ...

That are all practical purposes, aren't they?

[quote name='Tiege' timestamp='1315359075' post='4858420']
Haegarr your post is very philosphical and very informative :) I hope I can apply it to my program

Well, it is a way of thinking what happens when the transformation pipeline is processed. As such the authors of any 3D program need to apply it in the one or other way, at least if they don't program by trial.

It is in particular useful for
* understanding the terminology,
* composing parent-child transformations (and hence doing forward kinematics),
* understanding the commons and differences of world-objects and cameras,
* composing Euler rotations to yield in a single rotation matrix,
* rotating around arbitrary origins,
* rotating around arbitrary axes (e.g. the local axes),
* scaling along arbitrary axes,
* using incremental rotations,
* knowing where to incorporate LHS/RHS conversion,
* understanding why moving the world is mathematically the same as (inversely) moving the camera,
* and so on ...

That are all practical purposes, aren't they?
[/quote]

Indeed but I just want to get this one thing working so I can move on with my game :)
I think I'm starting to understand a little more about matrices. How that a matrix can be used to edit everything about an object before it renders it to world space. So obviously if I rotate the object around an axis and continue to edit that object in the SAME matrix space further the edits will be effected by that axis which was rotated. So I guess to fix this I'm wondering is there a way to edit the same object with two independent and separate matrices. Howver this method doesn't work...



//Fix orientation of character (only needed once)
D3DXMatrixRotationX( &matRotX, D3DXToRadian(90.0f) );
D3DXMatrixRotationY( &matRotY, D3DXToRadian(90.0f) );

// Move character left or right
D3DXMatrixTranslation(&matTrans, indexx, indexy, 0);

//Transform character world
d3dDevice->SetTransform( D3DTS_WORLD, &(matRotX * matRotY) );
d3dDevice->SetTransform( D3DTS_WORLD, &(matTrans) );


Here I am trying to modify my world by two independent matrices to get my model to rotate, and then translate along default axises and not the ones changed after the rotation. I don't even see my character displayed when I try this

Howver if I try


d3dDevice->SetTransform( D3DTS_WORLD, &(matRotX * matRotY * matTrans) );


My character moves along changed axises making his movement all wrong.

A lot of people mention something about a Matrix Identity. I've tried looking it up but no tutorial explains it well or how to apply it in this case. Can someone explain how I would go about doing this?

I drew a simple diagram of what is happening as a result of the above code (all the matrices multipled together) and what my desired result is that im trying to get working:

matrixrot.jpg

Notice how in the actual the translation is affected by the rotation. I need them to be independent of one another.
UPDATE: So after some tinkering I think I REALLY found the source of my problem. I noticed that my translation still applied without having any setTransform functions... My character is animated and I used the guide of this website to get it to work. I have an UpdateFrameMatrices() function my my model class which already uses matrices so I'm guessing this is where it is conflicting with what I want to apply to my object.

Thank you guys for all your help so far :) I know I'm super annoying because I have no idea what's going on. Now I need to figure out how to apply transformations to the .x file animation tutorial code that is given on this website.

If you can find where or even if they give me room to make me move and edit my object how I want let me know, I can't seem to find it.

Source.cpp:


#include "model.h"

char* filename = "BarbA2.x";

//globals
LPDIRECT3D9 d3dObject=NULL;
LPDIRECT3DDEVICE9 d3dDevice;
LPDIRECTINPUT8 din; // the pointer to our DirectInput interface
LPDIRECTINPUTDEVICE8 dinkeyboard; // the pointer to the keyboard device
BYTE keystate[256]; // the storage for the key-information


D3DXMATRIX matWorld;
D3DXMATRIX resRotX;
D3DXMATRIX resRotY;



Model* pModel = NULL;
Model* pModel2 = NULL;

static float vector = 0;
static bool jump = false;

static float indexx = 0.0f;
static float indexy = 0.0f;
bool right = true;

void initDInput(HINSTANCE hInstance, HWND hWnd); // sets up and initializes DirectInput
void detect_input(void); // gets the current input state
void cleanDInput(void); // closes DirectInput and releases memory
void Render();


HRESULT InitD3D( HWND hWnd )
{
//create D3D Object
if( NULL == ( d3dObject=Direct3DCreate9(D3D_SDK_VERSION) ) )
return E_FAIL;

//setup structure for parameters for D3D Device
D3DPRESENT_PARAMETERS presParams;
ZeroMemory(&presParams,sizeof(presParams));
presParams.Windowed=TRUE;
presParams.SwapEffect=D3DSWAPEFFECT_DISCARD;
presParams.BackBufferFormat=D3DFMT_UNKNOWN;
presParams.PresentationInterval=D3DPRESENT_INTERVAL_ONE;


//create D3D Device
if( FAILED (d3dObject->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &presParams, &d3dDevice) ) )
{
return E_FAIL;
}
// Turn on ambient lighting
d3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );


return S_OK;
}

VOID SetupMatrices()
{
// Set up world matrix

//Set Model Orientation




// Set view matrix
D3DXVECTOR3 vEyePt( 0.0f, 0.0f, 50.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
d3dDevice->SetTransform( D3DTS_VIEW, &matView );


// Set Projection Matrix
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 500.0f );
d3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

}

void checkInput()
{

if(keystate[DIK_LEFT] & 0x80)
{
indexx -= 0.5f;
right = false;
}

if(keystate[DIK_RIGHT] & 0x80)
{
indexx += 0.5f;
right = true;
}

if(keystate[DIK_UP] & 0x80)
{
if ( jump == false)
{
jump = true;
vector = 2;
}
}

return;
}

void Advance()
{
static float orientation = 0;
static DWORD lastTime=timeGetTime();
float timeElapsed=0.001f*(timeGetTime()-lastTime);
lastTime=timeGetTime();

//gravity
indexy-=vector;

if (indexy < 0)
vector-=0.25;
if (indexy > 0)
{
jump = false;
vector=0;
}

if(keystate[DIK_R] & 0x80)
orientation = 3.14159;

if(keystate[DIK_L] & 0x80)
orientation = 0;

//pModel->SetOrientation(&matRot, right, indexx, indexy);
//pModel->SetPosition(&matWorld,0,indexx,indexy);





pModel->FrameMove(timeElapsed,&matWorld);




return;
}

void Render()
{
D3DXMATRIX matTrans;
D3DXMATRIX matRotX;
D3DXMATRIX matRotY;

//clear buffer
d3dDevice->Clear(0,NULL,D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,50,100),1.0f,0);

//begin scene
d3dDevice->BeginScene();

Advance();

checkInput();

//Fix orientation of character (only needed once)
D3DXMatrixRotationX( &matRotX, D3DXToRadian(90.0f) );
D3DXMatrixRotationY( &matWorld, D3DXToRadian(90.0f) );

// Move character left or right
D3DXMatrixTranslation(&matWorld, indexx, indexy, 0);

//Transform character world
//d3dDevice->SetTransform( D3DTS_WORLD, &(matRotX * matRotY) );
//d3dDevice->SetTransform( D3DTS_WORLD, &(matTrans) );

//Render Model
pModel->DrawFrame(pModel->GetFrameRoot());

//end scene
d3dDevice->EndScene();

//present screen
d3dDevice->Present( NULL, NULL, NULL, NULL );
}



void initDInput(HINSTANCE hInstance, HWND hWnd)
{
// create the DirectInput interface
DirectInput8Create(hInstance, // the handle to the application
DIRECTINPUT_VERSION, // the compatible version
IID_IDirectInput8, // the DirectInput interface version
(void**)&din, // the pointer to the interface
NULL); // COM stuff, so we'll set it to NULL

// create the keyboard device
din->CreateDevice(GUID_SysKeyboard, // the default keyboard ID being used
&dinkeyboard, // the pointer to the device interface
NULL); // COM stuff, so we'll set it to NULL

// set the data format to keyboard format
dinkeyboard->SetDataFormat(&c_dfDIKeyboard);

// set the control we will have over the keyboard
dinkeyboard->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
}


// this is the function that gets the latest input data
void detect_input(void)
{
// get access if we don't have it already
dinkeyboard->Acquire();

// get the input data
dinkeyboard->GetDeviceState(256, (LPVOID)keystate);
}


// this is the function that closes DirectInput
void cleanDInput(void)
{
dinkeyboard->Unacquire(); // make sure the keyboard is unacquired
din->Release(); // close DirectInput before exiting
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
//case WM_COMMAND:
// handle menu selections etc.
//break;
//case WM_PAINT:
// draw our window - note: you must paint something here or not trap it!
//break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
// We do not want to handle this message so pass back to Windows
// to handle it in a default way
return DefWindowProc(hWnd, message, wParam, lParam);
}

return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc= (WNDPROC)WndProc;
wcex.cbClsExtra= 0;
wcex.cbWndExtra= 0;
wcex.hInstance= hInstance;
wcex.hIcon= 0;
wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName= 0;
wcex.lpszClassName= "MyWindowClass";
wcex.hIconSm= 0;

// Now we can go ahead and register our new window class
RegisterClassEx(&wcex);

HWND hWnd = CreateWindow("MyWindowClass", "Poop", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

//call initD3D
InitD3D(hWnd);
initDInput(hInstance, hWnd); // initialize DirectInput



//Make model
pModel = new Model(d3dDevice);

//Load the new
pModel->Load(filename);

SetupMatrices();


ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

//enter main loop
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);

detect_input();
Render();
}
cleanDInput();

return (int)msg.wParam;
}


model.cpp (my model class)


#include "model.h"





Model::Model(LPDIRECT3DDEVICE9 pD3DDevice)
{
pd3dDevice = pD3DDevice;
pFrameRoot = NULL;
boneMatrices = NULL;
currentAnimationSet = -1;
numAnimationSets = 0;
maxBones = 0;
pAnimController = NULL;
}

Model::~Model()
{
//Delete Animation Controller
if (pAnimController)
pAnimController->Release();

//if there is a frame hierarchyo
if(pFrameRoot)
{
//Allocation class
CMeshHierarchy Alloc;
D3DXFrameDestroy(pFrameRoot, &Alloc);
pFrameRoot = NULL;
}

//Delete the bones
if (boneMatrices)
delete [] boneMatrices;

//Make the Device not point to the other device
pd3dDevice = NULL;
}

void Model::Load(char* filename)
{
CMeshHierarchy Alloc;

if(FAILED(D3DXLoadMeshHierarchyFromX(
filename,
D3DXMESH_MANAGED,
pd3dDevice,
&Alloc,
NULL,
&pFrameRoot,
&pAnimController )))
{
MessageBox(NULL, filename, "Model Load Error", MB_OK);
}

//Set Breakpoint to check value of pFrameRoot
if (pFrameRoot)
{
SetupBoneMatrices((D3DXFRAME_EXTENDED*)pFrameRoot);

if(pAnimController)
numAnimationSets = pAnimController->GetMaxNumAnimationSets();

// Create the bone matrices array for use during FrameMove to hold the final transform
boneMatrices = new D3DXMATRIX[maxBones];
ZeroMemory(boneMatrices, sizeof(D3DXMATRIX)*maxBones);
}
}

void Model::FrameMove(float elapsedTime,const D3DXMATRIX *matWorld)
{
float speed = 30;
elapsedTime/=speed;

// Advance the time and set in the controller
if (pAnimController != NULL)
pAnimController->AdvanceTime(elapsedTime, NULL);

currentTime+=elapsedTime;

// Now update the model matrices in the hierarchy
UpdateFrameMatrices(pFrameRoot, matWorld);

// If the model contains a skinned mesh update the vertices
UpdateSkinnedMesh(pFrameRoot);
}


void Model::UpdateSkinnedMesh(const D3DXFRAME *frameBase)
{
D3DXFRAME_EXTENDED *currentFrame = (D3DXFRAME_EXTENDED*)frameBase;

D3DXMESHCONTAINER_EXTENDED* pMesh = (D3DXMESHCONTAINER_EXTENDED*)currentFrame->pMeshContainer;
while(pMesh && pMesh->pSkinInfo) // handle chained skinned mesh added 24/08/10
{
unsigned int Bones = pMesh->pSkinInfo->GetNumBones();

// Create the bone matrices that transform each bone from bone space into character space
// (via exFrameCombinedMatrixPointer) and also wraps the mesh around the bones using the bone offsets
// in exBoneOffsetsArray
for (unsigned int i = 0; i < Bones; ++i)
{

// Note: during set up exFrameCombinedMatrixPointer is made to point to the correct frame matrix (exCombinedTransformationMatrix)
// So it does not directly get updated but uses the existing frame calculated value from the correct 'controller' frame
D3DXMatrixMultiply(&boneMatrices,&pMesh->exBoneOffsets, pMesh->exFrameCombinedMatrixPointer);
}

// We need to modify the vertex positions based on the new bone matrices. This is achieved
// by locking the vertex buffers and then calling UpdateSkinnedMesh. UpdateSkinnedMesh takes the
// original vertex data (in pMesh->MeshData.pMesh), applies the matrices and writes the new vertices
// out to skin mesh (pMesh->exSkinMesh).

// UpdateSkinnedMesh uses software skinning which is the slowest way of carrying out skinning
// but is easiest to describe and works on the majority of graphic devices.
// Other methods exist that use hardware to do this skinning - see the notes and the
// DirectX SDK skinned mesh sample for more details
void *srcPtr=0;
pMesh->MeshData.pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&srcPtr);


void *destPtr=0;
pMesh->exSkinMesh->LockVertexBuffer(0, (void**)&destPtr);


// Update the skinned mesh
pMesh->pSkinInfo->UpdateSkinnedMesh(boneMatrices, NULL, srcPtr, destPtr);

// Note: bounds may have changed due to skinning! Need to recalc
D3DXVECTOR3 min,max;
D3DXComputeBoundingBox((D3DXVECTOR3*)destPtr,pMesh->exSkinMesh->GetNumVertices(),
D3DXGetFVFVertexSize(pMesh->exSkinMesh->GetFVF()),&min,&max);


// Unlock the meshes vertex buffers
pMesh->exSkinMesh->UnlockVertexBuffer();
pMesh->MeshData.pMesh->UnlockVertexBuffer();

// If we have more than one mesh
pMesh=(D3DXMESHCONTAINER_EXTENDED*)pMesh->pNextMeshContainer;
}

// If we have a sibling recurse
if (currentFrame->pFrameSibling != NULL)
UpdateSkinnedMesh(currentFrame->pFrameSibling);

// If we have a child recurse
if (currentFrame->pFrameFirstChild != NULL)
UpdateSkinnedMesh(currentFrame->pFrameFirstChild);
}

void Model::UpdateFrameMatrices(const D3DXFRAME *frameBase, const D3DXMATRIX *parentMatrix)
{
D3DXFRAME_EXTENDED *currentFrame = (D3DXFRAME_EXTENDED*)frameBase;

// If parent matrix exists multiply our frame matrix by it
if (parentMatrix != NULL)
D3DXMatrixMultiply(&currentFrame->exCombinedTransformationMatrix, &currentFrame->TransformationMatrix, parentMatrix);
else
currentFrame->exCombinedTransformationMatrix = currentFrame->TransformationMatrix;

// If we have a sibling recurse
if (currentFrame->pFrameSibling != NULL)
UpdateFrameMatrices(currentFrame->pFrameSibling, parentMatrix);

// If we have a child recurse
if (currentFrame->pFrameFirstChild != NULL)
UpdateFrameMatrices(currentFrame->pFrameFirstChild, &currentFrame->exCombinedTransformationMatrix);
}

void Model::SetupBoneMatrices(D3DXFRAME_EXTENDED *pFrame)
{
// Cast to our extended structure first
D3DXMESHCONTAINER_EXTENDED* pMesh = (D3DXMESHCONTAINER_EXTENDED*)pFrame->pMeshContainer;

// If this frame has a mesh and there is skin info, then setup the bone matrices
// Note: handles multiple mesh (// Added 24/08/10
while(pMesh && pMesh->pSkinInfo)
{
// Create a copy of the mesh to skin into later
D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE];
if (FAILED(pMesh->MeshData.pMesh->GetDeclaration(Declaration)))
return;

pMesh->MeshData.pMesh->CloneMesh(D3DXMESH_MANAGED,
Declaration, pd3dDevice,
&pMesh->exSkinMesh);

// Max bones is calculated for later use (to know how big to make the temp bone matrices array)
maxBones=max(maxBones,(UINT)pMesh->pSkinInfo->GetNumBones());

// For each bone work out its matrix
for (unsigned int i = 0; i < pMesh->pSkinInfo->GetNumBones(); i++)
{
// Find the frame containing the bone
// Must do this from root as skinned mesh and bone frame are not together
D3DXFRAME_EXTENDED* pTempFrame = (D3DXFRAME_EXTENDED*)D3DXFrameFind(pFrameRoot,
pMesh->pSkinInfo->GetBoneName(i));


// set the bone part - Note just point it at the transformation matrix of the relevant frame (aliase)
pMesh->exFrameCombinedMatrixPointer = &pTempFrame->exCombinedTransformationMatrix;
}

pMesh=(D3DXMESHCONTAINER_EXTENDED*)pMesh->pNextMeshContainer;
}

// Pass on to sibblings
if(pFrame->pFrameSibling)
SetupBoneMatrices((D3DXFRAME_EXTENDED*)pFrame->pFrameSibling);

// Pass on to children
if(pFrame->pFrameFirstChild)
SetupBoneMatrices((D3DXFRAME_EXTENDED*)pFrame->pFrameFirstChild);
}


void Model::DrawFrame(LPD3DXFRAME frame)
{
// Draw all mesh containers in this frame
LPD3DXMESHCONTAINER meshContainer = frame->pMeshContainer;
while (meshContainer)
{
DrawMeshContainer(meshContainer, frame);
meshContainer = meshContainer->pNextMeshContainer;
}

// Recurse for sibblings
if (frame->pFrameSibling != NULL)
DrawFrame(frame->pFrameSibling);

// Recurse for children
if (frame->pFrameFirstChild != NULL)
DrawFrame(frame->pFrameFirstChild);
}

void Model::DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase)
{
// Cast to our extended frame type
D3DXFRAME_EXTENDED *frame = (D3DXFRAME_EXTENDED*)frameBase;

// Cast to our extended mesh container
D3DXMESHCONTAINER_EXTENDED *meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase;

// Loop through all the materials in the mesh rendering each subset
for (unsigned int iMaterial = 0; iMaterial < meshContainer->NumMaterials; iMaterial++)
{
// use the material in our extended data rather than the one in meshContainer->pMaterials[iMaterial].MatD3D
pd3dDevice->SetMaterial( &meshContainer->exMaterials[iMaterial] );
pd3dDevice->SetTexture( 0, meshContainer->exTextures[iMaterial] );


// Select the mesh to draw, if there is skin then use the skinned mesh else the normal one

LPD3DXMESH pDrawMesh = (meshContainer->pSkinInfo) ? meshContainer->exSkinMesh: meshContainer->MeshData.pMesh;
// Finally Call the mesh draw function
pDrawMesh->DrawSubset(iMaterial);
}
}


allocatehierarchy.cpp:


#include "allocatehierarchy.h"

HRESULT CMeshHierarchy::CreateFrame(LPCSTR Name, LPD3DXFRAME *retNewFrame)
{
// Always a good idea to initialise a return pointer before proceeding
*retNewFrame = 0;

// Create a new frame using the derived version of the structure
D3DXFRAME_EXTENDED *newFrame = new D3DXFRAME_EXTENDED;
ZeroMemory(newFrame,sizeof(D3DXFRAME_EXTENDED));

// Now fill in the data members in the frame structure

// Now initialize other data members of the frame to defaults
D3DXMatrixIdentity(&newFrame->TransformationMatrix);
D3DXMatrixIdentity(&newFrame->exCombinedTransformationMatrix);

newFrame->pMeshContainer = 0;
newFrame->pFrameSibling = 0;
newFrame->pFrameFirstChild = 0;

// Assign the return pointer to our newly created frame
*retNewFrame = newFrame;

// The frame name (note: may be 0 or zero length)
if (Name != NULL)
{
newFrame->Name = new char[strlen(Name) + 1];
strcpy(newFrame->Name, Name);
}
return S_OK;
}

/**
* \brief callback called when a mesh data is encountered during the .x file load
* \param Name - name of the Mesh (const char*)
* \param meshData - the mesh data
* \param materials - material array
* \param effectInstances - effect files / settings for the mesh
* \param numMaterials - number of materials in the mesh
* \param adjacency - adjacency array
* \param pSkinInfo - skin info.
* \param retNewMeshContainer - output pointer to assign our newly created mesh container
* \return success code
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::CreateMeshContainer(
LPCSTR Name,
CONST D3DXMESHDATA *meshData,
CONST D3DXMATERIAL *materials,
CONST D3DXEFFECTINSTANCE *effectInstances,
DWORD numMaterials,
CONST DWORD *adjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER* retNewMeshContainer)
{
// Create a mesh container structure to fill and initilaise to zero values
// Note: I use my extended version of the structure (D3DXMESHCONTAINER_EXTENDED) defined in MeshStructures.h
D3DXMESHCONTAINER_EXTENDED *newMeshContainer=new D3DXMESHCONTAINER_EXTENDED;
ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED));

// Always a good idea to initialise return pointer before proceeding
*retNewMeshContainer = 0;

// The mesh name (may be 0) needs copying over
if (Name != NULL)
{
newMeshContainer->Name = new char[strlen(Name) + 1];
strcpy(newMeshContainer->Name, Name);
}

// The mesh type (D3DXMESHTYPE_MESH, D3DXMESHTYPE_PMESH or D3DXMESHTYPE_PATCHMESH)
if (meshData->Type!=D3DXMESHTYPE_MESH)
{
// This demo does not handle mesh types other than the standard
// Other types are D3DXMESHTYPE_PMESH (progressive mesh) and D3DXMESHTYPE_PATCHMESH (patch mesh)
DestroyMeshContainer(newMeshContainer);
return E_FAIL;
}

newMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

// Adjacency data - holds information about triangle adjacency, required by the ID3DMESH object
DWORD dwFaces = meshData->pMesh->GetNumFaces();
newMeshContainer->pAdjacency = new DWORD[dwFaces*3];
if (adjacency)
{
memcpy(newMeshContainer->pAdjacency, adjacency, sizeof(DWORD) * dwFaces*3);
}
else
{
// Added 24/08/10: previously did not detect null adjacency
if(FAILED( newMeshContainer->MeshData.pMesh->GenerateAdjacency( 1e-6f, (DWORD*)(void*)newMeshContainer->pAdjacency ) ) )
FillMemory((void*)newMeshContainer->pAdjacency, dwFaces*3, 0xFF );
}

// Get the Direct3D device, luckily this is held in the mesh itself (Note: must release it when done with it)
LPDIRECT3DDEVICE9 pd3dDevice = 0;
meshData->pMesh->GetDevice(&pd3dDevice);

// Changed 24/09/07 - can just assign pointer and add a ref rather than need to clone
newMeshContainer->MeshData.pMesh=meshData->pMesh;
newMeshContainer->MeshData.pMesh->AddRef();

// Create material and texture arrays. Note that I always want to have at least one
newMeshContainer->NumMaterials = max(numMaterials,1);
newMeshContainer->exMaterials = new D3DMATERIAL9[newMeshContainer->NumMaterials];
newMeshContainer->exTextures = new LPDIRECT3DTEXTURE9[newMeshContainer->NumMaterials];

ZeroMemory(newMeshContainer->exTextures, sizeof(LPDIRECT3DTEXTURE9) * newMeshContainer->NumMaterials);

if (numMaterials>0)
{
// Load all the textures and copy the materials over
for(DWORD i = 0; i < numMaterials; ++i)
{
newMeshContainer->exTextures = 0;
newMeshContainer->exMaterials=materials.MatD3D;

if(materials.pTextureFilename)
{

D3DXCreateTextureFromFile(pd3dDevice, materials.pTextureFilename,
&newMeshContainer->exTextures);

}
}
}
else
// make a default material in the case where the mesh did not provide one
{
ZeroMemory(&newMeshContainer->exMaterials[0], sizeof( D3DMATERIAL9 ) );
newMeshContainer->exMaterials[0].Diffuse.r = 0.5f;
newMeshContainer->exMaterials[0].Diffuse.g = 0.5f;
newMeshContainer->exMaterials[0].Diffuse.b = 0.5f;
newMeshContainer->exMaterials[0].Specular = newMeshContainer->exMaterials[0].Diffuse;
newMeshContainer->exTextures[0]=0;
}

// If there is skin data associated with the mesh copy it over
if (pSkinInfo)
{
// save off the SkinInfo
newMeshContainer->pSkinInfo = pSkinInfo;
pSkinInfo->AddRef();

// Need an array of offset matrices to move the vertices from the figure space to the bone's space
UINT numBones = pSkinInfo->GetNumBones();
newMeshContainer->exBoneOffsets = new D3DXMATRIX[numBones];

// Create the arrays for the bones and the frame matrices
newMeshContainer->exFrameCombinedMatrixPointer = new D3DXMATRIX*[numBones];

// get each of the bone offset matrices so that we don't need to get them later
for (UINT i = 0; i < numBones; i++)
newMeshContainer->exBoneOffsets = *(newMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i));


// Note: in the Microsoft samples a GenerateSkinnedMesh function is called here in order to prepare
// the skinned mesh data for optimial hardware acceleration. As mentioned in the notes this sample
// does not do hardware skinning but instead uses software skinning.
}
else
{
// No skin info so 0 all the pointers
newMeshContainer->pSkinInfo = 0;
newMeshContainer->exBoneOffsets = 0;
newMeshContainer->exSkinMesh = 0;
newMeshContainer->exFrameCombinedMatrixPointer = 0;
}

// When we got the device we caused an internal reference count to be incremented
// So we now need to release it
pd3dDevice->Release();

// The mesh may contain a reference to an effect file
if (effectInstances)
{
if (effectInstances->pEffectFilename)
MessageBox(NULL, "Effect Instance", "Model Load Error", MB_OK);
}

// Set the output mesh container pointer to our newly created one
*retNewMeshContainer = newMeshContainer;

return S_OK;
}

/**
* \brief callback called to deallocate the frame data
* \param the frame to free
* \return success result
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::DestroyFrame(LPD3DXFRAME frameToFree)
{
// Convert to our extended type. OK to do this as we know for sure it is:
D3DXFRAME_EXTENDED *frame = (D3DXFRAME_EXTENDED*)frameToFree;

delete []frame->Name;
delete frame;

return S_OK;
}

/**
* \brief callback called to deallocate the mesh container data
* \param the mesh data to free
* \return success result
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER meshContainerBase)
{
// Convert to our extended type. OK as we know for sure it is:
D3DXMESHCONTAINER_EXTENDED* meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase;
if (!meshContainer)
return S_OK;

// name
delete []meshContainer->Name;
meshContainer->Name=0;

// material array
delete []meshContainer->exMaterials;
meshContainer->exMaterials=0;

// release the textures before deleting the array
if(meshContainer->exTextures)
{
for(UINT i = 0; i < meshContainer->NumMaterials; ++i)
{
if (meshContainer->exTextures)
meshContainer->exTextures->Release();
}
}

// texture array
delete []meshContainer->exTextures;

// adjacency data
delete []meshContainer->pAdjacency;

// bone parts
delete []meshContainer->exBoneOffsets;

// frame matrices
delete []meshContainer->exFrameCombinedMatrixPointer;

// release skin mesh
if (meshContainer->exSkinMesh)
meshContainer->exSkinMesh->Release();

// release the main mesh
if (meshContainer->MeshData.pMesh)
meshContainer->MeshData.pMesh->Release();

// release skin information
if (meshContainer->pSkinInfo)
meshContainer->pSkinInfo->Release();

// finally delete the mesh container itself
delete meshContainer;
meshContainer=0;

return S_OK;
}
I think ill just clear up that stuff about identity matrices i said before. Basically calling D3DXMatrixIdentity(&matWorld); makes sure the matrix is set to Identity. This identity matrix is such that if any other matrix is multiplied by it, its result remains unchanged. eg. if matrix 'I' is the indentiy matrix then... I x A = A. Anyway applying it to your program, If you have your matrices set as global that means they retain their data until such point as their parent class is destroyed. Which means they retain data between frames.

After typing out some code to show you how it works, i realized your program wont be affected by any permanence of the matrices, so using the identity matrices wont be necessary. But its still good to know about it and be aware of what it can do.

also some of the code you posted before

//Fix orientation of character (only needed once)
1 D3DXMatrixRotationX( &matRotX, D3DXToRadian(90.0f) );
2 D3DXMatrixRotationY( &matRotY, D3DXToRadian(90.0f) );
3
4 // Move character left or right
5 D3DXMatrixTranslation(&matTrans, indexx, indexy, 0);
6
7 //Transform character world
8 d3dDevice->SetTransform( D3DTS_WORLD, &(matRotX * matRotY) );
9 d3dDevice->SetTransform( D3DTS_WORLD, &(matTrans) );


on line 8 you set the world matrix as one rotated 90degrees along X and Y, then at line 9 you RE-set the world matrix as one ONLY translated by 5x and 5y. They need to be done is a single calculation eg.

d3dDevice->SetTransform( D3DTS_WORLD, &(matRotX * matRotY * matTrans) );

This ensures that both the rotations and translations are applied
I took about a week break since I got a new full time job and was never in the mood to think about this. But today I finally got it figured out and I want to thank all of you who put up with me and my non sensible help. Especially Yogurt and Whitewizard.

Anyway I figured out my matrices were automatically being updated somewhere else in the animation code so I was basically doing it twice with my SetTransform functions. So the line of code that made what I wanted to work was :


D3DXMatrixMultiply(&matWorld, &(matRotX * matRotY), &matTrans);


since it just multiplies the matrices without updating them so they get updated later ( i have no idea where haha).

This is exactly what I needed and thanks for all your helpful info and guidance!
Yay! I'd been wondering if you'd ever gotten it working. But, you should probably track down where your actually setting your updated world matrix :D

Yay! I'd been wondering if you'd ever gotten it working. But, you should probably track down where your actually setting your updated world matrix :D


Ya I pinpointed it. It only works if the x file is animated too haha. I have to add an independent setTransform function if its not animated. Thinking about putting my matrix functions in my model class so each model can keep track of its own position etc. I have to toy more with matrices to make sure if I have 50 models up at once each keeping track of their own position I can link them all together

This topic is closed to new replies.

Advertisement