world/view/projection transform bug in c++ [solved]
Hi
I have a weird bug. I recently started using DirectX9 in visual studio C++. Thus far I have managed to load and display meshes from *.x files. The problem is: when I load in more than 1 model and wish to translate/rotate only one of the models all the models loaded are transformed.
Basically what I want to do is load a room (which would be one model), and then use a different model to move around the room.
I am using:
D3DXMatrixRotationX,
D3DXMatrixRotationY,
D3DXMatrixRotationZ, and
D3DXMatrixTranslation to transform a giving model.
I think the problem is because the LPDIRECT3DDEVICE9 is used to load both the models and the same LPDIRECT3DDEVICE9 is used to transform the models. I don't know how to tell LPDIRECT3DDEVICE9 (or whatever I need to tell) to transform the models independently.
I'm not using DXUT cuz I wanna know how to load and move object manually.
Here is some code thus far, it might be to much code but I wanna define/show what I am doing and how I am doing it. I omitted some of the code cuz it gets to long.
////////////////////////////////////class header file////////////////////////
class CStaticMesh
{
private:
LPDIRECT3DDEVICE9 pd3dDevice; //device pointer
//MESH data
LPD3DXMESH mesh; // Our mesh object
D3DMATERIAL9 *meshMaterials;
LPDIRECT3DTEXTURE9 *meshTextures;
DWORD numMaterials;
float MeshPosRot[6];
//end MESH DATA
public:
CStaticMesh(LPDIRECT3DDEVICE9 DevicePTR);
~CStaticMesh();
HRESULT loadMeshFile(char *dir);
HRESULT drawMeshID();
HRESULT moveMeshID(FLOAT nx=0.0f,FLOAT ny=0.0f,FLOAT nz=0.0f);
HRESULT rotateMeshID(FLOAT nx=0.0f,FLOAT ny=0.0f,FLOAT nz=0.0f);
};
///////////////////////////class implementation file/////////////////////
CStaticMesh::CStaticMesh(LPDIRECT3DDEVICE9 DevicePTR)
{
......
pd3dDevice=DevicePTR;
......
}
HRESULT CStaticMesh::loadMeshFile(char *dir)
{
.........
if(FAILED(D3DXLoadMeshFromX(dir, D3DXMESH_SYSTEMMEM,
pd3dDevice, NULL,
&materialBuffer,NULL, &numMaterials,
&mesh )))
return false;
........
}
HRESULT CStaticMesh::drawMeshID()
{
for (DWORD i=0; i<numMaterials; i++)
{
// Set the material and texture for this subset
pd3dDevice->SetMaterial(&meshMaterials);
pd3dDevice->SetTexture(0,meshTextures);
// Draw the mesh subset
mesh->DrawSubset( i );
}
return true;
}
HRESULT CStaticMesh::moveMeshID(FLOAT nx,FLOAT ny,FLOAT nz)
{
D3DXMATRIX objMat,moveMat;
pd3dDevice->GetTransform(D3DTS_WORLD, &objMat);
D3DXMatrixIdentity(&moveMat);
MeshPosRot[0]=nx;
MeshPosRot[1]=ny;
MeshPosRot[2]=nz;
D3DXMatrixTranslation(&moveMat,MeshPosRot[0],MeshPosRot[1],MeshPosRot[2]);
D3DXMatrixMultiply(&objMat, &objMat, &moveMat);
pd3dDevice->SetTransform(D3DTS_WORLD, &objMat);
return true;
}
HRESULT CStaticMesh::rotateMeshID(FLOAT nx,FLOAT ny,FLOAT nz)
{
D3DXMATRIX matRotate,finalMat,objMat;
pd3dDevice->GetTransform(D3DTS_WORLD, &objMat);
MeshPosRot[3]=nx;//update new rotation
MeshPosRot[4]=ny;
MeshPosRot[5]=nz;
// Set the rotation
D3DXMatrixRotationX(&matRotate, MeshPosRot[3]);
D3DXMatrixMultiply(&finalMat, &objMat, &matRotate);
D3DXMatrixRotationY(&matRotate, MeshPosRot[4]);
D3DXMatrixMultiply(&finalMat, &finalMat, &matRotate);
D3DXMatrixRotationZ(&matRotate, MeshPosRot[5]);
D3DXMatrixMultiply(&finalMat, &finalMat, &matRotate);
pd3dDevice->SetTransform(D3DTS_WORLD, &finalMat);
return true;
}
//////////////////////////main file//////////////////////////
CStaticMesh *cmesh;
CStaticMesh *cmeshRoom;
VOID render()
{
pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER ,D3DCOLOR_XRGB( 0,0,0 ), 1.0f, 0 );//clear to black
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
cameraStuff();
cmesh->moveMeshID(moveX,moveY,moveZ);
cmesh->rotateMeshID(rotateX,rotateY,rotateZ);
cmesh->drawMeshID();
cmeshRoom->drawMeshID();
pd3dDevice->EndScene();
pd3dDevice->Present(NULL,NULL,NULL,NULL);
}
}
INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow )
{
.......
cmesh=new CStaticMesh(pd3dDevice);
cmeshRoom=new CStaticMesh(pd3dDevice);
if(!cmesh->loadMeshFile("DwarfWithEffectInstance.x"))
return false;
if(!cmeshRoom->loadMeshFile("room.x"))
return false;
........
render();
........
delete cmesh;
delete cmeshRoom;
return (int) msg.wParam;
}
///////////////////////////END////////////////////////////////
If you look at the render function: I am only moving the cmesh model and not the cmeshRoom model. But when I compile and run both models are transformed....
I hope you can help me.
Thanks
[Edited by - Kapoef on March 18, 2010 10:36:12 AM]
It sounds like you need to restore the world matrix after you're done drawing each object.
It's probably clearer (to others and yourself) if you set the world transform just before you render, not in another function.
D3DXMATRIX oldWorld;dev->GetTransform(D3DTS_WORLD,&oldWorld);dev->SetTransform(D3DTS_WORLD,&thisObjectsMat); // set the transform here!... // do the renderingdev->SetTransfrom(D3DTS_WORLD,&oldWorld);
It's probably clearer (to others and yourself) if you set the world transform just before you render, not in another function.
I tried your(Buckeye) approach but to no avail. When I implemented:
D3DXMATRIX oldWorld;
dev->GetTransform(D3DTS_WORLD,&oldWorld);
dev->SetTransform(D3DTS_WORLD,&thisObjectsMat); // set the transform here!
... // do the rendering
dev->SetTransfrom(D3DTS_WORLD,&oldWorld);
no transformation was done at all.
Is there a way to get access to the matrix for a specific model only. As I understand it the device in use only has one D3DTS_WORLD. But all objects loaded in are loaded using the one device thus making all the world transform relative to each other, or not?
What the code does now is:
Backup old world -> transform the model a bit -> display -> restore the old world AND the old model.
Thus the entire old world is restored and the next transformation will be voided, since the old world is continuously restored.
I guess I am missing something... but idk what thats the big question....
D3DXMATRIX oldWorld;
dev->GetTransform(D3DTS_WORLD,&oldWorld);
dev->SetTransform(D3DTS_WORLD,&thisObjectsMat); // set the transform here!
... // do the rendering
dev->SetTransfrom(D3DTS_WORLD,&oldWorld);
no transformation was done at all.
Is there a way to get access to the matrix for a specific model only. As I understand it the device in use only has one D3DTS_WORLD. But all objects loaded in are loaded using the one device thus making all the world transform relative to each other, or not?
What the code does now is:
Backup old world -> transform the model a bit -> display -> restore the old world AND the old model.
Thus the entire old world is restored and the next transformation will be voided, since the old world is continuously restored.
I guess I am missing something... but idk what thats the big question....
You can't use the device to store the transform state of a model instance. As you've noticed you can only have one world transform set onto the device at a time.
Typically you'll have "instances" of a particular model, where an instance is one occurrence of a particular model in your scene. So if you wanted to draw your room model 5 times in the scene with different positions, you would have 5 instances but only the one model.
The simplest version of instance can just store a world matrix, and a pointer to the model. Then when you want to move or rotate an instance you alter the matrix that belongs to that instance, and when you want to draw the instance you set its world matrix onto the device and render the model.
Oh and if you want to post code here, you can use the "code" or "source" tags. See the faq.
Typically you'll have "instances" of a particular model, where an instance is one occurrence of a particular model in your scene. So if you wanted to draw your room model 5 times in the scene with different positions, you would have 5 instances but only the one model.
The simplest version of instance can just store a world matrix, and a pointer to the model. Then when you want to move or rotate an instance you alter the matrix that belongs to that instance, and when you want to draw the instance you set its world matrix onto the device and render the model.
Oh and if you want to post code here, you can use the "code" or "source" tags. See the faq.
Quote:As I understand it the device in use only has one D3DTS_WORLD. But all objects loaded in are loaded using the one device thus making all the world transform relative to each other, or not?
Loading a file does not effect the world transform currently in use by the device. They're totally unrelated, provided you mean you use D3DXLoadMeshFromX or some similar function to load objects.
When you call mesh->DrawSubset(), the rendering is done with whatever viewport, view matrix and projection matrix the device currently has set.
Did you remove the SetTransform calls from your move/rotateMesh functions? If you didn't, the next mesh will use the device-world matrix from whatever you last set it to.
ok as i understand it now:
basic code flow follows:
1. INIT all
1.1. Load 2 *.x model (model A and model B).
1.2. Set D3DTS_WORLD to (0,0,0).
2. LOOP
2.1. Begin frame (using pd3dDevice->BeginScene() ).
2.2. Set new D3DTS_WORLD for model A.
2.3. Display model A. (using DrawSubset() ).
2.4. Set new D3DTS_WORLD for model B (in this case D3DTS_WORLD to (0,0,0) ).
2.5. Display model B. (using DrawSubset() ).
2.6. End frame(using pd3dDevice->EndScene() ).
2.7. display Buffer (pd3dDevice->Present(NULL,NULL,NULL,NULL) ).
k well i tried the above approach and it still does not work... The entire frame is stationary model A does not move at all.
Do any of you have a simple complete example that i could look at? this is probably a trivial problem but i fail to correct my error.
By the way thanks for the advice so far ;)
basic code flow follows:
1. INIT all
1.1. Load 2 *.x model (model A and model B).
1.2. Set D3DTS_WORLD to (0,0,0).
2. LOOP
2.1. Begin frame (using pd3dDevice->BeginScene() ).
2.2. Set new D3DTS_WORLD for model A.
2.3. Display model A. (using DrawSubset() ).
2.4. Set new D3DTS_WORLD for model B (in this case D3DTS_WORLD to (0,0,0) ).
2.5. Display model B. (using DrawSubset() ).
2.6. End frame(using pd3dDevice->EndScene() ).
2.7. display Buffer (pd3dDevice->Present(NULL,NULL,NULL,NULL) ).
k well i tried the above approach and it still does not work... The entire frame is stationary model A does not move at all.
Do any of you have a simple complete example that i could look at? this is probably a trivial problem but i fail to correct my error.
By the way thanks for the advice so far ;)
D3DXMATRIX aMat, bMat;D3DXMatrixTranslation(&aMat,1,1,1); // at x=1, y=1, z=1D3DXMatrixTranslation(&bMat,0,0,0); // at the originfloat aAngle = 0;float bAngle = 0;LOOP: dev->BeginScene(); D3DXMATRIX tmp, world; aAngle += 0.1f; bAngle -= 0.2f; D3DXMatrixRotationX(&tmp,aAngle); world = tmp * aMat; dev->SetTransform(D3DTS_WORLD,&world); objA->DrawSubset(..); D3DXMatrixRotationY(&tmp,bAngle); world = tmp * bMat; dev->SetTransform(D3DTS_WORLD,&world); objB->DrawSubset(..); dev->EndScene(); dev->Present(...);// end LOOP
That's all off the top of my head, but it should result in objA at (1,1,1) rotating about it's local x-axis. objB, at the origin, should be rotating twice as fast as objA about the y-axis at the origin.
This all assumes you have a projection and view set up to be able to see those two points, etc., etc.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement