|
|
|
|
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 (link). 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 is 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 too 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 our current 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 immediately before you call the DrawIndexedPrimitives method:
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 or the points further than 50 units away from the camera won’t be drawn! Just set the background color to black to have a nicer result. Now run the program and you'll see a nice terrain :-)

Click here to go to the forum on this chapter!
Or click on one of the topics on this chapter to go there: Flat Terrain Howdy. These are by far some of the best tutorials...multiple terrains Hi,
Great tutorials thanks.
I am writing a 3d C...Error in Indices Loop Code? I'm somewhat of a DirectX noob, although I have t...Unexpected triangles being drawn Hi!
The basic code of this tutorial worked fine...Reading .raw error When I put the heighdata.raw file in my debug fold...windows is dark I run the code of terrain from file but the window...About Terrain from file Hello everyone ..Thanks a Lot Mr.Riemer for ur coo...Editor .raw files How i can edit .raw file? I want change terrain, b...Dont get indices to work at all Hi!
Liked your tutorial it was verry easy to gras...Problems with the debug hi
when i debug (f5) the program this have so tro...Window Resize I tired both the printed code copied and pasted an..."Error in the application" Hi!
When I use F6 “Build Solution” no problems ...
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].Position = 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); } } } }
- Website design & XNA + DirectX code : Riemer Grootjans - ©2003 - 2011 Riemer Grootjans
|
|
|
|
|