Transformations

  CU_Transformations.zip (34.0 KiB, 3,213 hits)

Recommended reading for this tutorial:

In 3D graphics, there are three basic transformations: translation, rotation, and scale. To transform our geometry, we have to manipulate the world matrix before rendering each separate piece of geometry. The specific manipulations required are described in any beginning graphics book or article such as the ones listed above.

To make things easier, I have created a class, CWorldTransform, that will handle all the transformations with simple method calls. In the future, other classes can derive from this class if they need their own world matrix to transform, rotate, and scale.

#ifndef CWORLDMATRIX_H 
#define CWORLDMATRIX_H
#include "stdafx.h"

class CWorldTransform
{
public:
CWorldTransform();
~CWorldTransform() { Reset(); }

void Reset();
void TranslateAbs( float x, float y, float z );
void TranslateRel( float x, float y, float z );
void RotateAbs( float x, float y, float z );
void RotateRel( float x, float y, float z );
void ScaleAbs( float x, float y, float z );
void ScaleRel( float x, float y, float z );

D3DXMATRIX* GetTransform();
float GetXPosition() { return m_translate._41; }
float GetYPosition() { return m_translate._42; }
float GetZPosition() { return m_translate._43; }
float GetXRotation() { return m_rotationX; }
float GetYRotation() { return m_rotationY; }
float GetZRotation() { return m_rotationZ; }
float GetXScale() { return m_scale._11; }
float GetYScale() { return m_scale._22; }
float GetZScale() { return m_scale._33; }

protected:
D3DXMATRIX m_translate;
D3DXMATRIX m_rotate;
D3DXMATRIX m_scale;
D3DXMATRIX m_transform;
float m_rotationX, m_rotationY, m_rotationZ;
};
#endif

Since a world transformations matrix is composed of three concatenated transformation matrices, the CWorldTransform class will store these matrices separately so we can manipulate them independantly. These matrices are the transformation matrix, the rotation matrix, and the scaling matrix. All the transformation methods above will manipulate these matrices.

#include “..\include\stdafx.h”
#include “..\include\CWorldTransform.h”

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Default Constructor
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
CWorldTransform::CWorldTransform() Toggle

{

Reset();

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Reset the matrices to default position.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CWorldTransform::Reset() Toggle

{

D3DXMatrixIdentity( &m_translate );
D3DXMatrixIdentity( &m_rotate );
D3DXMatrixIdentity( &m_scale );
D3DXMatrixIdentity( &m_transform );
m_rotationX = m_rotationY = m_rotationZ = 0.0f;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Absolute translation
Parameters:
[in] x – X position
[in] y – Y position
[in] z – Z position
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CWorldTransform::TranslateAbs( float x, float y, float z ) Toggle

{

m_translate._41 = x;
m_translate._42 = y;
m_translate._43 = z;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Relative translation
Parameters:
[in] x – X amount
[in] y – Y amount
[in] z – Z amount
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CWorldTransform::TranslateRel( float x, float y, float z ) Toggle

{

m_translate._41 += x;
m_translate._42 += y;
m_translate._43 += z;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Absolute rotation
Parameters:
[in] x – X radians
[in] y – Y radians
[in] z – Z radians
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CWorldTransform::RotateAbs( float x, float y, float z ) Toggle

{

m_rotationX = x;
m_rotationY = y;
m_rotationZ = z;
D3DXMatrixRotationYawPitchRoll( &m_rotate, y, x, z );

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Relative rotation
Parameters:
[in] x – X radians
[in] y – Y radians
[in] z – Z radians
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CWorldTransform::RotateRel( float x, float y, float z ) Toggle

{

m_rotationX += x;
m_rotationY += y;
m_rotationZ += z;
D3DXMatrixRotationYawPitchRoll( &m_rotate, m_rotationY, m_rotationX, m_rotationZ );

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Absolute scale.
Parameters:
[in] x – X size
[in] y – Y size
[in] z – Z size
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CWorldTransform::ScaleAbs( float x, float y, float z ) Toggle

{

m_scale._11 = x;
m_scale._22 = y;
m_scale._33 = z;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Relative scale.
Parameters:
[in] x – X size
[in] y – Y size
[in] z – Z size
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CWorldTransform::ScaleRel( float x, float y, float z ) Toggle

{

m_scale._11 += x;
m_scale._22 += y;
m_scale._33 += z;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Get the transformation matrix
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
D3DXMATRIX* CWorldTransform::GetTransform() Toggle

{

m_transform = m_scale * m_rotate * m_translate;
return &m_transform;

}

The CWorldTransform class contains methods to translate, rotate, and scale to either absolute values or relative to the current transformation. The translation and scaling values are the easiest to set because they can be put straight into their corresponding matrices. The rotation values, on the other hand, cannot be put directly into the rotation matrix. We need to create a rotation matrix by calling D3DXMatrixRotationYawPitchRoll.

The GetTransform method concatenates the 3 matrices together and returns the result. The order of the concatenation is important because matrix multiplication is noncommutative. The scaling matrix should be applied first, followed by the rotation matrix, and then the translation matrix.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Updates the current frame.
Parameters:
[in] pDevice – Pointer to a DIRECT3DDEVICE9 instance
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CGameApp::OnUpdateFrame( LPDIRECT3DDEVICE9 pDevice )
{

// Translation
m_transform.TranslateRel( g_Xdirection, g_Ydirection, 0.0f );
if ( m_transform.GetXPosition() > 3.0f || m_transform.GetXPosition() < –3.0f )
{

g_Xdirection *= –1.0f;

}
if ( m_transform.GetYPosition() > 4.0f || m_transform.GetYPosition() < –4.0f )
{

g_Ydirection *= –1.0f;

}

// Rotation
m_transform.RotateRel( 0.0f, 0.0f, 0.001f );

// Scale
m_transform.ScaleRel( g_scale, g_scale, g_scale );
if ( m_transform.GetXScale() > 2.0f || m_transform.GetXScale() < 0.5f )
{

g_scale *= –1.0f;

}

}

Transforming geometry is made easy with the CWorldTransform class. Each frame, I update the transform by applying a translation, rotation, and a scale.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Renders the current frame.
Parameters:
[in] pDevice – Pointer to a DIRECT3DDEVICE9 instance
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CGameApp::OnRenderFrame( LPDIRECT3DDEVICE9 pDevice )
{

pDevice->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 );
pDevice->BeginScene();

pDevice->SetTransform( D3DTS_WORLD, m_transform.GetTransform() );
m_VB.Render( pDevice, 2, D3DPT_TRIANGLELIST );

pDevice->EndScene();
pDevice->Present( 0, 0, 0, 0 );

}

When we render the geometry, we need to set the world transform of the device to the matrix created by the CWorldTransform class.

The square will transform at different speeds depending on how powerful your computer is. In the next tutorial, we will create a timer that will be used to keep a consistent animation speed.