Home | Course Index | Next >> | PDF Version of this Page |
Course 3D_MDX: 3D-Graphics with Managed DirectX 9.0
|
|
Let me know what you think |
Project triangle1 Form1, OnResize, OnTimer Using the VertexBuffer of the graphics card More triangles More movements Many triangles Chaos Exercises |
This project is the ManagedDirectX-clone of the C#-projects:
3D-Computer Graphics with XNA, Chapter C1: Moving Triangles and of
3D-Computer Graphics with C++ and OpenGL, Chapter C1: Moving Triangles.
This chapter is a synoptic summary of three Direct3D-Tutorials from Microsoft: Tutorial1, Tutorial2 und Tutorial3. You find the tutorials here: C:\DXSDK\Samples\Managed\Direct3D\Tutorials.
Main Menu after starting VS 2008: File → New Project... → Visual Studio installed templates: Windows Forms Application
Name: triangle1 → Location: C:\temp → Create directory for solution: switch it off → OK
Delete the files Program.cs and Form1.Designer.cs and the content of Form1.cs, as described in the chapters 2DCisC1 to 2DCisC4.
If You find no Solution Explorer-window, open it via the main menu: View → Solution Explorer.
Inside the Solution Explorer-window click the plus-sign in front of triangle1. A tree opens. Look for the branch "References". Right-click References and left-click Add Reference.... An Add Reference dialog box opens. Scroll down to the component name: Microsoft.DirectX Version 1.0.2902.0.
Highlight this reference by a left-click and (holding the Strg-key pressed) the reference Microsoft.DirectX.Direct3D Version 1.0.2902.0 somewhere below. Quit the Add Reference dialog box with OK.
Check if both references Microsoft.DirectX and Microsoft.DirectX.Direct3D are now visible inside the Solution Explorer window underneath triangle1 → References.
If You use Visual Studio 2008 Professional You should switch off the vexatious automatic format- and indent- mechanism of the code editor before You copy the following code to Form1.cs (otherwise all the code will be reformatted into chaos):
1. Main menu of Visual Studio 2008 Professional: click menu "Tools".
2. A DropDown-menu appears. Click "Options...".
3. An Options dialog box appears.
4. Click the branch "Projects and Solutions". Click "General". Redirect all three pathes to C:\temp.
5. Click the branch "Text Editor", then click "C#".
6. A sub-tree appears with the branches "General, Tabs, Advanced, Formatting, IntelliSense".
7. Click "Tabs". Change "Indenting" to None, "Tab size" and "Indent size" to 1 and switch on the option "Insert spaces".
8. Inside the sub-tree "C#" click the plus-sign in front of "Formatting" and change all "Formatting"-branches as follows:
"General": switch off all CheckBoxes, "Indentation": switch off all CheckBoxes, "New Lines": switch off all CheckBoxes, "Spacing": switch off all CheckBoxes, "Wrapping": switch on both CheckBoxes.
9. Leave the dialog box with button "OK".
Write the following code into the empty code window of Form1.cs:
using System; using System.Drawing; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; public class Form1 : Form { [STAThread] static void Main() { Application.Run( new Form1() ); } static Device device = null; static float fAngle; static CustomVertex.PositionColored[] v = new CustomVertex.PositionColored[3]; Timer myTimer = new Timer(); public Form1() { Text = "D3DTriangleAnimation"; //fill coordinates and colors into an array "v" v[0].X=-1f; v[0].Y=-1f; v[0].Z=0f; v[1].X= 1f; v[1].Y=-1f; v[1].Z=0f; v[2].X= 0f; v[2].Y= 1f; v[2].Z=0f; v[0].Color = System.Drawing.Color.DarkGoldenrod.ToArgb(); v[1].Color = System.Drawing.Color.MediumOrchid.ToArgb(); v[2].Color = System.Drawing.Color.Cornsilk.ToArgb(); myTimer.Tick += new EventHandler( OnTimer ); myTimer.Interval = 1; ClientSize = new Size( 400, 300 ); //Calls OnResize( ... ) } protected override void OnResize( System.EventArgs e ) //Whenever the window changes we have to initialize Direct3D from scratch { myTimer.Stop();// stop the timer during initialization try { //get information from the operating system about its current graphics properties PresentParameters presentParams = new PresentParameters(); //we have to set two extra flags presentParams.Windowed = true; //no full screen display presentParams.SwapEffect = SwapEffect.Discard; //no swap buffer //create a new D3D-device that serves as canvas if ( device != null ) device.Dispose(); //free the old canvas if any device = new Device( 0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams ); //set up the transformation of world coordinates into camera or view space device.Transform.View = Matrix.LookAtLH( new Vector3( 0f, 0f,-4f ), //eye point 4.0 in front of the canvas new Vector3( 0f, 0f, 0f ), //camera looks at point 0,0,0 new Vector3( 0f, 1f, 0f ) ); //world's up direction is the y-axis //set up the projection transformation using 4 parameters: //1.: field of view = 45 degrees; 2.: aspect ratio = width / height = 1 = square window; //3.: near clipping distance = 0; 4.: far clipping distance = 10; device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI/4, 1f, 0f, 10f ); //Turn off culling, so the user sees the front and back of the triangle device.RenderState.CullMode = Cull.None; //Turn off lighting, since the triangle provides its own colors device.RenderState.Lighting = false; //set up the property that fills the triangle with colors device.VertexFormat = CustomVertex.PositionColored.Format; myTimer.Start();//start the timer again } catch (DirectXException) { MessageBox.Show( "Could not initialize Direct3D." ); return; } } protected static void OnTimer( Object myObject, EventArgs myEventArgs ) { if (device == null) return; //throw the old image away device.Clear( ClearFlags.Target, Color.Blue, 1f, 0 ); //rotate with an angular velocity = 0.1 fAngle += 0.1f; device.Transform.World = Matrix.RotationY( fAngle ); //draw on the canvas device.BeginScene(); device.DrawUserPrimitives( PrimitiveType.TriangleList, 1, v ); device.EndScene(); device.Present(); // show the canvas } }
Click Debug → Start Without Debugging Ctrl F5. Try to drag all window borders.
Until now at any Timer-event triangle1 reads the triangle which has the form of the structure
Write the following declaration into the head of
VertexBuffer vertexBuffer;
Write the following code into the function
if ( vertexBuffer != null ) vertexBuffer.Dispose();//Free the old vertexBuffer if any. //Create a new vertex buffer on the graphics card and connect it to the device. vertexBuffer = new VertexBuffer( typeof(CustomVertex.PositionColored), 3, device, Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default ); vertexBuffer.SetData( v, 0, LockFlags.None );//Copy the vertices from main memory to graphics card memory. device.SetStreamSource( 0, vertexBuffer, 0 );//Tell the device to use the vertexBuffer on the graphics card.
Inside
device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 );
Click Debug → Start Without Debugging Ctrl F5. There is just a minimal performance benefit of approx. 10%. A more dramatic benefit will occur in case of larger polygons with more than 10 vertices.
Change the device.BeginScene(); - device.EndScene(); - clause inside
device.BeginScene(); device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 ); device.Transform.World = Matrix.Scaling( 0.5f, 0.5f, 0.5f ) * Matrix.Translation( 1f, 0f, 0f ); device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 ); device.Transform.World = Matrix.Scaling( 0.5f, 0.5f, 0.5f ) * Matrix.Translation( -1f, 0f, 0f ); device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 ); device.EndScene(); device.Present(); //show the canvas
Click Debug → Start Without Debugging Ctrl F5. Two new small triangles will appear.
Change the device.BeginScene(); - device.EndScene(); - clause inside
device.BeginScene(); device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 ); device.Transform.World = Matrix.Scaling( 0.5f, 0.5f, 0.5f ) * Matrix.Translation( 1f, 0f, 0f ) * Matrix.RotationYawPitchRoll( fAngle, fAngle, fAngle ); device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 ); device.Transform.World = Matrix.Scaling( 0.5f, 0.5f, 0.5f ) * Matrix.Translation(-1f, 0f, 0f ) * Matrix.RotationYawPitchRoll( fAngle, fAngle, fAngle ); device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 ); device.EndScene(); device.Present(); //show the canvas
Click Debug → Start Without Debugging Ctrl F5. The two small triangles will dance around the first one.
Add the following declarations to the head of public class Form1 : Form below the line:
const Int32 nTriangles = 100; static float[] dx = new float[nTriangles]; static float[] dy = new float[nTriangles]; static float[] dz = new float[nTriangles]; static float[] ax = new float[nTriangles]; static float[] ay = new float[nTriangles]; static float[] az = new float[nTriangles]; static Random r = new Random();
Add the following intialisations to public Form1() below the line:
for ( int i = 0; i < nTriangles; i++ ) { dx[i] = (float)r.NextDouble(); //random permanent translation dx dy[i] = (float)r.NextDouble(); //random permanent translation dy dz[i] = (float)r.NextDouble(); //random permanent translation dz }
Change the device.BeginScene(); - device.EndScene(); - clause inside
device.BeginScene(); for ( int i = 0; i < nTriangles; i++ ) { device.Transform.World = Matrix.Scaling( 0.5f, 0.5f, 0.5f ) * Matrix.Translation( dx[i], dy[i], dz[i] ) * Matrix.RotationYawPitchRoll( fAngle, fAngle, fAngle ); device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 ); } device.EndScene(); device.Present(); //show the canvas
Click Debug → Start Without Debugging Ctrl F5. Hundred small triangles will dance synchronously as fishes do.
Add the initializations of the rotating angles ax[i], ay[i], az[i] inside the loop
for ( int i = 0; i < nTriangles; i++ ) { dx[i] = (float)r.NextDouble(); //random permanent translation dx dy[i] = (float)r.NextDouble(); //random permanent translation dy dz[i] = (float)r.NextDouble(); //random permanent translation dz ax[i] = (float)r.NextDouble(); //random initial pitch rotation angle ay[i] = (float)r.NextDouble(); //random initial yaw rotation angle az[i] = (float)r.NextDouble(); //random initial roll rotation angle }
Change the device.BeginScene(); - device.EndScene(); - clause inside
device.BeginScene(); for ( int i = 0; i < nTriangles; i++ ) { device.Transform.World = Matrix.Scaling( 0.5f, 0.5f, 0.5f ) * Matrix.Translation( dx[i], dy[i], dz[i] ) * Matrix.RotationYawPitchRoll( ay[i] += 0.01f * (float)r.NextDouble(), ax[i] += 0.01f * (float)r.NextDouble(), az[i] += 0.01f * (float)r.NextDouble() ); device.DrawPrimitives( PrimitiveType.TriangleList, 0, 1 ); } device.EndScene(); device.Present(); //show the canvas
Click Debug → Start Without Debugging Ctrl F5. Hundred small triangles will dance as flying paper sheets do.
Read: Tutorial1.pdf (73 kB) and Tutorial1_devices.pdf (3.3 MB).
1. Slow the animation down by increasing
2. Accelerate the animation by increasing
3. Rotate the triangle around the X-axis resp. around the Z-axis with
4. Change the colors of the edges v[0], v[1] and v[2] inside the constructor.
5. Step back with the eye point from
6. Experiment: Comment out the line
7. Vary the constant nTriangles between 10 and 1000.
8. Vary the random initial pitch+yaw+roll rotation angles ax[i], ay[i], az[i] inside the constructor between 0f and
9. Vary the retarding factors 0.01f inside Matrix.RotationYawPitchRoll of the angular increments ay[i], ax[i] and az[i] between 0.001f and 0.1f in order to decrease/increase the chaos.
10. Make some bustling excitement by replacing the 0.5f Matrix.Scaling-parameters
11. Read the comments C3DCisC1_Comment.htm and try to understand the sense of the code lines.
12. You can find more explanations and comments about this chapter here: http://msdn.microsoft.com/en-us/library/default.aspx.
Caution: Mozilla Firefox doesn't correctly display the tree on the left side.
12a: Click trough the tree on the left side:
Win32 and COM Development →
12b: Click trough the tree on the left side:
Win32 and COM Development →
12c: Click trough the tree on the left side:
Win32 and COM Development →
13: Read: ../../Lectures/L05_OpenGL_DirectX/OGL_DX_d.htm#a5
top of page: |