Archived

This topic is now archived and is closed to further replies.

ZitherMan

Rotating a mesh

Recommended Posts

I've been trying to make some kind of system for moving and rotating my meshes. I thought i'd set the objects position to 0,0,0 then rotate and then move it back, but the object is rotating around some other point, not beeing 0,0,0. Does anyone have any idea why it does this? Here are some code-samples:
        
void CMesh::Rotate(D3DXVECTOR3 axis, long Speed)
{

	float old_x, old_y, old_z;
	old_x = m_vPos.x;
	old_y = m_vPos.y;
	old_z = m_vPos.z;
	SetPos(0,0,0);
	D3DXMatrixRotationAxis( &mtxRot, &axis, D3DXToRadian((float)Speed / 40.0f));
	D3DXVec3TransformCoord( &m_vLook, &m_vLook, &mtxRot );
	D3DXVec3TransformCoord( &m_vUp, &m_vUp, &mtxRot );
	SetPos(old_x, old_y, old_z);
}

void CMesh::SetPos(float x, float y, float z)
{
	m_vPos   = D3DXVECTOR3(x, y, z);  // Mesh Position

	Update();
}

void CMesh::Update()
{

	D3DXMatrixIdentity( &mesh );

	D3DXVec3Normalize( &m_vLook, &m_vLook );
	D3DXVec3Cross( &m_vRight, &m_vUp, &m_vLook );
	D3DXVec3Normalize( &m_vRight, &m_vRight );
	D3DXVec3Cross( &m_vUp, &m_vLook, &m_vRight );
	D3DXVec3Normalize( &m_vUp, &m_vUp );

	view._11 = m_vRight.x;
        view._12 = m_vUp.x;
        view._13 = m_vLook.x;
	view._14 = 0.0f;

	view._21 = m_vRight.y;
        view._22 = m_vUp.y;
        view._23 = m_vLook.y;
 	view._24 = 0.0f;

	view._31 = m_vRight.z;
        view._32 = m_vUp.z;
        view._33 = m_vLook.z;
	view._34 = 0.0f;

	view._41 = -D3DXVec3Dot( &m_vPos, &m_vRight );
	view._42 = -D3DXVec3Dot( &m_vPos, &m_vUp );
	view._43 = -D3DXVec3Dot( &m_vPos, &m_vLook );
	view._44 =  1.0f;
	

}
        
Is there a better way to do this (i guess there is)? I've heard something about some model-matrix but i havnt found any reference on it. Any help would be appreciated [edited by - ZitherMan on May 5, 2003 2:42:27 PM]

Share this post


Link to post
Share on other sites
Where are you moving the object to 0,0,0 ? Do you mean set it''s position to this or it''s rotation ?

Share this post


Link to post
Share on other sites
Free your mind, young grasshopper. You see, in DirectX, meshes do not really exist.

Hard to believe, but the g_Device->SetTranform(DTS_WORLD) thing that may have looked so mysterious for such a long time is the solution to all your problems, assuming you''re in the same ditch I was a while back.

Meshes, in DirectX, like I said, don''t acutally exist. DirectX changes the relative position of a camera every time you render a new object, as long as you give it a transformation matrix. When you''re rotating an object, you''re actually just adding a rotation matrix to your overall transformation. So, instead of transforming the matrix to the center and all that jazz, just create a new matrix:

D3DXMATRIX mRotation;

Next: The amount the mesh will have rotated since the last frame will be incremented, not concretely determined, by your Speed variable. You''ll need a D3DXVECTOR3 member variable in your mesh to keep track of the orientation (call it m_Orientation). Now, increment the orientation according to your axis parameter, tampered in magnitude by your Speed variable. Even more important is a g_RotationFactor, which will determine how you''re going to convert your axis strength and speed into radians:

m_Orientation += axis * (float)speed / g_RotationFactor;

g_RotationFactor, as you can see, is a global float that you can adjust in your console (you DO have a console, don''t you?) until you find a good Speed-to-radian ratio, all without having to recompile.

Next up is the actual rotation transformation. You may already have this code in your Render or Update function - it''s pretty important stuff. You''ve already created a mRotation matrix, and now it''s time to use it. This nifty function will apply a given amount of x, y, and z rotation to a matrix which you can use to rotate anything by that amount:

D3DXMatrixRotationYawPitchRoll(&mRotation, m_Orientation.x, m_Orientation.y, m_Orientation.z);

When you render your object, you''re likely using a trasformation matrix in a line of code that looks like the following:

g_Device->SetTransform(DTDS_WORLD, &mTrans);

If so, just add the mRotation matrix to the stack of transformations. If you have no idea what I''m talking about, read on.

Like I was talking about in the beginning, DirectX needs to know from what point the mesh will be rendered (the mesh doesn''t move - DirectX moves). This is done with the matrix thingies, as it looks like you''ve kind of already found out. Whatever matrix you''re using right now to transform the position (mTrans, for example), you''ll need to multiply - combine, in the common tongue - these two matrices. This is easier than it sounds:

D3DXMatrixMultiply(&mTrans, &mRotation, &mTrans);

And then you set the transformation matrix like I showed you with the SetTransform(DTDS_WORLD, &mTransfunction above.

The end result is, DirectX knows the new orientation of yer mesh, and when it renders it, the results should be visible. Don''t forget to tweek around with that g_RotationFactor variable.

Long winded, I know, but I hope it helped. I tried to give you the information I now know I needed when I was in the same fix a while back. I''ll be glad to answer any questions, if I can.

- TythosEternal



"Who''s John Galt?"

Share this post


Link to post
Share on other sites
Thank you very much! That made me understand things a little bit better.



My problem now, is that the mesh gets extremely deformed.
http://zith.cisko.org/screen.gif
there's like beams from the center of the screen, to the edges. When i move the camera, these "beams" get replaced with new ones. When i try to rotate, the same thing happens as when i move the camera

Here is the new code


      
in CMesh::CMesh i do
m_Orientation = D3DXVECTOR3(0.0f,0.0f,1.0f);




void CMesh::Rotate(D3DXVECTOR3 axis, long Speed)
{
m_Orientation += axis * (float)Speed / 40.0f;
D3DXMatrixRotationYawPitchRoll(&mtxRot, m_Orientation.x, m_Orientation.y, m_Orientation.z);

D3DXMatrixMultiply(&trans, &mtxRot, &trans);

}



void CMesh::Render()
{

m_D3DDevice->SetTransform(D3DTS_WORLD, &trans);
for(DWORD i = 0; i < m_NumMaterials; i++)
{
// Set the material and texture for this subset

m_D3DDevice->SetMaterial(&m_Materials[i]);
m_D3DDevice->SetTexture(0, m_Textures[i]);
m_D3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_POINT);


// Draw the mesh subset

m_Mesh->DrawSubset(i);
}
}





[edited by - ZitherMan on May 8, 2003 5:00:36 PM]

Share this post


Link to post
Share on other sites
Your render function should be reordered, first. Here''s what mine looks like:


  
HRESULT CMesh::Render()
{
HRESULT r = E_FAIL;

for (int i = 0; i < m_NumMaterials; i++)
{
m_Materials[i].Update();
m_D3DDevice->SetTexture(0, m_pTextures[i]);
r = m_Mesh->DrawSubset(i);
}

//You''ll need to reset the vertex shader...

m_D3DDevice->SetVertexShader(/*Whatever you''re using*/);

return r;
}


Wondering where the matrix stuff went? Good question. It goes into something called a frame class, which is basically a wrapper object for your mesh so you don''t have to deal with 60 of the same meshes in your game (like 60 of the same kind of alien) and then trying to update and render each individual mesh. Instead, you should only have one mesh object for each type of mesh in your game - one alien infantry mesh, for example, no matter how many alient infantry are in your level.

The frame is where you can do all your individual manipulation. This is also where you''ll have your rotate function, which will change the Orientation vector accordingly. A basic frame class will look something like this:


  
class CFrame
{
private:
D3DXMATRIX m_mLocal;
D3DVECTOR3 m_vPosition;
D3DVECTOR3 m_vVelocity;
D3DVECTOR3 m_vOrientation;

CMesh m_YeOldeMesh;

public:
CFrame();
~CFrame();

//All your set and get functions for position, velocity, etc


void Rotate(D3DXVECTOR3 axis, long Speed);
void Update();
HRESULT Render();
};



Also, how are you creating your mesh, and how are you converting it to an x file (if you''re using a 3d modeling program)? Sometimes, especially with the more advanced modeling programs, the scale, rotation pivot point, and transformation centers can REALLY mess things up (imagine a TIE fighter stretched sideways until it''s about 100 times as wide as it is long and you''ll know what I mean).

The end conclusion, though, is that once you load your mesh, you should NEVER touch it. If it''s working fine, (and there''s no really big reason it shouldn''t, other than that render function), you should just encapsulate it and use it in your frame class.

- TythosEternal




"Who''s John Galt?"

Share this post


Link to post
Share on other sites
quote:
Original post by TythosEternal
(...)
Also, how are you creating your mesh, and how are you converting it to an x file (if you''re using a 3d modeling program)? Sometimes, especially with the more advanced modeling programs, the scale, rotation pivot point, and transformation centers can REALLY mess things up (imagine a TIE fighter stretched sideways until it''s about 100 times as wide as it is long and you''ll know what I mean).



I can tell you that

The mesh is converted from 3ds to .x using the SDK converter (or at least that''s what zith told me that little thingie was ) The pivot point has been set at the very centre of the model before exporting, so that should not be a problem either.

BTW, you are amazing Tythos

Richard Olsson
maxed@johnbauer.org

Share this post


Link to post
Share on other sites
Thank you very very very much for your replies, there are many things you've made more clear for me. However, the mesh still doesn't rotate right

Here's a screenshot:
http://zith.cisko.org/screen2.gif

So it still rotates around the same point as before, while i want it to rotate around its own pivot-point / axis. The speed of the rotation also increases every frame, making the object spin faster and faster and i really can't figure out why..



I made a frame-class pretty much like the one you showed me.

          
// This is the header

class CFrame
{
private:
D3DXMATRIX m_mLocal;
D3DXVECTOR3 m_vPosition;
D3DXVECTOR3 m_vVelocity;
D3DXVECTOR3 m_vOrientation;

LPDIRECT3DDEVICE8 m_D3DDevice;
D3DXMATRIX mtxRot;
CMesh *m_Mesh;

public:
CFrame(LPDIRECT3DDEVICE8 lpD3DDevice, CMesh *Mesh);
~CFrame();

//All your set and get functions for position, velocity, etc


void Rotate(D3DXVECTOR3 axis, long Speed);
void Update();
HRESULT Render();
};


// This is the cpp file

CFrame::CFrame(LPDIRECT3DDEVICE8 lpD3DDevice, CMesh *Mesh)
{
m_vOrientation = D3DXVECTOR3(0.00000001,0.00000001,0.00000001);
m_vVelocity = D3DXVECTOR3(0,0,0);
m_vPosition = D3DXVECTOR3(0,0,0);
D3DXMatrixIdentity(&m_mLocal);

m_D3DDevice = lpD3DDevice;

m_Mesh = Mesh;

}



HRESULT CFrame::Render()
{
HRESULT hr;
m_D3DDevice->SetTransform(D3DTS_WORLD, &m_mLocal);
hr = m_Mesh->Render();
return hr;
}

void CFrame::Rotate(D3DXVECTOR3 axis, long speed)
{

m_vOrientation += axis * (float)speed) / 10000.0f;
D3DXMatrixRotationYawPitchRoll(&mtxRot, m_vOrientation.x, m_vOrientation.y, m_vOrientation.z);

D3DXMatrixMultiply(&m_mLocal, &mtxRot, &m_mLocal);
}



As you can see, i'm using 0.00000001x0.00000001x0.00000001 as the orientation-vector. If i use a bigger value, the rotation will be much faster. If i use 0, there is no rotation.


The mesh-class have changed quite a lot so i'll post that too.

     
// This is the header (some old parts might still be in it)

class CMesh
{
public:
CMesh(LPDIRECT3DDEVICE8 lpD3DDevice, LPSTR Filename);
~CMesh();
HRESULT Render();

private:
LPD3DXMESH m_Mesh;
D3DMATERIAL8 *m_Materials;
LPDIRECT3DTEXTURE8 *m_Textures;
DWORD m_NumMaterials;
LPD3DXBUFFER m_MaterialsBuffer;
LPDIRECT3DDEVICE8 m_D3DDevice;
};


// This is the cpp-file, pretty much init-stuff, the only function that is left except for the constructor and the deconstructor is Render()


CMesh::CMesh(LPDIRECT3DDEVICE8 lpD3DDevice, LPSTR Filename)
{
HRESULT hr;
m_D3DDevice = lpD3DDevice;

Log.Log("Loading Model ",Filename);
if(FAILED(D3DXLoadMeshFromX(Filename, D3DXMESH_SYSTEMMEM, m_D3DDevice, NULL, &m_MaterialsBuffer, &m_NumMaterials, &m_Mesh)))
{
Log.Log("Could not load model ",Filename);
}


D3DXMATERIAL *d3dxMaterials = (D3DXMATERIAL*)m_MaterialsBuffer->GetBufferPointer();
m_Materials = new D3DMATERIAL8[m_NumMaterials];
m_Textures = new LPDIRECT3DTEXTURE8[m_NumMaterials];

for(DWORD i = 0; i < m_NumMaterials; i++)
{
m_Materials[i] = d3dxMaterials[i].MatD3D;
m_Materials[i].Ambient = m_Materials[i].Diffuse;


hr = D3DXCreateTextureFromFile(m_D3DDevice, d3dxMaterials[i].pTextureFilename, &m_Textures[i]);
if(hr==D3DERR_NOTAVAILABLE)
{
m_Textures[i] = NULL;
Log.Log(" Error, Not Avavible");
}
else if(hr==D3DERR_OUTOFVIDEOMEMORY)
{
m_Textures[i] = NULL;
Log.Log(" Error, Out of videomemory");
}
else if(hr==D3DERR_INVALIDCALL)
{
m_Textures[i] = NULL;
Log.Log(" Error, Invalid Call");
}
else if(hr==D3DXERR_INVALIDDATA)
{
m_Textures[i] = NULL;
Log.Log(" Error, Couldn't find texture", d3dxMaterials[i].pTextureFilename);
}
else if(hr==E_OUTOFMEMORY)
{
m_Textures[i] = NULL;
Log.Log(" Error, Out of memory");
}




}

m_MaterialsBuffer->Release();

Log.Log("Model Loaded");
}


CMesh::~CMesh()
{
if(m_Materials != NULL)
delete[] m_Materials;

if(m_Textures != NULL)
{
for(DWORD i = 0; i < m_NumMaterials; i++)
{
if(m_Textures[i])
m_Textures[i]->Release();
}
delete[] m_Textures;
}

if(m_Mesh != NULL)
m_Mesh->Release();


}

HRESULT CMesh::Render()
{
HRESULT r = E_FAIL;

for (int i = 0; i < m_NumMaterials; i++)
{
//m_Materials[i].Update();

m_D3DDevice->SetMaterial(&m_Materials[i]);
m_D3DDevice->SetTexture(0, m_Textures[i]);
r = m_Mesh->DrawSubset(i);
}

// Reset the vertexshader here when (if) i will use one

return r;
}





[edited by - ZitherMan on May 13, 2003 11:58:56 AM]

[edited by - ZitherMan on May 16, 2003 10:56:44 AM]

Share this post


Link to post
Share on other sites
I just wanted you guys to know that i''m still stuck

It seems like the mesh rotates around the point where the camera starts.

Share this post


Link to post
Share on other sites

  
void CFrame::Rotate(D3DXVECTOR3 axis, long speed){ m_vOrientation += axis * (float)speed) / 10000.0f; D3DXMatrixRotationYawPitchRoll(&mtxRot, m_vOrientation.x, m_vOrientation.y, m_vOrientation.z); D3DXMatrixMultiply(&m_mLocal, &mtxRot, &m_mLocal);}



try resetting your mesh matrix to identity before myltiplying
since your are rotating with acceleration ...

also you can't just add orientation forever ... it should wrap around some value .... I use degrees it should be reset after 360



[edited by - thy MC on May 20, 2003 12:50:15 PM]

Share this post


Link to post
Share on other sites
..first of all...I have to admit...I didn''t read all the way through your last snippet of source code...so forgive me if my assumption is incorrect....

..but...from your last screenshot...it looks like your building your matrix wrong.

The order of transformation is very important. You don''t get the same results if you do the translation first and then the rotation or if you do the rotation and then the translation.

From your screenshot, it looks like you''re doint the translation first and then the rotation....which would be wrong...

...you have to do the rotation first and then do the translation...that should work just fine....

...the rotation happens around the World 0,0,0 ....


....maybe I missed the point....hope it was the solution to your problem though....

Share this post


Link to post
Share on other sites
Thanks for your replies.

djc: you''re right. I did translate before i rotated, but unfortenantly it didnt make any difference

I have positioned it on 0,0,0 already, but it''s still spinning around the cameras original position (which i also set to 0,0,0, and it is not positioned in the same place as the mesh, and yes, my pivot-point is correct (if the 3ds to .x tool which comes with dxsdk 7 doesnt change this horribly)

However, when i try to set the mesh on some other place in the init, it still shows up in the same place.



argh, i cant get my head around this

Share this post


Link to post
Share on other sites
I''m still stuck with this problem


Is there anyone who maybe could give me their source for THEIR mesh-handling (including rotation) so i can see how you did it? I have already made the base for mine, so i wont steal the whole thing. The only thing i want to do is to see how you did it.

Share this post


Link to post
Share on other sites
I''ve got the same problem. It''s just that the pivot is wrong. Pivot (0, 0, 0) doesn''t mean world coordinates. It means local coordinates. So how do you turn the local pivot into world coordinates?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
im only just starting with the 3D stuff, but try

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/TutorialsAndSamples/Tutorials/tutorials.asp

for help. thats what i used to get my head around the meshes along with the transformation tutorials from two kings:

http://www.riaz.de/index.html

have a look through all that and if it still doesnt help then i''ll paste some of my code in here. I would do it now, but its such a mess that i doubt it will be any help to you.

Share this post


Link to post
Share on other sites