Using D3DXMatrixTransformation2D in DX9

Started by
9 comments, last by Supernat02 19 years, 7 months ago
I'm having a little bit of trouble rotating my 2D sprite. I'm using textured quads and I'm trying to write my blit function. It works fine, until I'm going to add rotation, which looks like this:

// ... Fill the vertices

    // Check if we need to rotate the texture
    if (fRotate != 0)
    {
        D3DXVECTOR2 vCenter(m_ImgInfo.Width / 2.0f, m_ImgInfo.Height / 2.0f);
        D3DXVECTOR2 vScale(1.0f, 1.0f);
        D3DXVECTOR2 vRotCenter(m_ImgInfo.Width / 2.0f, m_ImgInfo.Height / 2.0f);
        D3DXMatrixTransformation2D(&matRotation, &vCenter, NULL, &vScale, &vRotCenter, fRotate, NULL);
        pRender->m_pDevice->SetTransform(D3DTS_WORLD, &matRotation);
    }

    // Unlock the vertexbuffer
    pRender->m_VertexBuffer->Unlock();

    // Draw the texture
    pRender->m_pDevice->SetTexture(0, this->m_lpTexture);
    return (pRender->m_pDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2));

What's wrong with this code? Toolmaker

Advertisement
Nothing's wrong with your code. When you say your 2D sprite, I assume you created your own sprite from a transformed quad. In other words, you're using XYZ_RHW right? Think about the name given to the vertices. It's "transformed vertices". Now that you think about it, it probably makes more sense. You can't use the World, View, or Projection transforms when drawing pre-transformed vertices (that's your job to transform them). You have to rotate the object yourself. If you just take each vertex and multiply it by your transformation matrix, then save the vertices, you should be set. It's a vector multiplied by a matrix. It should be easy to calculate with simple matrix multiplication or you could use a helper function.

Good luck,
Chris
Chris ByersMicrosoft DirectX MVP - 2005
So instead of using SetTransform I need to multiply all the x and y values in the vertices?

In case you want to know how I fill my vertices:
    TLVERTEX *vertices;    D3DXMATRIX matRotation;    pRender->m_VertexBuffer->Lock(0, 0, (void**)&vertices, NULL);        vertices[0].colour = VertexColor;    vertices[0].x = (float) pDest->left - 0.5f;    vertices[0].y = (float) pDest->top - 0.5f;    vertices[0].z = 0.0f;    vertices[0].rhw = 1.0f;    vertices[0].v = 0.0f;    vertices[0].u = 0.0f;    vertices[1].colour = VertexColor;    vertices[1].x = (float) pDest->right - 0.5f;    vertices[1].y = (float) pDest->top - 0.5f;    vertices[1].z = 0.0f;    vertices[1].rhw = 1.0f;    vertices[1].u = 1.0f;    vertices[1].v = 0.0f;    vertices[2].colour = VertexColor;    vertices[2].x = (float) pDest->right - 0.5f;    vertices[2].y = (float) pDest->bottom - 0.5f;    vertices[2].z = 0.0f;    vertices[2].rhw = 1.0f;    vertices[2].u = 1.0f;    vertices[2].v = 1.0f;    vertices[3].colour = VertexColor;    vertices[3].x = (float) pDest->left - 0.5f;    vertices[3].y = (float) pDest->bottom - 0.5f;    vertices[3].z = 0.0f;    vertices[3].rhw = 1.0f;    vertices[3].u = 0.0f;    vertices[3].v = 1.0f;

Anyone? I'm stuck here :( I have no clue how to handle this

Did you change the values of the vertices after the rotation was implemented as Chris said? Because its not going to work with the same values of pretransformed vertices.
It would go something like this:

void TransformMe(D3DXMATRIX fpMatrix){  pMesh->LockVertexBuffer(0, (void**)&pData);  for (int x=0; x < NumVertices; x++)  {    pStruct = (DataStruct*)pData;    NewPosition.x = (*fpMatrix)._11*pStruct->Position.x +                     (*fpMatrix)._21*pStruct->Position.y +                     (*fpMatrix)._31*pStruct->Position.z +                     (*fpMatrix)._41;    NewPosition.y = (*fpMatrix)._12*pStruct->Position.x +                     (*fpMatrix)._22*pStruct->Position.y +                     (*fpMatrix)._32*pStruct->Position.z +                     (*fpMatrix)._42;    NewPosition.z = 0;    NewPosition.w = 1;    pStruct->Position = NewPosition;    pData += NumBytes;  }  pMesh->UnlockVertexBuffer(); }


pMesh is an ID3DXMesh interface, but you can just lock a vertex buffer. You can remove the NewPosition.z value or just set it to 0 (I removed it for you). NewPosition is a 4D float vector and represents your XYZ_RHW values. Position is also a 4D float vector in your FVF structure and represents the same thing. I modified the code a little, since this comes from what I do to 3D stuff, but you can further reduce it if you want. The way it is above, just be sure you use the D3DXMatrixTransformation2D function to get a proper transform passed in, which you are doing.

Chris
Chris ByersMicrosoft DirectX MVP - 2005
I have no clue about the other code, I'm a pure n00b at this. Perhaps I should get a book that covers 2D game engine in D3D9 extensively. Are there any hints for that?

As for now, I've tried this code, which a friend gave me and worked for him, but not for me for a reason:
	D3DXMATRIX matPosition, matRotation, matScaling, matTransform;	D3DXMatrixScaling(&matScaling, 1.0f, 1.0f, 1.0f );	D3DXMatrixTranslation( &matPosition, (float)(pDest->left + pDest->right) / 2.0f, (float)(pDest->top + pDest->bottom) / 2.0f, 0.0f );	//Set the Rotation Matrix	D3DXMatrixRotationZ( &matRotation, fRotation );	D3DXMatrixMultiply( &matTransform, &matScaling, &matPosition );	D3DXMatrixMultiply( &matTransform, &matRotation, &matTransform );	//D3DXMatrixMultiply( &matTransform, &matScaling, &matRotation );	pRender->m_pDevice->SetTransform( D3DTS_WORLD, &matTransform );	//pRender->m_pDevice->SetVertexShader(NULL);	//pRender->m_pDevice->SetStreamSource(0, pRender->m_VertexBuffer, 0, sizeof(TLVERTEX));	    // Draw the texture    pRender->m_pDevice->SetTexture(0, this->m_lpTexture);    return (pRender->m_pDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2));


Ideas?

The thing to understand is that there are 2 types of vertices: Transformed and Untransformed. Well that's not entirely true, but any vertice will be in one of these two groups when it travels through the video card pipeline.

Untransformed vertices are a given when using the D3DFVF_XYZ type. The position vector (3 floats) in your FVF structure define the units in world space. The units are just floating point numbers, where their size is relative to the projection matrix. These units can be transformed by two other matrices (well they are transformed by the projection matrix obviously as I've stated): the View matrix and the World transform matrix. The view matrix and world transform matrix aren't special. You could set one to Identity (that is 1's in the diagonal of the matrix, 0 everywhere else), and use the other as if it was just both of them combined. For example:

View = Identity;
World = MyWorld*MyView; // I can't remember if this is the right order of multiplication, it doesn't matter, that's not my point.

For simplicity, the video card pipeline just takes Untransformed vertices and multiplies them through the 3 matrices, World, View, and Projection. Once multiplied through these matrices, the new vertex is considered to be in Screen Space. It is a vertex that was defined by some 3D point in world space and is now defined as an X,Y pixel in Screen Space.

Transformed vertices are a given when using the D3DFVF_XYZ_RHW type. The position vector (2 floats) in your FVF structure define the pixels from top/left corner of the screen. For simplicity's sake, the z value and w value (another 2 floats) after that are just set to 0 and 1 respectively. Don't get bogged down in what they do yet. These vertices, in their Transformed state, are considered to already be in Screen Space, therefore no projection, view, or world matrices in the video card pipeline are multiplied into the position vector.

The D3DXSprite interface uses transformed vertices, but it has a function SetTransform() that will just move the vertices around (scale, translate, and rotate them) manually, without using the graphics card pipeline.

Now for the reason for all of that. The code your friend gave you can not move a series of vertices created with D3DFVF_XYZ_RHW. The code will move a series of vertices created with D3DFVF_XYZ. Does this all make a little more sense, or did you know all of this already and I'm just assuming too much?

I can't recommend a book on 2D that I've read, because I haven't read any. There are some out there, probably in the Andre LaMothe Game Development series.

Good luck,
Chris
That was me, sorry, it logged me out...guess I spent too long writing it :)

Chris
Chris ByersMicrosoft DirectX MVP - 2005
Wow, that makes. Sense! Thanks for the long answer.

In other words, I just need to turn my vertex into XYZ form. I'll try that later today. And perhaps I'm going to switch back to the ID3DXSprite interface and try it a bit more.

Thanks!

++Supernat02->Rating;

This topic is closed to new replies.

Advertisement