//
-----------------------------------------------------------------------------
//
File: Matrices.cs
//
//
Desc: Now that we know how to create a device and render some 2D vertices,
//
this tutorial goes the next step and renders 3D geometry. To deal with
//
3D geometry we need to introduce the use of 4x4 matrices to transform
//
the geometry with translations, rotations, scaling, and setting up our
//
camera.
//
//
Geometry is defined in model space. We can move it (translation),
//
rotate it (rotation), or stretch it (scaling) using a world transform.
//
The geometry is then said to be in world space. Next, we need to
//
position the camera, or eye point, somewhere to look at the geometry.
//
Another transform, via the view matrix, is used, to position and
//
rotate our view. With the geometry then in view space, our last
//
transform is the projection transform, which "projects" the 3D scene
//
into our 2D viewport.
//
//
Note that in this tutorial, we are introducing the use of D3DX, which
//
is a set of helper utilities for D3D. In this case, we are using some
//
of D3DX's useful matrix initialization functions. To use D3DX, simply
//
include the D3DX reference in your project
//
//
Copyright (c) Microsoft Corporation. All rights reserved.
//
-----------------------------------------------------------------------------
using
System;
using
System.Drawing;
using
System.Windows.Forms;
using
Microsoft.DirectX;
using
Microsoft.DirectX.Direct3D;
using
Direct3D
=
Microsoft.DirectX.Direct3D;
namespace
MatricesTutorial
{
public
class
Matrices : Form
{
//
Our global variables for this project
Device device
=
null
;
//
Our rendering device
VertexBuffer vertexBuffer
=
null
;
PresentParameters presentParams
=
new
PresentParameters();
bool
pause
=
false
;
public
Matrices()
{
//
Set the initial size of our form
this
.ClientSize
=
new
System.Drawing.Size(
400
,
300
);
//
And it's caption
this
.Text
=
"
Direct3D Tutorial 3 - Matrices
"
;
}
public
bool
InitializeGraphics()
{
try
{
//
Now let's setup our D3D stuff
presentParams.Windowed
=
true
;
presentParams.SwapEffect
=
SwapEffect.Discard;
device
=
new
Device(
0
, DeviceType.Hardware,
this
, CreateFlags.SoftwareVertexProcessing, presentParams);
device.DeviceReset
+=
new
System.EventHandler(
this
.OnResetDevice);
this
.OnCreateDevice(device,
null
);
this
.OnResetDevice(device,
null
);
pause
=
false
;
return
true
;
}
catch
(DirectXException)
{
return
false
;
}
}
public
void
OnCreateDevice(
object
sender, EventArgs e)
{
Device dev
=
(Device)sender;
//
Now Create the VB
vertexBuffer
=
new
VertexBuffer(
typeof
(CustomVertex.PositionColored),
3
, dev,
0
, CustomVertex.PositionColored.Format, Pool.Default);
vertexBuffer.Created
+=
new
System.EventHandler(
this
.OnCreateVertexBuffer);
this
.OnCreateVertexBuffer(vertexBuffer,
null
);
}
public
void
OnResetDevice(
object
sender, EventArgs e)
{
Device dev
=
(Device)sender;
//
Turn off culling, so we see the front and back of the triangle
dev.RenderState.CullMode
=
Cull.None;
//
Turn off D3D lighting, since we are providing our own vertex colors
dev.RenderState.Lighting
=
false
;
}
public
void
OnCreateVertexBuffer(
object
sender, EventArgs e)
{
VertexBuffer vb
=
(VertexBuffer)sender;
CustomVertex.PositionColored[] verts
=
(CustomVertex.PositionColored[])vb.Lock(
0
,
0
);
verts[
0
].X
=-
1.0f
; verts[
0
].Y
=-
1.0f
; verts[
0
].Z
=
0.0f
; verts[
0
].Color
=
System.Drawing.Color.DarkGoldenrod.ToArgb();
verts[
1
].X
=
1.0f
; verts[
1
].Y
=-
1.0f
;verts[
1
].Z
=
0.0f
; verts[
1
].Color
=
System.Drawing.Color.MediumOrchid.ToArgb();
verts[
2
].X
=
0.0f
; verts[
2
].Y
=
1.0f
; verts[
2
].Z
=
0.0f
; verts[
2
].Color
=
System.Drawing.Color.Cornsilk.ToArgb();
vb.Unlock();
}
private
void
Render()
{
if
(device
==
null
)
return
;
if
(pause)
return
;
//
Clear the backbuffer to a blue color
device.Clear(ClearFlags.Target, System.Drawing.Color.Blue,
1.0f
,
0
);
//
Begin the scene
device.BeginScene();
//
Setup the world, view, and projection matrices
SetupMatrices();
device.SetStreamSource(
0
, vertexBuffer,
0
);
device.VertexFormat
=
CustomVertex.PositionColored.Format;
device.DrawPrimitives(PrimitiveType.TriangleList,
0
,
1
);
//
End the scene
device.EndScene();
device.Present();
}
private
void
SetupMatrices()
{
//
For our world matrix, we will just rotate the object about the y-axis.
//
Set up the rotation matrix to generate 1 full rotation (2*PI radians)
//
every 1000 ms. To avoid the loss of precision inherent in very high
//
floating point numbers, the system time is modulated by the rotation
//
period before conversion to a radian angle.
int
iTime
=
Environment.TickCount
%
1000
;
float
fAngle
=
iTime
*
(
2.0f
*
(
float
)Math.PI)
/
1000.0f
;
device.Transform.World
=
Matrix.RotationY( fAngle );
//
Set up our view matrix. A view matrix can be defined given an eye point,
//
a point to lookat, and a direction for which way is up. Here, we set the
//
eye five units back along the z-axis and up three units, look at the
//
origin, and define "up" to be in the y-direction.
device.Transform.View
=
Matrix.LookAtLH(
new
Vector3(
0.0f
,
3.0f
,
-
5.0f
),
new
Vector3(
0.0f
,
0.0f
,
0.0f
),
new
Vector3(
0.0f
,
1.0f
,
0.0f
) );
//
For the projection matrix, we set up a perspective transform (which
//
transforms geometry from 3D view space to 2D viewport space, with
//
a perspective divide making objects smaller in the distance). To build
//
a perpsective transform, we need the field of view (1/4 pi is common),
//
the aspect ratio, and the near and far clipping planes (which define at
//
what distances geometry should be no longer be rendered).
device.Transform.Projection
=
Matrix.PerspectiveFovLH( (
float
)Math.PI
/
4
,
1.0f
,
1.0f
,
100.0f
);
}
protected
override
void
OnPaint(System.Windows.Forms.PaintEventArgs e)
{
this
.Render();
//
Render on painting
}
protected
override
void
OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
{
if
((
int
)(
byte
)e.KeyChar
==
(
int
)System.Windows.Forms.Keys.Escape)
this
.Close();
//
Esc was pressed
}
protected
override
void
OnResize(System.EventArgs e)
{
pause
=
((
this
.WindowState
==
FormWindowState.Minimized)
||
!
this
.Visible);
}
/**/
///
<summary>
///
The main entry point for the application.
///
</summary>
static
void
Main()
{
using
(Matrices frm
=
new
Matrices())
{
if
(
!
frm.InitializeGraphics())
//
Initialize Direct3D
{
MessageBox.Show(
"
Could not initialize Direct3D. This tutorial will exit.
"
);
return
;
}
frm.Show();
//
While the form is still valid, render and process messages
while
(frm.Created)
{
frm.Render();
Application.DoEvents();
}
}
}
}
}
// Set up the world, view, and projection matrices.
private void SetupMatrices()
{
// For our world matrix, we will just rotate the object about the y-axis.
// Set up the rotation matrix to generate 1 full rotation (2*PI radians)
// every 1000 ms. To avoid the loss of precision inherent in very high
// floating point numbers, the system time is modulated by the rotation
// period before conversion to a radian angle.
int iTime = Environment.TickCount % 1000;
float fAngle = iTime * (2.0f * (float)Math.PI) / 1000.0f;
device.Transform.World = Matrix.RotationY( fAngle );
// Set up our view matrix. A view matrix can be defined given an eye point,
// a point to lookat, and a direction for which way is up. Here, we set the
// eye five units back along the z-axis and up three units, look at the
// origin, and define "up" to be in the y-direction.
device.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 3.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) );
// For the projection matrix, we set up a perspective transform (which
// transforms geometry from 3D view space to 2D viewport space, with
// a perspective divide making objects smaller in the distance). To build
// a perpsective transform, we need the field of view (1/4 pi is common),
// the aspect ratio, and the near and far clipping planes (which define at
// what distances geometry should be no longer be rendered).
device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );
}