<

Please click on the link below to go to my new pages:

http://www.riemers.net

See you there!!

Set up
Contact
  • Overview 
  • Device
  • Vertices
  • Camera
  • Rotation
  • Indices
  • Terrain
  • Landscape
  • Keyboard
  • - Website design & DirectX code : Riemer Grootjans -


    - Terrain creation from file

    It's time to finally create a nice looking landscape. Instead of manually entering the HeightData array, we are going to fill it from a file. To do this, we are going to load a 64x64 black&white image, and use the 'white value' of every pixel as the Z coordinate for the corresponding pixel! You can download my example file here. To open and read files, you need to add the following line to your using-block :

      using System.IO;

    Change your LoadHeightData method to this:

      private void LoadHeightData()

      {

        heightData = new int[WIDTH,HEIGHT];

     

        FileStream fs = new FileStream("heightdata.raw",FileMode.Open, FileAccess.Read);

        BinaryReader r = new BinaryReader(fs);

        for (int i = 0;i<HEIGHT;i++)

        {

          for (int y=0; y<WIDTH; y++)

          {

            int height =(int)(r.ReadByte()/50);

            heightData[WIDTH-1-y,HEIGHT-1-i] = height;

          }

        }

        r.Close();

      }

    First we create a heightData array capable of storing the 64x64 Z coordinates. The 2 following lines open the file heightdata.raw that should be in the same directory as your .exe file for binary access. In a .raw file, the 'white value' of every pixel if stored byte after byte. So the only thing we have to do is load byte after byte into our heightData array! We divide by 50, otherwise the Z coordinates would be way to high. We have to use the WIDTH-1-y structures, because the data is stored inversely in the .raw format. Now change our width and height variables so we can display the whole terrain :

      private int WIDTH = 64;

      private int HEIGHT = 64;

    You can try running this code, but you'll notice that you can't see the whole terrain with these camera settings. First we'll introduce a translation before drawing the triangles, so the middle of the terrain is in the (0,0,0) position. Add the following line right before you call the DrawIndexedPrimitives :

      device.Transform.World = Matrix.Translation(-HEIGHT/2, -WIDTH/2, 0);

    With the terrain in the center of our window, the only thing left to do is reposition our camera!

      device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI/4, this.Width/this.Height, 1f, 150f);

      device.Transform.View = Matrix.LookAtLH(new Vector3(0,-40,50), new Vector3(0,-5,0), new Vector3(0,1,0));

    Don't forget to set the far clipping plane to 150f! Just set the background color to black to have a nicer result. Now run the program and you'll see a nice terrain :-)

     

     

    Here's the total code:

    using System;

    using System.Drawing;

    using System.Collections;

    using System.ComponentModel;

    using System.Windows.Forms;

    using System.Data;

    using Microsoft.DirectX;

    using Microsoft.DirectX.Direct3D;

    using System.IO;

     

    namespace DirectX_Tutorial

    {

     

          public class WinForm : System.Windows.Forms.Form

          {

                private int WIDTH = 64;

                private int HEIGHT = 64;

                private Device device;

                private System.ComponentModel.Container components = null;

                private float angle = 0f;

                private CustomVertex.PositionColored[] vertices;

                private int[,] heightData;

                private int[] indices;

                private IndexBuffer ib;

                private VertexBuffer vb;

     

     

                public WinForm()

                {

                      InitializeComponent();

                      this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);

                }

     

                public void InitializeDevice()

                {

                      PresentParameters presentParams = new PresentParameters();

                      presentParams.Windowed = true;

                      presentParams.SwapEffect = SwapEffect.Discard;

                      device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);

                      device.RenderState.FillMode = FillMode.WireFrame;

                      device.RenderState.CullMode = Cull.None;

                }

     

                private void CameraPositioning()

                {

                      device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI/4, this.Width/this.Height, 1f, 150f);

                      device.Transform.View = Matrix.LookAtLH(new Vector3(0,-40,50), new Vector3(0,-5,0), new Vector3(0,1,0));

                      device.RenderState.Lighting = false;

                      device.RenderState.CullMode = Cull.None;

                }

     

                private void VertexDeclaration()

                {

                      vb = new VertexBuffer(typeof(CustomVertex.PositionColored), WIDTH*HEIGHT, device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);

                      vertices = new CustomVertex.PositionColored[WIDTH*HEIGHT];

                      for (int x=0;x<WIDTH;x++)

                      {

                            for (int y=0; y<HEIGHT;y++)

                            {

                                 vertices[x+y*WIDTH].SetPosition(new Vector3(x, y, heightData[x,y]));

                                 vertices[x+y*WIDTH].Color = Color.White.ToArgb();

                            }

                      }

     

                      vb.SetData(vertices, 0 ,LockFlags.None);

                }

     

                private void IndicesDeclaration()

                {

                      ib = new IndexBuffer(typeof(int), (WIDTH-1)*(HEIGHT-1)*6, device, Usage.WriteOnly, Pool.Default);

                      indices = new int[(WIDTH-1)*(HEIGHT-1)*6];

                      for (int x=0;x<WIDTH-1;x++)

                      {

                            for (int y=0; y<HEIGHT-1;y++)

                            {

                                 indices[(x+y*(WIDTH-1))*6] = (x+1)+(y+1)*WIDTH;

                                 indices[(x+y*(WIDTH-1))*6+1] = (x+1)+y*WIDTH;

                                 indices[(x+y*(WIDTH-1))*6+2] = x+y*WIDTH;

     

                                 indices[(x+y*(WIDTH-1))*6+3] = (x+1)+(y+1)*WIDTH;

                                 indices[(x+y*(WIDTH-1))*6+4] = x+y*WIDTH;

                                 indices[(x+y*(WIDTH-1))*6+5] = x+(y+1)*WIDTH;

                            }

                      }

                      ib.SetData(indices, 0, LockFlags.None);

                }

     

                protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)

                {

                      device.Clear(ClearFlags.Target, Color.Black , 1.0f, 0);

     

                      device.BeginScene();

                      device.VertexFormat = CustomVertex.PositionColored.Format;

                      device.SetStreamSource(0, vb, 0);

                      device.Indices = ib;

     

                      device.Transform.World = Matrix.Translation(-HEIGHT/2, -WIDTH/2, 0);

                      device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, WIDTH*HEIGHT, 0, indices.Length/3);

                      device.EndScene();

     

                      device.Present();

     

                      this.Invalidate();

                      angle += 0.05f;

                }

     

                private void LoadHeightData()

                {

                      heightData = new int[WIDTH,HEIGHT];

     

                      FileStream fs = new FileStream("heightdata.raw",FileMode.Open, FileAccess.Read);

                      BinaryReader r = new BinaryReader(fs);

                      for (int i = 0;i<HEIGHT;i++)

                      {

                            for (int y=0; y<WIDTH; y++)

                            {

                                 int height =(int)(r.ReadByte()/50);

                                 heightData[WIDTH-1-y,HEIGHT-1-i] = height;

                            }

                      }

                      r.Close();

                }

     

                protected override void Dispose (bool disposing)

                {

                      if (disposing)

                      {

                            if (components != null)

                            {

                                 components.Dispose();

                            }

                      }

                      base.Dispose(disposing);

                }

     

                private void InitializeComponent()

                {

                      this.components = new System.ComponentModel.Container();

                      this.Size = new System.Drawing.Size(500,500);

                      this.Text = "DirectX Tutorial";

                }

         

                static void Main()

                {

                      using (WinForm our_directx_form = new WinForm())

                      {                   

                            our_directx_form.LoadHeightData();

                            our_directx_form.InitializeDevice();

                            our_directx_form.CameraPositioning();

                            our_directx_form.VertexDeclaration();

                            our_directx_form.IndicesDeclaration();

                            our_directx_form.Show();

                            Application.Run(our_directx_form);

                      }

                }

          }

    }