Home Course Index << Prev Next >> PDF Version of this Page

Course 3D_MDX: 3D-Graphics with Managed DirectX 9.0
Chapter C6: Mesh Viewer


Copyright © by V. Miszalok, last update: 05-06-2007

Mail me...
Let me know
what you think
  Projekt mesh_viewer1
  Programm komplett
  Weitere Aufgaben

Projekt mesh_viewer1

Diese Übungsaufgabe ist eine kurze, übersichtliche Fassung eines Direct3D-Tutorials von Microsoft: Tutorial6. Sie finden es unter C:\DXSDK\Samples\Managed\Direct3D\Tutorials\Tutorial6.

Main Menu nach dem Start von VS 2008: File → New Project... → Visual Studio installed templates: Windows Forms Application
Name: mesh_viewer1 → Location: C:\temp → Create directory for solution:
ausschalten → OK
Löschen Sie die Files Program.cs und Form1.Designer.cs und den Inhalt von Form1.cs, wie es in den Kapiteln 2DCisC1 bis 2DCisC4 beschrieben wurde.

Falls das Solution Explorer- Fenster nicht schon offen ist, öffnen Sie es über das Hauptmenü: View → Solution Explorer.
Im Solution Explorer- Fenster klicken Sie auf das Pluszeichen vor mesh_viewer1. Es öffnet sich ein Baum. Ein Ast heißt "References". Klicken Sie mit der rechten Maustaste auf References und dann mit der linken Maustaste auf Add Reference.... Es öffnet sich eine Add Reference Dialog Box. Scrollen Sie abwärts, bis Sie den Component Name: Microsoft.DirectX Version 1.0.2902.0 sehen.
Markieren Sie durch Linksklick diese Referenz und (bei gedrückter der Strg-Taste) die beiden weiter unten stehende Referenzen
Microsoft.DirectX.Direct3D  Version 1.0.2902.0 und
Microsoft.DirectX.Direct3DX Version 1.0.2902.0 oder 1.0.2903.0 oder 1.0.2904.0.
Verlassen Sie die Add Reference Dialog Box mit OK.
Wenn Sie DirectX Bibliotheken (=References) älter als Version 1.0.2902.0 verwenden wollen, werden Sie 3 Fehlermeldungen bekommen. Die Lösung ist sehr einfach: Sie müssen in den 3 betroffenen Befehlen:
mesh0 = Mesh.Clean( CleanType.Optimization, mesh0, adjacency, adjacency );
myfont.DrawText( null, "This mesh has " ...
myfont.DrawText( null, "divided into " ...
den jeweils ersten Parameter, also CleanType.Optimization, null, und null, weglassen oder auskommentieren. Dann läuft das Programm.


Kontrollieren Sie, ob jetzt im Solution Explorer Fenster unter mesh_viewer1 → References (unter anderen) die drei Referenzen
Microsoft.DirectX und
Microsoft.DirectX.Direct3D und
Microsoft.DirectX.Direct3DX stehen.

Diese Übung setzt voraus dass C:\DXSDK\Samples\Media\Tiger\tiger.x und C:\DXSDK\Samples\Media\Tiger\tiger.bmp und weitere 13 Mesh-files unter ihrem jeweiligen Pfad existieren. Falls diese Files bei Ihnen irgendwo anders stehen, müssen Sie im Kopf von Form1 den String static String s = @"C:\DXSDK\Samples\"; entsprechend ändern.

 

Programm komplett

Schreiben in das leere Codefenster Form1.cs folgenden Code:

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;
  static float xAngle, yAngle, zAngle;
  static Mesh mesh0, mesh1;
  static ExtendedMaterial[] materials;
  static Microsoft.DirectX.Direct3D.Font myfont;
  struct m{ public String title; public String mesh; public String texture; public Int32 eyedistance;
            public m(String a, String b, String c, Int32 d)  //Constructor
            { title = a; mesh = b; texture = c; eyedistance = d; }
          };
  static String s = @"C:\DXSDK\Samples\";
  static m[] meshes =
  { new m("tiger"  ,s+@"Media\Tiger\tiger.x"            ,s+@"Media\Tiger\tiger.bmp",   5),
    new m("bigship",s+@"Media\misc\bigship1.x"          ,s+@"Media\Tiger\tiger.bmp",  50),
    new m("knot"   ,s+@"Media\misc\knot.x"              ,s+@"Media\Tiger\tiger.bmp",   5),
    new m("shapes" ,s+@"Media\misc\shapes1.x"           ,s+@"Media\Earth\earth.bmp",  50),
    new m("scull"  ,s+@"Media\misc\skullocc.x"          ,s+@"Media\Tiger\tiger.bmp",  50),
    new m("shark"  ,s+@"Media\Prt Demo\LandShark.x"     ,s+@"Media\Tiger\tiger.bmp",1000),
    new m("car"    ,s+@"C++\Direct3D\EffectParam\car2.x",s+@"C++\Direct3D\EffectParam\EffectParam.jpg",2000),
    new m("tiny"   ,s+@"Media\Tiny\tiny.x"              ,s+@"Media\Tiger\tiger.bmp",2000),
    new m("dwarf"  ,s+@"Media\Dwarf\dwarf.x"            ,s+@"Media\Tiger\tiger.bmp",  10),
    new m("airplan",s+@"Media\Airplane\airplane 2.x"    ,s+@"Media\Airplane\bihull.bmp",50),
    new m("headsad",s+@"Media\Prt Demo\Head_Sad.x"      ,s+@"Media\Tiger\tiger.bmp",1000),
    new m("virus"  ,s+@"C++\Direct3D\EffectParam\cytovirus.x",s+@"Media\Tiger\tiger.bmp",2000)
  };
  String myMeshFile    =  meshes[0].mesh;
  String myTextureFile =  meshes[0].texture;
  Bitmap          myBitmap  = null;
  BaseTexture     myTexture = null;
  GraphicsStream  adjacency = null;
  GroupBox group      = new GroupBox();
  RadioButton[] radio = new RadioButton[meshes.Length];
  TrackBar[] track    = new TrackBar[2];
  Label[] label       = new Label[2];
  TextBox[] text      = new TextBox[2];
  CheckBox check      = new CheckBox();
  Panel panel         = new Panel();
  Timer myTimer       = new Timer();

  public Form1()
  { Text = "Mesh Viewer";
    for ( int i = 0; i < track.Length; i++ )
    { label[i] = new Label();    Controls.Add( label[i] );
      track[i] = new TrackBar(); Controls.Add( track[i] );
      text [i] = new TextBox();  Controls.Add( text [i] );
      label[i].BackColor = track[i].BackColor = Color.Gray;
      track[i].Minimum   = 1;
      track[i].TickStyle = TickStyle.None;
      label[i].TextAlign = ContentAlignment.MiddleCenter;
      text [i].TextAlign = HorizontalAlignment.Center;
    }
    Controls.Add( group );
    for ( int i = 0; i < meshes.Length; i++ )
    { radio[i] = new RadioButton(); Controls.Add( radio[i] );
      radio[i].Parent = group;
      radio[i].Text = meshes[i].title;
      radio[i].Location = new Point( 5, Convert.ToInt32((0.6 + i*1.2)*FontHeight) );
      radio[i].Size = new Size( 60, Convert.ToInt32(1.2*Font.Height) );
      radio[i].TextAlign = ContentAlignment.MiddleCenter;
      radio[i].CheckedChanged += new EventHandler( radio_changed );
    }
    label[0].Text = "Reduce Vertices"; label[1].Text = "Eye Distance";
    Controls.Add( check );
    Controls.Add( panel );
    track[0].MouseUp        += new MouseEventHandler( track0_MouseUp );
    track[1].MouseUp        += new MouseEventHandler( track1_MouseUp );
    check   .CheckedChanged += new EventHandler( check_changed );
    myTimer.Tick            += new EventHandler( OnTimer );
    myTimer.Interval = 1;
    myBitmap = (Bitmap)Image.FromFile( meshes[0].texture );
    track[1].Value = track[1].Maximum = meshes[0].eyedistance;
    ClientSize = new Size( 1024, 800 ); //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
    for ( int i = 0; i < track.Length; i++ )
      label[i].Width = track[i].Width = text[i].Width = ClientSize.Width / 10;
    text[0].Text = "vertices = " + track[0].Value.ToString();
    text[1].Text = "eye = - "    + track[1].Value.ToString();
    check  .Text = "Wire Frame";
    group.Size = new Size( ClientSize.Width / 10, meshes.Length*radio[0].Height + 6 );
    check.Size = new Size( ClientSize.Width / 10, radio[0].Height );
    panel.Size = new Size( ClientSize.Width - label[0].Width - 2, ClientSize.Height - 2 );
    group   .Location = new Point( 2, 1 );
    label[0].Location = new Point( 2, group   .Location.Y + group   .Height + 20 );
    track[0].Location = new Point( 2, label[0].Location.Y + label[0].Height +  1 );
    text [0].Location = new Point( 2, track[0].Location.Y + track[0].Height +  2 );
    label[1].Location = new Point( 2, text[ 0].Location.Y + text [0].Height + 20 );
    track[1].Location = new Point( 2, label[1].Location.Y + label[1].Height +  1 );
    text [1].Location = new Point( 2, track[1].Location.Y + track[1].Height +  2 );
    check   .Location = new Point( 2, text [1].Location.Y + text [1].Height + 20 );
    panel   .Location = new Point( 2 + group.Width + 2, group.Location.Y );
    try
    { PresentParameters presentParams = new PresentParameters();
      presentParams.Windowed = true;
      presentParams.SwapEffect = SwapEffect.Discard;
      presentParams.EnableAutoDepthStencil = true;
      presentParams.AutoDepthStencilFormat = DepthFormat.D16;
      if ( device != null ) device.Dispose();
      device = new Device( 0, DeviceType.Hardware, panel,
                           CreateFlags.MixedVertexProcessing, presentParams );
      //turn on some white directional light from left to right
      device.Lights[0].Type = LightType.Directional;
      device.Lights[0].Diffuse = Color.White;
      device.Lights[0].Direction = new Vector3( 1, 0, 0 );
      device.Lights[0].Enabled = true;
      Material myMaterial = new Material();
      myMaterial.Diffuse = myMaterial.Ambient = Color.White;
      device.Material = myMaterial;
      device.RenderState.Ambient = Color.FromArgb( 0x00303030 );
      device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI/4, 1f, 1f, 5000f );
      device.Transform.View = Matrix.LookAtLH(
        new Vector3( 0f, 0f, -track[1].Value ),
        new Vector3( 0f,0f,0f ),
        new Vector3( 0f,1f,0f ) );
      device.RenderState.Lighting = true;
      if ( check.Checked ) device.RenderState.FillMode = FillMode.WireFrame;
      else                 device.RenderState.FillMode = FillMode.Solid;
      myfont = new Microsoft.DirectX.Direct3D.Font(
               device, new System.Drawing.Font( "Arial", 12, FontStyle.Bold ) );
      SetUpMesh();
      SetUpTexture();
      myTimer.Start();
    }
    catch (DirectXException) { MessageBox.Show("Could not initialize Direct3D." ); return; }
  }

  private void SetUpMesh()
  { Cursor.Current = Cursors.WaitCursor; //change mouse pointer to hour glass
    if ( mesh0 != null ) mesh0 .Dispose(); //free the old mesh if any
    mesh0 = Mesh.FromFile( myMeshFile, MeshFlags.Managed, device, out adjacency, out materials );
    mesh0 = Mesh.Clean( CleanType.Optimization, mesh0, adjacency, adjacency );
    if ( mesh1  != null ) mesh1.Dispose(); //free the old mesh if any
    //make a copy mesh1 from mesh0
    mesh1 = mesh0.Clone( mesh0.Options.Value, mesh0.VertexFormat | VertexFormats.Normal, device );
    //if mesh0 has no normals, compute them within mesh1 and copy them back to mesh0
    if ( (mesh0.VertexFormat & VertexFormats.Normal) == 0 )
    { mesh1.ComputeNormals();
      mesh0.Dispose();
      mesh0 = mesh1.Clone( mesh1.Options.Value, mesh1.VertexFormat, device );
    }
    track[0].Value = track[0].Maximum = mesh0.NumberVertices;
    text[0].Text = "vertices = " + track[0].Value.ToString();
    Cursor.Current = Cursors.Arrow; //change mouse pointer back to normal arrow
  }

  private void SetUpTexture()
  { if ( myTexture != null ) myTexture.Dispose(); //free the old texture if any
    myTexture = new Texture( device, myBitmap, 0, Pool.Managed );
    device.SetTexture( 0, myTexture );
  }

  protected static void OnTimer( Object myObject, EventArgs myEventArgs )
  { device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Gray, 1f, 0);
    device.Transform.World = Matrix.RotationYawPitchRoll( yAngle += 0.02f,
                                                          xAngle += 0.02f,
                                                          zAngle += 0.02f );
    device.BeginScene();
      for ( int i=0; i < materials.Length; i++ ) mesh1.DrawSubset( i );
      myfont.DrawText( null, "This mesh has " + mesh1.NumberVertices.ToString() + " vertices",
                       new Rectangle( 0,  0, 100, 20 ), DrawTextFormat.NoClip, Color.Red );
      myfont.DrawText( null, "divided into " + materials.Length.ToString() + " subsets",
                       new Rectangle( 0, 20, 100, 20 ), DrawTextFormat.NoClip, Color.Red );
    device.EndScene();
    device.Present(); //show the canvas
  }

  private void radio_changed( Object sender, EventArgs e )
  { RadioButton radio = (RadioButton)sender;
    Int32 i;
    for ( i = 0; i < meshes.Length; i++ )
      if ( meshes[i].title == radio.Text ) break;
    if ( myMeshFile != meshes[i].mesh )
    { myMeshFile = meshes[i].mesh;
      SetUpMesh();
    }
    if ( myTextureFile != meshes[i].texture )
    { myBitmap = (Bitmap)Image.FromFile( myTextureFile = meshes[i].texture );
      SetUpTexture();
    }
    track[1].Value = track[1].Maximum = meshes[i].eyedistance;
    text [1].Text = "eye = - " + track[1].Value.ToString();
    device.Transform.View = Matrix.LookAtLH(
      new Vector3( 0f, 0f, -meshes[i].eyedistance ),
      new Vector3( 0f,0f,0f ),
      new Vector3( 0f,1f,0f ) );
  }

  private void track0_MouseUp(object sender, System.EventArgs e) //Reduce no. of vertices
  { if ( materials.Length > 1 )
    { MessageBox.Show( "This mesh has more than one subset. It can't be simplified !" );
      track[0].Value = track[0].Maximum;
      return;
    }
    Cursor.Current = Cursors.WaitCursor;
    if ( mesh1 != null ) mesh1.Dispose();
    try { mesh1 = Mesh.Simplify( mesh0, adjacency, null, track[0].Value, MeshFlags.SimplifyVertex ); }
    catch { mesh1 = mesh0.Clone( mesh0.Options.Value, mesh0.VertexFormat, device );
            MessageBox.Show( "This mesh cannot be simplified !" );
          }
    track[0].Value = mesh1.NumberVertices;
    text[0].Text = "vertices = " + mesh1.NumberVertices.ToString();
    Cursor.Current = Cursors.Default;
  }

  private void track1_MouseUp(object sender, System.EventArgs e)//Eye Distance
  { device.Transform.View = Matrix.LookAtLH(
        new Vector3( 0f, 0f, -track[1].Value ),   //eye point 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
    text[1].Text = "eye = - " + track[1].Value.ToString();
  }

  private void check_changed( Object sender, EventArgs e ) //Wire Frame on/off
  { if ( check.Checked ) device.RenderState.FillMode = FillMode.WireFrame;
    else                 device.RenderState.FillMode = FillMode.Solid;
  }
}

Klicken Sie DebugStart Without Debugging Ctrl F5.
Wenn Sie DirectX Bibliotheken (=References) älter als Version 1.0.2902.0 benutzt haben, bekommen Sie 3 Fehlermeldungen. Die Lösung ist einfach: Sie müssen in den 3 betroffenen Befehlen:
mesh0 = Mesh.Clean( CleanType.Optimization, mesh0, adjacency, adjacency );
myfont.DrawText( null, "This mesh has " ...
myfont.DrawText( null, "divided into " ...
den jeweils ersten Parameter, also CleanType.Optimization, null, und null, weglassen oder auskommentieren. Dann läuft das Programm.


 

Weitere Aufgaben

1. Fügen Sie dem Programm einen weiteren Trackbar zu, mit dem man das x-Achsen Rotations-Inkrement zwischen 0 und 0.02 verstellen kann.
2. Fügen Sie dem Programm zwei weitere Trackbars zu, mit dem man das y- und z-Achsen Rotations-Inkrement zwischen 0 und 0.02 verstellen kann.
3. Fügen Sie dem Programm einen weiteren Trackbar zu, mit dem den Augenpunkt in z-Richtung von -2000 bis +2000 verschieben kann.
4. Vermindern Sie automatisch die Anzahl der Vertices, wenn der Augenpunkt sich entfernt und alles kleiner wird.

top of page: