D3DXMatrixRotationY Query

Started by
13 comments, last by Kram 16 years, 1 month ago
Hello All, I have a question about the D3DXMatrixRotationY method. Currently I have a nice spinning cube in my app, and I was wanting to be able to shift the cube left, right, up and down with the keyboard. This I can do, but when the cube is spinning and I shift the cube along the X axis, the spinning starts to become more of a wide rotation around the world Y axis. My question, is how do I make the cube rotate around its own Y axis, and not the world Y axis? I am currently doing it like this:

static float index = 0.0f; index+=0.03f;    // an ever-increasing float value
D3DXMATRIX matRotateY;
D3DXMatrixRotationY(&matRotateY, index);
p_d3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY));

(Although i dont really understand that D3DXMATRIX stuff yet). Do I just need to change the D3DTS_WORLD parameter to something else? Thanks a lot! Mark
Advertisement
Matrices are not like normal numbers.
For example:
You have the number 5 and 3. 5 * 3 = 15. But 3 * 5 = 15 too.

With matrices you have to multiplicate the matrices in a certain order. Lets say you first translate it. And then start to rotate it (this is what's happening in your case)

You first move it along the x-axis, and then you start to rotate around (0, 0, 0), this is because matrices work that way.

What you want to do is first rotate, and then translate. What happens is: You start to rotate around (0, 0, 0), so it rotates like you want it too. And then you apply the translation.

In code (did not check for errors):

float index = 0.0f;index += 0.03f;D3DXMATRIX matTranslation;D3DXMATRIX matRotation;D3DXMATRIX matResult;D3DXMatrixTranslateX(&matTranslation, 5.0f); //don't know if this function existsD3DXMatrixRotationY(&matRotation, index);matResult = matRotation * matTranslation;//apply matResult
Ah, you know what Max, that is probably exactly what I am doing! I'll have a look tonight after work. Thanks for the advice.
actually I dont know what the issue is, here is the code for my game entity's render method:

void GameEntity::Render(IDirect3DDevice9* p_d3dDevice){	// select which vertex format we are using    p_d3dDevice->SetFVF(CUSTOMFVF);    // set the view transform    D3DXMATRIX matView;    // the view transform matrix    D3DXMatrixLookAtLH(&matView,    &D3DXVECTOR3 (0.0f, 8.0f, 25.0f),					// the camera position    &D3DXVECTOR3 (0.0f, 0.0f, 0.0f),					// the look-at position    &D3DXVECTOR3 (0.0f, 1.0f, 0.0f));					// the up direction    p_d3dDevice->SetTransform(D3DTS_VIEW, &matView);    // set the projection transform    D3DXMATRIX matProjection;    // the projection transform matrix    D3DXMatrixPerspectiveFovLH(&matProjection,                               D3DXToRadian(45),    // the horizontal field of view                               (FLOAT)640 / (FLOAT)480, // aspect ratio                               1.0f,    // the near view-plane                               500.0f);    // the far view-plane    p_d3dDevice->SetTransform(D3DTS_PROJECTION, &matProjection);    // set the world transform    static float index = 0.0f; index+=0.03f;    // an ever-increasing float value    D3DXMATRIX matRotateY;						// a matrix to store the rotation    D3DXMatrixRotationY(&matRotateY, index);    // the rotation matrix    p_d3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY));    // set the world transform    // select the vertex buffer to display    p_d3dDevice->SetStreamSource(0, this->GetVertexBuffer(), 0, sizeof(CUSTOMVERTEX));    // set the texture    p_d3dDevice->SetTexture(0, m_triangleTexture);    // draw the textured square    p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);    p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);    p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 8, 2);    p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 12, 2);    p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 16, 2);    p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 20, 2); }


What I should mention too is that when I press the keyboard keys to move the object left and right, this is the code that does it:

void GameEntity::MoveRight(){	std::vector<CUSTOMVERTEX>::iterator vectorIterator;	for(vectorIterator = m_vertices.begin(); vectorIterator != m_vertices.end(); ++vectorIterator)		vectorIterator->X -= MOVEMENT_SIZE;	SetupVertexBuffer();}void GameEntity::MoveLeft(){	std::vector<CUSTOMVERTEX>::iterator vectorIterator;	for(vectorIterator = m_vertices.begin(); vectorIterator != m_vertices.end(); ++vectorIterator)		vectorIterator->X += MOVEMENT_SIZE;	SetupVertexBuffer();}


so when this happens, the cube still rotates around the Y axis, but is offset on the X axis byt how many times you've hit the keys...

I hope someone can help with this.

Thanks
Mark
You're modifying the locations of your vertices to translate your mesh. That's why it doesn't work. Because you're modifying the vertices themselves, they have an offset position in local space. When you transform it into world space, the rotation occurs about the origin of the cube (which is no longer the centre of the cube since you moved it). In other words, you're performing translation before rotation, when it should be the other way around. Modifying every vertex like that is horrificly slow, anyway.

The solution is to use a proper world matrix to move and rotate your cube. D3DX provides the D3DXMatrixTranslation() function to produce a translation matrix. You then multiply it by your rotation matrix to produce the desired output. Remember, rotation comes before translation. So remember to do matRotate * matTranslate, not matTranslate * matRotate!

D3DX also provides functions such as D3DXMatrixAffineTransformation(), which performs all this for you. But it may be a little heavy-weight for this application (and you'll need to use quaternions).
NextWar: The Quest for Earth available now for Windows Phone 7.
Ok so let me see if I have this correct.

When I load the app, I have a simple spinning cube, which is rotating on the Y axis.

When I then hit the Right keyboard key, I increase the X axis location of the cubes vertices (which I see is slow).

Then in the transformation, I am shifting the cube along the X axis, THEN I am rotating the cube, which is rotating around an axis that has moved?

I sort of understand what to do to fix it, but in the design should I store sort of member variables like m_xOffset and m_yOffset, then in the Render() method, use this as the parameters of the D3DXMatrixTranslation method?

Thanks for the help, this translation stuff is getting me a little confused!
Quote:Original post by Kram
Then in the transformation, I am shifting the cube along the X axis, THEN I am rotating the cube, which is rotating around an axis that has moved?

Essentially. Since you modified the location of the cube's vertices (when you press the right/left key), the cube is no longer centred around the origin. Since the rotation happens about the origin, your cube will appear to "orbit" a certain location.


Quote:I sort of understand what to do to fix it, but in the design should I store sort of member variables like m_xOffset and m_yOffset, then in the Render() method, use this as the parameters of the D3DXMatrixTranslation method?

Yep.
NextWar: The Quest for Earth available now for Windows Phone 7.
Sweet, and it works well. Thanks for the help!

I suppose I should also ask then, if I was going to shift the cube from one location to another when the user clicks the mouse button, how would I go about changing the x and y offset variables?

In other words, I know I cant just change the x and y offsets to be whatever the user clicks, I need to get the difference between where the user clicked (say 150,200) and the current "location" of the cube...

How would one do this?

Thanks again for the help!
I am having a similar problem and after reading this thread I still can not fix the problem. It looks as if the X is only moving half of its distance for me. However, how I do my transform may just be wrong.

void CPlane::Rotate(float fX, float fY, float fZ){	D3DXMatrixIdentity(&m_mTransform);	if(fX)	D3DXMatrixRotationX(&m_mTransform, fX);	if(fY)	D3DXMatrixRotationY(&m_mTransform, fY);	if(fZ)	D3DXMatrixRotationZ(&m_mTransform, fZ);	m_mTransform._41 = m_vLocation.GetX();	m_mTransform._42 = m_vLocation.GetY();	m_mTransform._43 = m_vLocation.GetZ();}

Quote:Original post by Kram
I suppose I should also ask then, if I was going to shift the cube from one location to another when the user clicks the mouse button, how would I go about changing the x and y offset variables?

In other words, I know I cant just change the x and y offsets to be whatever the user clicks, I need to get the difference between where the user clicked (say 150,200) and the current "location" of the cube...
Why? You want to set the new position of the cube to the position that was clicked, so you'll want to set the X and Y values to that position.

If you mean you want the cube to move over several frames, then yes - you'll need the old position, the new position, and the interpolation between then (0..1), and then just set the position to oldPos * (1-time) + newPos * time or similar.

Quote:Original post by simotix
I am having a similar problem and after reading this thread I still can not fix the problem. It looks as if the X is only moving half of its distance for me. However, how I do my transform may just be wrong.
Looks fine to me. What makes you think it's only moving half the distance?

This topic is closed to new replies.

Advertisement