DirectX projekt i Visual Studio 2005

Tegn en trekant på skærmen med brug af DirectX

Denne tekst er et forsøg på at sammenskrive en række forskellige tekster, som alle beskriver opbygningen af et DirectX program i Visual Studio.

Udviklingen af applikationen kan inddeles i en række naturlige trin. Efter hvert trin bør man have en applikation, der kan oversættes og køres, også selvom den måske ikke kan udføre noget meningsfyldt endnu. Her er en oversigt over trinene i udviklingen af applikationen:

  1. Start ny applikation
  2. Device til rendering erklæres og defineres
  3. Rendering (tegning) på skærmen
  4. Simpel trekant tegnes

1. Start ny applikation

I guiden til oprettelse af nye projekter vælges Windows Application. Denne mulighed giver dog mere kode, end der beøves til denne type projekt; men den er det bedste valg i situationen. I dette tilfælde døber jeg projektet DirectXEksempel01.

I første omgang fjernes overflødig kode fra Form1.cs, således at den kommer til at se således ud:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace DirectXEksempel01 { public partial class Form1 : Form { public Form1() { } static void Main() {
} }
}

Filen Program.cs slettes, da de ting den indeholder vil indgå på andre måder i dette projekt. I stedet indsættes i Form1 klassen en Main metode, som kommer til at indeholde følgende:

 	using (Form1 engine = new Form1())
   	{
   		engine.Show();
 		// While the form is still valid, render and process messages
   		while (engine.Created)
   		{
   			Application.DoEvents();
   		}
   	}

Den kode som er til stede nu kan oversættes og køres. Der bør fremkomme et skærmbillede, som ser således ud:

For at få et større skærmareal at arbejde med i vinduet og en caption sat på, ændres constructoren, så den ser således ud:

 	public Form1()
   	{
   		// Set the initial size of the form
   		this.ClientSize = new System.Drawing.Size(800, 600);
   		// And its caption
   		this.Text = "DirectX Eksempel 1";
   	}

Koden skal kunne oversættes og køres.

2. Device erklæres og defineres

De DirectX komponenter, vi agter at bruge senere, skal have defineret et Device objekt for at kunne sende output ud på skærmen. Device objektet erklæres og defineres ved at tilføje kode forskellige steder i programmet. Først skal et par referencer til nogle komponenter dog tilføjes til programmet. Disse forudsætter, at man forinden har installeret DirectX SDK på sin maskine.

Under menupunktet Project vælges Add Reference, og herefter findes komponenten Microsoft.DirectX under fanebladet .Net, som vist på næste billede.

På samme måde indsættes en reference til komponenten Direct3D.

Øverst i programmet under using System.Windows.Forms indsættes disse to linier:

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

Øverst i klassen Form1 indsættes erklæringen af en device variabel:

	// Global variables for this project
   	private Device device = null; // Rendering device

En metode, InitializeGraphics, indsættes:

	public void InitializeGraphics() // Ny metode
   	{
   		// Definering af device til DirectX Rendering
   		PresentParameters presentParams = new PresentParameters();
   		presentParams.Windowed = true;
   		presentParams.SwapEffect = SwapEffect.Discard;
   		device = new Device(0, DeviceType.Hardware, this,
   			CreateFlags.SoftwareVertexProcessing, presentParams);
   	}

Et PresentParameters objekt bruges til at opbygge et sæt parametre til kontrol af den måde vinduet skal fungere på.

InitializeGraphics kaldes øverst i Main:

 			using (Form1 engine = new Form1())
   			{
   				engine.InitializeGraphics(); // Ny linie
   				engine.Show();
				...

Check at programmet kan oversættes og kører.

3.Rendering

Til generering af outputtet på skærmen skrives en metode med navnet Render - denne metode kaldes løbende så længe applikationen kører. I metoden opbygges indholdet af vinduet forfra, hver gang metoden kaldes. Man starter således med at blankstille det hidtidige indhold med kald af Clear, og derefter opbygges billedet. Her anvendes det Device objekt, som blev defineret i sidste trin. Selve grafikken tilføjes i senere udviklingstrin; men vi kan allerede nu se, hvor den skal indsættes - mellem BeginScene og EndScene. Clear metodens 2. parameter definerer skærmbilledets baggrundsfarve (her defineret til blå).

Grafikken opbygges i en såkaldt backbuffer og afslutningsvis kaldes metoden Present, som sender indholdet af backbuffer ud til skærmenheden.

		private void Render()
   		{
 			//Clear the backbuffer to a blue color 
   			device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

   			//Begin the scene
   			device.BeginScene();
   
   			// Her indsættes flere metodekald
 			//End the scene
   			device.EndScene();
   			device.Present();
   		}	

I Main metodens loop indsættes kald af Render metoden:

 			while (engine.Created)
   			{
   				engine.Render(); // Ny linie
   				Application.DoEvents();
   			}

Programmet kan stadig oversættes og køres. Hvis man prøver det, vil man opdage, at skærmbilledets baggrund nu er blå, sådan som det også blev defineret i begyndelsen af Render metoden. Programmet kan stadig ikke tegne noget; men det råder vi bod på i næste trin af udviklingen.

4. Trekant tegnes

Til starten af klassen tilføjes en ny erklæring - denne gang af en tabel, som skal fyldes med data, der beskriver en figur, som skal tegnes på vinduet.

 	// Global variables for this project
   	private Device device = null; // Rendering device
   	CustomVertex.TransformedColored[] vertices = new CustomVertex.TransformedColored[3];

Der er en del forskellige typer af CustomVertex at vælge imellem. I dette tilfælde anvendes typen TransformedColored - som navnet antyder er der tale om en type, hvor koordinaterne er angivet i skærmens koordinatsystem (transformed) og der er knyttet en farve til hvert hjørne (colored). Der afsættes plads til 3 hjørner i tabellen - nok til definition af en enkelt trekant. Definitionen af de tre hjørner sker i CreateVertices metoden:

 		public void CreateVertices()
   		{
   			int i = 0;
   			vertices[i++] = new CustomVertex.TransformedColored(400f, 100f, 0, 1f, 
				System.Drawing.Color.Red.ToArgb());
   			vertices[i++] = new CustomVertex.TransformedColored(700f, 500f, 0, 1f, 
				System.Drawing.Color.Green.ToArgb());
   			vertices[i++] = new CustomVertex.TransformedColored(100f, 500f, 0, 1f, 
				System.Drawing.Color.Yellow.ToArgb());
   		}

Z-koordinaten er sat til 0, fordi den ikke spiller nogen rolle i denne sammenhæng - der er ikke tale om ægte 3D, fordi vi anvender typen TransformedColored, som specificerer hjørnerne i skærmkoordinater, der i sagens natur er 2D. Der er anvendt tre forskellige farver til de tre hjørner - det giver en effekt, hvor farverne bliver blandet i midten af trekanten. Hjørnerne skal angives i en bestemt rækkefølge, for at trekanten bliver synlig - rækkefølgen af hjørnerne er med til at bestemme, hvilken flade, der vender frem, og hvilken, der vender bagud. Bagsiden bliver normalt ikke tegnet. Den forventede rækkefølge er defineret i device objektets egenskab RenderState.CullMode og default-værdien er Counterclockwise - altså imod urets retning, sådan som det også fremgår af definitionen ovenfor.

Man kan få systemet til også at tegne bagsiden ved at sætte den ovennævnte egenskab til Cull.None.

 			device.BeginScene();
	   		device.VertexFormat = CustomVertex.TransformedColored.Format;
   			device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, vertices); // Ny linie
   			device.EndScene();

Når trekanten skal tegnes indsættes ovenstående linie i Render metoden. I metoden InitializeGraphics indsættes følgende linier. Den vigtigste er kaldet af metoden CreateVertices, som danner trekantens hjørner. Ændring af Cullmode er også forberedt, så man kan eksperimentere med den senere.

            //device.RenderState.CullMode = Cull.None;
// Opbygning af vertex tabel CreateVertices();

Programmet skulle nu gerne kunne køre og generere følgende trekant på skærmen.

Vedhæftede arkiv-fil indeholder kode svarende til dette eksempel.


Sidst opdateret: 12. februar 2007

Index