Transformations CU_MDX_Transformations.zip (64.3 KiB, 2,573 hits) CUnitFramework.zip (101.1 KiB, 20,514 hits)

Extract the C-Unit Framework
inside the project (not solution) directory.

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, we’ll creat a class, WorldTransform, 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.

namespace CUnit
{
/// World matrix wrapper
public class WorldTransform
{
private Matrix m_translate;
private Matrix m_rotate;
private Matrix m_scale;
float m_rotationX, m_rotationY, m_rotationZ;

/// Creates a new WorldTransform
public WorldTransform() {
Reset();
}

/// Reset the matrices to default position.
public void Reset() {
m_translate = Matrix.Identity;
m_rotate = Matrix.Identity;
m_scale = Matrix.Identity;
m_rotationX = m_rotationY = m_rotationZ = 0.0f;
}

/// Absolute translation
/// X
/// Y
/// Z
public void TranslateAbs( float x, float y, float z ) {
m_translate.M41 = x;
m_translate.M42 = y;
m_translate.M43 = z;
}

/// Absolute translation
/// Translations vector
public void TranslateAbs( Vector3 translation ) {
TranslateAbs( translation.X, translation.Y, translation.Z );
}

/// Relative translation
/// X
/// Y
/// Z
public void TranslateRel( float x, float y, float z ) {
m_translate.M41 += x;
m_translate.M42 += y;
m_translate.M43 += z;
}

/// Relative translation
/// Translations vector
public void TranslateRel( Vector3 translation ) {
TranslateRel( translation.X, translation.Y, translation.Z );
}

/// Absolute rotation
public void RotateAbs( float x, float y, float z ) {
m_rotationX = x;
m_rotationY = y;
m_rotationZ = z;
m_rotate = Matrix.RotationYawPitchRoll( y, x, z );
}

/// Relative rotation
public void RotateRel( float x, float y, float z ) {
m_rotationX += x;
m_rotationY += y;
m_rotationZ += z;
m_rotate = Matrix.RotationYawPitchRoll( m_rotationY, m_rotationX, m_rotationZ );
}

/// Absolute scale.
/// X
/// Y
/// Z
public void ScaleAbs( float x, float y, float z ) {
m_scale.M11 = x;
m_scale.M22 = y;
m_scale.M33 = z;
}

/// Relative scale
/// X
/// Y
/// Z
public void ScaleRel( float x, float y, float z ) {
m_scale.M11 += x;
m_scale.M22 += y;
m_scale.M33 += z;
}

/// The combined transformation matrix.
public Matrix Transform {
get
{
return  m_scale * m_rotate * m_translate;
}
}

/// Gets and sets the position vector
public Vector3 Position {
get { return new Vector3( m_translate.M41, m_translate.M42, m_translate.M43 ); }
set
{
m_translate.M41 = value.X;
m_translate.M42 = value.Y;
m_translate.M43 = value.Z;
}
}

/// Absolute x position.
public float XPosition {
get { return m_translate.M41; }
set { m_translate.M41 = value; }
}

/// Absolute y position.
public float YPosition {
get { return m_translate.M42; }
set { m_translate.M42 = value; }
}

/// Absolute z position.
public float ZPosition {
get { return m_translate.M43; }
set { m_translate.M43 = value; }
}

/// Absolute x rotation.
public float XRotation {
get { return m_rotationX; }
set { RotateAbs( value, m_rotationY, m_rotationZ ); }
}

/// Absolute y rotation.
public float YRotation {
get { return m_rotationY; }
set { RotateAbs( m_rotationX, value, m_rotationZ ); }
}

/// Absolute z rotation.
public float ZRotation {
get { return m_rotationZ; }
set { RotateAbs( m_rotationX, m_rotationY, value ); }
}

/// Absolute x scale.
public float XScale {
get { return m_scale.M11; }
set { m_scale.M11 = value; }
}

/// Absolute y scale.
public float YScale {
get { return m_scale.M22; }
set { m_scale.M22 = value; }
}

/// Absolute z scale.
public float ZScale {
get { return m_scale.M33; }
set { m_scale.M33 = value; }
}

}
}

The WorldTransform 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 Matrix.RotationYawPitchRoll.

The Transform property 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.

private float Xdirection = 3f;
private float Ydirection = 3f;
private float scale = 1f;

/// Updates a frame prior to rendering.
/// The Direct3D device
/// Time elapsed since last frame
public override void OnUpdateFrame( Device device, float elapsedTime )
{
// Translation
m_transform.TranslateRel( Xdirection * elapsedTime, Ydirection * elapsedTime, 0f );
if ( m_transform.XPosition > 4f || m_transform.XPosition < –4f )
{
m_transform.XPosition = Math.Max( –4f, m_transform.XPosition );
m_transform.XPosition = Math.Min( 4f, m_transform.XPosition );
Xdirection *= –1f;
}
if ( m_transform.YPosition > 4f || m_transform.YPosition < –4f )
{
m_transform.YPosition = Math.Max( –4f, m_transform.YPosition );
m_transform.YPosition = Math.Min( 4f, m_transform.YPosition );
Ydirection *= –1f;
}

// Rotation
m_transform.RotateRel( 0f, 0f, 6.28f * elapsedTime );

// Scale
float _scale = scale * elapsedTime;
m_transform.ScaleRel( _scale, _scale, _scale );
if ( m_transform.XScale > 2f || m_transform.XScale < 0.5f )
{
m_transform.XScale = Math.Max( 0.5f, m_transform.XScale );
m_transform.XScale = Math.Min( 2f, m_transform.XScale );
scale *= –1.0f;
}
}

Transforming geometry is made easy with the WorldTransform class. Each frame, we can update_ the transform by applying a translation, rotation, and a scale. Notice that I am multiplying the amount to transform by the elapsedTime passed into the method. This is necessary in order to have a consistent animation speed over different machines. We’ll go over how to get this value in a later tutorial.

/// Renders the current frame.
/// The Direct3D device
/// Time elapsed since last frame
public override void OnRenderFrame( Device device, float elapsedTime )
{
device.Clear( ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0 );
device.BeginScene();

// Clip…

// Render buffer
device.VertexFormat = PositionColored.Format;
device.Transform.World = m_transform.Transform;
device.SetStreamSource( 0, m_vb4, 0, PositionColored.StrideSize );
device.Indices = m_ib4;
device.DrawIndexedPrimitives( PrimitiveType.TriangleList, 0, 0, 4, 0, 2 );

// Clip…

device.EndScene();
device.Present();
}

When we render the geometry, all we do is set the world transform of the device to the matrix created by the WorldTransform class.

On to the next tutorial!