CU_MDX_Transformations.zip (64.3 KB, 1,208 hits)
CUnitFramework.zip (101.1 KB, 12,582 hits)
inside the project (not solution) directory.
Recommended reading for this tutorial:
- Real-Time Rendering, Section 3.1: Basic Transforms
- MSDN’s transforms and matrices pages
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.
{
public class WorldTransform
{
private Matrix m_rotate;
private Matrix m_scale;
float m_rotationX, m_rotationY, m_rotationZ;
/// <summary>Creates a new WorldTransform</summary>
public WorldTransform()
}
/// <summary>Reset the matrices to default position.</summary>
public void Reset()
m_rotate = Matrix.Identity;
m_scale = Matrix.Identity;
m_rotationX = m_rotationY = m_rotationZ = 0.0f;
}
/// <summary>Absolute translation</summary>
/// <param name=”x”>X</param>
/// <param name=”y”>Y</param>
/// <param name=”z”>Z</param>
public void TranslateAbs( float x, float y, float z )
m_translate.M42 = y;
m_translate.M43 = z;
}
/// <summary>Absolute translation</summary>
/// <param name=”translation”>Translations vector</param>
public void TranslateAbs( Vector3 translation )
}
/// <summary>Relative translation</summary>
/// <param name=”x”>X</param>
/// <param name=”y”>Y</param>
/// <param name=”z”>Z</param>
public void TranslateRel( float x, float y, float z )
m_translate.M42 += y;
m_translate.M43 += z;
}
/// <summary>Relative translation</summary>
/// <param name=”translation”>Translations vector</param>
public void TranslateRel( Vector3 translation )
}
/// <summary>Absolute rotation</summary>
/// <param name=”x”>X radians</param>
/// <param name=”y”>Y radians</param>
/// <param name=”z”>Z radians</param>
public void RotateAbs( float x, float y, float z )
m_rotationY = y;
m_rotationZ = z;
m_rotate = Matrix.RotationYawPitchRoll( y, x, z );
}
/// <summary>Relative rotation</summary>
/// <param name=”x”>X radians</param>
/// <param name=”y”>Y radians</param>
/// <param name=”z”>Z radians</param>
public void RotateRel( float x, float y, float z )
m_rotationY += y;
m_rotationZ += z;
m_rotate = Matrix.RotationYawPitchRoll( m_rotationY, m_rotationX, m_rotationZ );
}
/// <summary>Absolute scale.</summary>
/// <param name=”x”>X</param>
/// <param name=”y”>Y</param>
/// <param name=”z”>Z</param>
public void ScaleAbs( float x, float y, float z )
m_scale.M22 = y;
m_scale.M33 = z;
}
/// <summary>Relative scale</summary>
/// <param name=”x”>X</param>
/// <param name=”y”>Y</param>
/// <param name=”z”>Z</param>
public void ScaleRel( float x, float y, float z )
m_scale.M22 += y;
m_scale.M33 += z;
}
/// <summary>The combined transformation matrix.</summary>
public Matrix Transform
{
}
}
/// <summary>Gets and sets the position vector</summary>
public Vector3 Position
set
{
m_translate.M42 = value.Y;
m_translate.M43 = value.Z;
}
}
/// <summary>Absolute x position.</summary>
public float XPosition
set { m_translate.M41 = value; }
}
/// <summary>Absolute y position.</summary>
public float YPosition
set { m_translate.M42 = value; }
}
/// <summary>Absolute z position.</summary>
public float ZPosition
set { m_translate.M43 = value; }
}
/// <summary>Absolute x rotation.</summary>
public float XRotation
set { RotateAbs( value, m_rotationY, m_rotationZ ); }
}
/// <summary>Absolute y rotation.</summary>
public float YRotation
set { RotateAbs( m_rotationX, value, m_rotationZ ); }
}
/// <summary>Absolute z rotation.</summary>
public float ZRotation
set { RotateAbs( m_rotationX, m_rotationY, value ); }
}
/// <summary>Absolute x scale.</summary>
public float XScale
set { m_scale.M11 = value; }
}
/// <summary>Absolute y scale.</summary>
public float YScale
set { m_scale.M22 = value; }
}
/// <summary>Absolute z scale.</summary>
public float ZScale
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 Ydirection = 3f;
private float scale = 1f;
/// <summary>Updates a frame prior to rendering.</summary>
/// <param name=”device”>The Direct3D device</param>
/// <param name=”elapsedTime”>Time elapsed since last frame</param>
public override void OnUpdateFrame( Device device, float elapsedTime )
{
m_transform.TranslateRel( Xdirection * elapsedTime, Ydirection * elapsedTime, 0f );
if ( m_transform.XPosition > 4f || m_transform.XPosition < -4f )
{
m_transform.XPosition = Math.Min( 4f, m_transform.XPosition );
Xdirection *= -1f;
}
if ( m_transform.YPosition > 4f || m_transform.YPosition < -4f )
{
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.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.
/// <param name=”device”>The Direct3D device</param>
/// <param name=”elapsedTime”>Time elapsed since last frame</param>
public override void OnRenderFrame( Device device, float elapsedTime )
{
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!