Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von hauptmann
Thema: Berechtigungen richtig setzen(IIS 6, ASP.net)
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hi!

ich bekomme beim IIS 6 beim Aufruf einer ASP.net Site(bzw. wollte ich die Telligent Foren Systems ausprobieren -.-) folgenden Fehler:

Zitat
Beim Ausführen der aktuellen Webanforderung wurde einen unbehandelte Ausnahme generiert. Informationen über den Ursprung und die Position der Ausnahme können mit der Ausnahmestapelüberwachung angezeigt werden.

Stapelüberwachung:


[HttpException (0x80070005): Der Zugriff auf 'D:\Inetpub\wwwdefault\' wurde verweigert. Das Überwachen der Dateiänderungen konnte nicht gestartet werden.]
System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter) +139
System.Web.DirectoryMonitor.StartMonitoring() +42
System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias) +154
System.Web.FileChangesMonitor.StartMonitoringDirectoryRenamesAndBinDirectory(String dir, FileChangeEventHandler callback) +278
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +331

[HttpException (0x80004005): ASP.NET-Initialisierungsfehler]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +982

System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +128

Ich habe bereits die ACLs für den ASP.net User und den Anonymen Internetuser habe ich bereits auf Vollzugriff gesetzt? Was muss ich noch tun, ich verzweifle schon leicht

Thema: Was habt ihr für einen Beruf?
Am im Forum: Smalltalk

Schüler der HTL Villach, Abteilung für EDV und Organisation - Software Engineering. Das Programmieren dort ist nicht wirklich anstrengend, im ersten Jahr(wo ich jetzt bin). C Grundlagen halt. Ich hasse eigentlich jetzt schon das 2. und das 3. Jahr(COBOL ^^).
Programmieren tue ich meist in meiner Freizeit sehr viel.

Thema: [FAQ] NET Anwendung ohne installiertes Framework ausführen
Am im Forum: FAQ

Links:

C# Anwendung ohne .NET Framework ausführen
.exe herstellen, die kein .NET Framework benötigt
Standalone Programm erstellen? [standalone = ausführbar ohne .NET Framework]
Selbstlaufende .exe erstellen? [selbstlaufend = ausführbar ohne .NET Framework]

Thema: [FAQ] NET Assembly vor Disassembling schützen (Obfuscator)
Am im Forum: FAQ

Links:

.NET:
.NET Assembly vor Disassemblern schützen
Assembly Code schützen
ILDASM verhindern
Obfuscator gesucht / Suche Freeware Obfuscator
List of obfuscators for .NET

Umfrage: Nutzt ihr einen Obfuscator?

Schutz vor Deobfuscation


WinRT:
WinRT Codesicherheit: Kann der "Quellcode" wie bei .NET angesehen werden? Welche Obfuscatoren gibts?

Thema: [FAQ] Kommunikation von 2 Forms
Am im Forum: FAQ

Links:

Kommunikation zwischen zwei Forms
MVC (Model-View-Controller Pattern mit ASP.NET)

Der Thread Wie von einer WIndow-Form auf die GUI-Elemente einer anderen Window-Form zugreifen? zeigt sehr schön, was man alles an Fehlern und schlechten Designansätzen vermeiden kann und sollte.

Und in Vorüberlegung zur Form2Form-Kommunikation: Programm-Design überdenken wird die Frage behandelt: "Brauche ich wirklich ein GUI mit mehreren unabhängigen Forms?".

Thema: [FAQ] Konsole schließt sich sofort nach dem Start
Am im Forum: FAQ

Wenn man eine einfache ConsoleApplication schreibt und diese dann aufruft öffnet sich zwar ein Konsolenfenster, aber es schließt sich sofort wieder. Um das zu verhindern reicht ein einfaches Console.ReadLine(); am Ende des Programmes. Dadurch wartet das Programm auf einen Enterdruck.

Sofern man kein Console.ReadLine(); verwenden kann, will oder soll und das Visual Studio verwendet, ist es auch möglich seine Anwendungen mit der Tastenkombination Strg+F5 auszuführen. Damit adaptiert das Visual Studio das Standardverhalten von VC++ 6.0 und wartet nach der Ausführung der Anwendung auf einen Tastendruck. Der Nachteil dieser Methode ist aber, dass dieser Tastendruck nur beim Debuggen mit Visual Studio gefordert wird, nicht beim kompilierten Programm.

Wenn das Programm fertig ist, sollte man das ReadLine unbedingt wieder entfernen, da es stört und verwirrt, wenn die Anwendung (später) direkt aus der Eingabeaufforderung gestartet wird.

Thema: [FAQ] Auf die parallele Schnittstelle zugreifen
Am im Forum: FAQ

In I/O Ports Uncensored - 1 - Controlling LEDs (Light Emiting Diodes) with Parallel Port findet man einen Artikel über das Ansteuern der parallelen Schnittstelle.

Thema: [FAQ] Auf COM1 (serielle Schnittstelle) zugreifen
Am im Forum: FAQ

Eine genaue Spezifikation der RS-232 Schnittstelle findet man in RS232 Specifications and standard.

Um auf diese Schnittstelle zugreifen zu können bietet sich die MSComm Komponente von Microsoft an. Eine genau Erklärung zu dieser Komponente findet sich in Serial COM Simply in C#. Einen Download findet man in MSCOMM32.OCX MSComm Control: Visual Basic Programmer's Guide to Serial Communications.

Wenn man .net 2.0 verwendet kann man die Klasse System.IO.Ports.SerialPort verwenden.

Siehe auch Template SerialPort.

Thema: DirectX: Tutorial
Am im Forum: Grafik und Sound

Hi!

Zitat
Mich würd mal interessieren wie lange du schon (C#) proggst und vor allem wie weit du das hier noch durchziehen möchtest. Ist doch ne ganze Menge Arbeit.

So ca. 2.5 Jahre und schreiben will ich das halt solange ich Zeit und Lust habe -.-

Das Tutorial ist jetzt unter Link verfügbar

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Der Indexbuffer - Indizieren von Vertices

Diesmal sehen wir uns den sogenannten Indexbuffer an. Indexbuffer sind dazu da um Vertices zu reduzieren.
Bei einer Indizierung fallen nämlich doppelte Vertices weg und man kann so einen Vertexbuffer deutlich optimieren.
Nehmen wir an wir wollen zwei Dreiecke zeichnen. Grafisch würde das so aussehen:
1 2|4


0|3 5

Die Nummern geben dabei die einzelnen Vertices an. Für dieses Beispiel bräuchten wir also 6 Vertices in einem
Vertexbuffer. Jedoch fällt uns auf das zwei Vertices mit den selben Koordinaten zweimal im Vertexbuffer stehen.
Ist das nicht sinnloser Verbrauch von Speicherplatz? Deshalb erstellt man nun einen Indexbuffer in dem man
speichert, an welcher Position welcher Vertex ist. (sry, aber ihr solltet den Beitrag quoten oder die im zip beiliegende Tutorial.txt ansehen, dort wird die Tabelle richtig dargestellt -.- )
Index Wert Vertex
0 0 (x0,y0)
1 1 (x1,y1)
2 2 (x2,y2)
3 0 (x0,y0)
4 2 (x2,y2)
5 5 (x5,y5)

Wie wir in der Tabelle sehen müssen wir nur mehr 4 verschiedene Vertices speichern, nicht mehr 6 verschiedene.
In diesem Beispiel mag das nicht als viel erscheinen, aber wenn man große Objekte hat, kann man mit Indexbuffer
viel einsparen und sehr gut optimieren. Zu beachten ist aber, dass man jedoch 6 Indices braucht. In DirectX SDK
Hilfe wird übrigens empfohlen nur mit indizierten Vertices zu arbeiten. Und nun können wir bereits zu Praxis
kommen. Direct3D stellt uns die Klasse IndexBuffer zur Verfügung, um einen IndexBuffer zu erstellen. Wir werden
jedoch nicht direkt mit dem Indexbuffer arbeiten sondern verwenden ein Mesh Objekt. Ein Mesh Objekt ist einfach
eine Klasse die das Arbeiten mit Vertexdaten vereinfacht.


Mesh Object;

Sehen wir uns nun die OnCreateDevice Funktion an. Hier erstellen wir zuerst 4 Vertices, danach 6 Indices und
speichern diese im Mesh Objekt:

		public void OnCreateDevice(object sender, EventArgs e)
		{
			Device dev = (Device)sender;

			CustomVertex.PositionOnly[] verts = { 			
										new CustomVertex.PositionOnly(-1f,  0f, -1f),
										new CustomVertex.PositionOnly( 1f,  0f, -1f),
										new CustomVertex.PositionOnly( 1f,  0f,  1f),
										new CustomVertex.PositionOnly(-1f,  0f,  1f),
			};

			short[] indices = { 0,1,2,		// erstes Dreieck
								  0,2,3 };	// zweites Dreieck

Dieser Code bietet uns keine Probleme. Wir verwenden short Indices aus Speicherplatzgründen, da wird ja nur kleine
Werte brauchen(von 0 bis 3) und so müssen wir auf dem RAM der Grafikkarte pro Index nur 2 Bytes verwenden anstatt
4 Byte wie bei int. Die Zahlen im indices Array weisen auf die Vertices hin, die beim Zeichnen verwendet werden.
Für das erste Dreieck verwenden wir die Vertices 0, 1 und 2. Fürs zweite 0, 2 und 3.

Object = new Mesh(indices.Length / 3,verts.Length,MeshFlags.WriteOnly,CustomVertex.PositionOnly.Format,
							  device);

			Object.VertexBuffer.SetData(verts,0,LockFlags.None);
			Object.IndexBuffer.SetData(indices,0,LockFlags.None);

		}

Hier erstellen wir ein neues Mesh Objekt und setzen die VertexBuffer und IndexBuffer Werte dafür. Die Parameter
des Mesh Konstruktors sind einfach:
Der erste Parameter gibt die Anzahl der Flächen eines Objektes an. Wir brauchen logischerweise 2 Flächen. Einmal
fürs erste Dreieck und einmal fürs Zweite.
Der zweite Paramter gibt dann die Anzahl der Vertices an. Der Dritte gibt sogenannte MeshFlags an. Diese können
dazu verwendet werden der Klasse gewisse Informationen zu geben, wie sie die Daten behandeln soll. Wir wollen nur
Daten in das Mesh Objekt schreiben, jedoch keine herauslesen. Dazu geben wir MeshFalgs.WriteOnly an. Das nächste
ist das Format der Vertexdaten. Der letzte Parameter gibt dann schließlich das Device an.
Danach greifen wir direkt auf den VertexBuffer und den IndexBuffer zu und setzen die Daten mit SetData.
Nun können wir auch schon zur Renderfunktion kommen.
Diese ist diesmal auch ganz einfach:

			device.Clear(ClearFlags.Target , System.Drawing.Color.Blue, 1.0f, 0);
			
			device.BeginScene();

			device.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 3.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) );
			device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );

			device.Transform.World = Matrix.Identity;
			
			device.RenderState.CullMode = Cull.Clockwise;
			Object.DrawSubset(0);

			device.EndScene();
			device.Present();

Der Code bietet eigentlich nur vertraute Dinge -.-

Was ist jetzt jedoch wenn wir direkt aus einem VertexBuffer und einem IndexBuffer heraus rendern wollen? Dazu
können wir die Funktion DrawIndexedPrimitives verwenden (oder DrawIndexedUserPrimitives wenn wir ohne Vertexbuffer
arbeiten wollen). Doch um diese Funktion müssen wir uns erstmal nicht kümmern, da uns ja die Mesh Klasse die
meiste Arbeit abnimmt.

Wie immer gibt es das gesamte Visual Studio 2003 .net Projekt als zip zum Download.(achtung, ich verwende immer jeweils das neueste SDK dh für diese Version braucht ihr das April Update des SDKs, ich glaube aber das es mit älteren Ausgaben des SDK auch funktionieren sollte)

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Texture Mapping

Alle unsere Objekte hatten bisher immer nur eine einzige Farbe und die Oberfläche der Objekte war glatt und durchgehend.
Jedoch hat eine solche Oberfläche so gut wie kein Objekt der realen Welt. Wenn man sich umschaut sind solche regelmäßigen
Anordnungen sehr selten und Oberflächen sind auch nicht sehr oft so glatt und "perfekt" wie wir sie bisher hatten.
Deshalb greifen wir auf das Texture Mapping zurück: Wir weisen unserem Objekt nicht einfach eine Farbe zu, sondern eine
Textur. Was ist jetzt eine Textur? Eine Textur ist ganze einfach ein Bild das wir über das Objekt legen. Dadurch können
wir jetzt zB einen Ziegelstein nicht einfach nur rot färben, sondern ihn auch ein realistisches Aussehen verpassen.
Sehen wir uns nun einmal an wie wir unsere Box texturieren können. Zunächst brauchen wir eine neue Variable vom Typ
Texture. In ihr speichern wir unsere Textur:


Texture textur;

Nun müssen wir unsere Textur laden. Das geht ziemlich einfach, da uns Direct3D die Klasse TextureLoader zur Verfügung
stellt, in der bereits vorgefertigte Funktionen zum Laden von Texturen enthalten sind:

public void OnCreateDevice(object sender, EventArgs e)
{
	Device dev = (Device)sender;

	textur = TextureLoader.FromFile(dev,"iron04.jpg");

Wir verwenden die Funktion FromFile, die als ersten Parameter das verwende Device verlangt und als zweiten das Bild,
das wir in der Textur speichern wollen. Die FromFile Funktion ist ein wahres Multitalent, denn laut SDK unterstützt
es die folgenden Bildformate: .bmp, .dds, .dib, .hdr, .jpg, .pfm, .png, .ppm, und .tga
In echten Spielen sollte man wenn möglich nicht jpg verwenden, so wie ich das hier tue, jedoch ist eine jpg schön klein
und als Beispiel sollte es reichen. Der Nachteil ist halt das ein jpg als Textur nicht wirklich toll aussieht.
Der Rückgabewert der Funktion ist ein Texture Objekt das die geladene Textur enthält.
Als nächstes müssen wir unsere Box anpassen. Bisher haben wir ja die Vertices der Box mit einer Farbkomponente erweitert,
jetzt müssen wir sie mit Texturkoordinaten erweitern.
Texturkoordinaten? Was sind Texturkoordinaten?
Wenn wir eine Textur auf ein Dreieck legen, woher soll Direct3D jetzt wissen wie es die Textur auf das Dreieck legen soll?
Deshalb gibt es die Texturkoordinaten, mit ihnen können wir bestimmen wie eine Textur auf ein Dreieck gelegt werden soll.
Als Anlehnung an Vertex werden diese Koordinaten auch Texel genannt. Ein Texel ist immer zwei dimensional(Bilder sind ja
auch nur zwei dimensional) und hat also 2 Achsen: Die u-Achse und die v-Achse. Die u-Achse ist eigentlich die x-Achse,
während die v-Achse die y-Achse ist. Der Koordinatenursprung einer Textur liegt jedoch in der linken oberen Ecke.
Eine weitere Besonderheit von Texel sind das sie in einem Intervall von [0,1] liegen. Dh das es bei allen Texturen nur
Texel zwischen 0 und 1 gibt unabhängig von der eigentlichen Größe der Textur. Der Texel 0,5 liegt daher immer in der Mitte
einer Achse.
Wir müssen nun also jedem Vertex einen Texel zuweisen, der anzeigt welcher Teil einer Textur auf diesen Vertex gelegt
werden soll.
Ein Beispiel: Nehmen wir an wir haben ein Rechteck mit 4 Vertices und eine Textur. Die Textur ist ebenfalls rechteckig
und wir wollen nun die Textur auf dieses Rechteck legen. Dazu müssen wir jetzt jedem Vertex des Rechteck einen Texel
der Textur zuweisen.
Sehen wir uns es jetzt den 1. Vertex an. Nehmen wir mal an das dieser in der linken oberen Ecke liegt. Wir können diesem
Vertex jetzt den Texel (0.0/0.0) zuweisen. Oder (1.0/1.0). Uns sind hierbei keine Grenzen gesetzt. Wir wollen aber die
Textur normal auf das Rechteck legen, also so wie ein Bildprogramm uns die Textur anzeigt, so wollen wir diese auf dem
Rechteck haben. Also weisem wir dem 1. Vertex den Texel (0/0) zu. Der 2. Vertex liegt nun in der rechten oberen Ecke.
Also weisen wir diesem Vertex den Texel (1/0) zu(wir müssen auf der u-Achse ganz nach rechts). Der 3. Vertex ist nun
die linke untere Ecke. Also brauchen wir hier den Texel (0/1). Und für den letzten Vertex brauchen wir schließlich den
Texel (1/1).
Ich hoffe mit diesem Beispiel versteht man die Texturkoordinaten recht gut. Am Besten ist es hier eine Zeichnung zu machen.
Kommen wir nun zum praktischen:

box = Mesh.Box(dev,2.0f,1.0f,2.0f);
			VertexFormats format = VertexFormats.PositionNormal | VertexFormats.Texture1;
			Mesh tempBox = box.Clone( box.Options.Value, format, dev );
			box.Dispose();
			box = tempBox;

			CustomVertex.PositionNormalTextured[] verts = (CustomVertex.PositionNormalTextured[])box.VertexBuffer.Lock( 0, 
				typeof( CustomVertex.PositionNormalTextured ), 
				LockFlags.None, 
				box.NumberVertices );

Wir wir sehen ist der Code nicht allzu schwer. Das VertexFormat der Box müssen wir auf PositionNormal und Texture1 setzen.
Texture1 beschreibt, das wir pro Vertex 1 Texel haben.
Danach müssen wir noch die neuen Vertices die wir schreiben wollen erstellen. Hierbei müssen wir PositionNormalTextured
verwenden, anstatt PositionNormalColored.
Nun kommen wir zum zuweisen der Texel, was nicht sonderlich schwer ist:

for(int i=0;i < verts.Length;++i)
	{
			verts[i].Tu = verts[i].X * 0.8f;
			verts[i].Tv = verts[i].Y * 0.8f;
	}
box.VertexBuffer.Unlock();
}

Sehen wir uns jetzt das Rendern an. Bevor unsere Box normal rendern können, müssen wir noch die Textur setzen. Dh wir
müssen Direct3D sagen das es jetzt für die nächsten Operationen wo es Texturen braucht die Textur nehmen soll, die wir
gesetz haben.

device.SetTexture(0,textur);
Was hat die 0 hier zu bedeuten? Wie wir später sehen werden gibt es verschiedene Texture Stages. Die untereste dieser
Schichten ist die Stufe 0. Mit diesen Texturstages werden wir später zwei oder mehr Texturen miteinander verbinden können
und auf unser Objekt legen. Dieses Verfahren nennt man dann Multi-Texturing.
Nun können wir unser Objekt mit der Textur rendern:

box.DrawSubset(0);

Und das wars schon. Mit Texturen kann man natürlich noch viel mehr anfangen, doch dazu mehr in späteren Teilen
Anbei ist natürlich wieder das Visual Studio .net 2003 Projekt sowie die Datei iron04.jpg

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Input -> Output

Nun, in unseren Anwendungen war jetzt zwar bereits etwas Bewegung. In Spielen kommt jedoch noch ein weiterer Faktor
hinzu: Der Userinput. Ohne diesen gäbe es eigentlich keine Spiele. Deshalb sehen wir uns einmal eine vereinfachte Form
an, die wir in unseren Anwendungen nutzen können. Unser Ziel ist einfach: Wir wollen anhand der Leertaste steuern
ob sich unser Objekt dreht oder nicht.
Dazu überschreiben wir einfach die Funktion ProcessCmdKeys der Basisklasse Form. Diese liefert uns im einem Parameter
die gerade gedrückte Taste.


protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
	return base.ProcessCmdKey( ref msg, keyData );
}

Nun können wir unseren bisherigen Eventhandler für Input löschen und fügen hier folgendes ein:

if(keyData == Keys.Escape)
		Application.Exit();

Nun kommen wir zum eigentlichen Teil: Zunächst reduzieren wir den Rendercode auf eine Box(und löschen nebenbei natürlich
überflüssigen Code für das zweite Objekt aus dem letzten Tutorial)

		private void Render()
		{
			if (device == null) 
				return;


			//Clear the backbuffer to a blue color 
			device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);
			//Begin the scene
			device.BeginScene();

			device.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 3.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) );
			device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );

			Matrix world;
			world = Matrix.Scaling(0.5f,0.5f,1.5f);
	
			device.Transform.World = world;

			box.DrawSubset(0);

			device.EndScene();
			device.Present();
		}

Nun müssen wir eine Variable vom Typ bool in unsere Klasse aufnehmen, die anzeigt ob das Objekt derzeit rotieren soll
oder nicht:

bool rotate = false;

Und schon kommen wir wieder zur ProcessCmdKey Funktion:

if(keyData == Keys.Space)
		rotate = !rotate;
Wir fragen ab ob die Leertaste(Space) gedrückt wurde, wenn ja dann wird roate invertiert(aus false wird true gemacht,
aus true false).

Nun müssen wir jedoch noch in die Render Funktion etwas ändern.
Vor dem device.Transform.World = world müssen wir noch abfragen ob rotate auf true ist, wenn ja dann müssen wir unser
Objekt drehen lassen.

	Matrix world;
	world = Matrix.Scaling(0.5f,0.5f,1.5f);

	if(rotate)
		world *= Matrix.RotationX(Environment.TickCount * (float)0.0025);
			
	device.Transform.World = world;

	box.DrawSubset(0);

Und damit ist es schon fertig. So einfach kann Benutzereingabe sein ^^
Wie immer ist das fertige Projekt im Visual Studio .net 2003 Format dabei. Außerdem ist in der Zip Datei das Tutorial als Txt enthalten ...

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Mehr als 2 Objekte

Bisher hatten wir immer nur 1 Objekt auf unserem Bildschirm. Das wird sich nun ändern, da wir nun zwei Objekte rendern
werden. Wie immer baut dieses Tutorial auf den anderen auf, sowohl im Wissen, als auch im Code. Doch nun zum
vergnüglichen Teil ^^
Zuerst brauchen wir natürlich zwei Objekte, dazu nehmen wir einfach die rote Box aus dem vorgen Teil und eine Teekanne.
Lassen wir die Teekanne einfach mal grün sein.
Dazu machen wir eigentlich dasselbe, was wir mit der Box getan haben: Eine Variable vom Typ Mesh erzeugen, in ihr eine
Teekanne speichern und danach die Farbe verändern. Zuerst definieren wir die Membervariable sphere:


Mesh teapot;

Danach weisen lassen wir uns wieder durch eine statische Funktion eine Kugel vorberechnen und speichern diese in der
Variable teapot:

teapot = Mesh.Teapot(dev);
Die Mesh Klasse ist wirklich toll ^^
Nun machen wir dasselbe, was wir für die Box getan haben. Wir verändern die Farbe der Teekanne. Da wir den Code gleich
nach dem erstellen der Box einfügen, müssen wir nicht wieder extra Variablen einfügen und können so das Vertex Format von
oben verwenden:

tempBox = teapot.Clone( teapot.Options.Value, format, dev );
			teapot.Dispose();
			teapot = tempBox;

			verts = (CustomVertex.PositionNormalColored[])teapot.VertexBuffer.Lock( 0, 
				typeof( CustomVertex.PositionNormalColored ), 
				LockFlags.None, 
				teapot.NumberVertices );
		

			for(int i=0;i < verts.Length;++i)
			{
				verts[i].Color = Color.Green.ToArgb();
			}
			teapot.VertexBuffer.Unlock();

Jetzt kommen wir zum interessanten Teil. Und zwar zum Rendern. Zuerst begnügen wir uns mal, einfach beide Objekte zu
rendern, ohne sie zu rotieren o.ä.
Dazu müssen wir für jedes Objet zuerst eine World Matrix setzen und es dann damit zeichnen.
Anders ausgedrückt:
Begin Scene
Projection Matrix setzen
View Matrix setzen

World Matrix für Objekt 1 setzen
Objekt 1 rendern

World Matrix(und evtl. auch Projection und View Matrix) für Objekt 2 setzen
Objekt 2 rendern
World Matrix für Objekt 1 setzen
Objekt 1 rendern

World Matrix(und evtl. auch Projection und View Matrix) für Objekt n setzen
Objekt n rendern
End Scene

Das ist natürlich stark vereinfacht ausgedrückt, da in echten Spielen natürlich noch haufenweise andere Sachen dazukommen(
wie z.B. Kollisionsabfrage, Benutzereingabe etc.). Wir werden später noch sehen, wie man eine einfache Benutzereingabe
verwirklichen kann.
Sehen wir uns nun einmal an, wie wir das rendern verwirklichen. Zuerst setzen wir die Projection und View Matrix, für unser
Beispiel reicht eine Projection und eine View Matrix.

device.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 3.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), 
											new Vector3( 0.0f, 1.0f, 0.0f ) );
device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );

Danach setzen wir die World Matrix für das erste Objekt und zeichnen es:

Matrix world;
world = Matrix.Scaling(0.5f,0.5f,1.5f);
			
world *= Matrix.Translation(-1.0f,0.0f,0.0f);
device.Transform.World = world;

box.DrawSubset(0);

Zuerst verkleinern wir das Objekt und strecken es auf der z Achse "nach hinten". Danach verschieben wir das Objekt um
eine Einheit nach links(auf der x Achse, negative Koordinaten sind hierbei nach links gerichtet). Schließlich rendern wir
es.
Nun zum zweiten Objekt. Wir setzen unsere Variable world zuerst auf die Identitätsmatrix:

world = Matrix.Identity;
Nun verkleinern wir das Objekt ein wenig und rotieren seitlich. Danach verschieben wir es um eine Einheit nach rechts.

world = Matrix.Scaling(0.5f,0.5f,1.0f);
world *= Matrix.Translation(1.0f,0.0f,0.0f);
world *= Matrix.RotationX(380);

Nun setzen wir die neue World Matrix und rendern die Teekanne:

device.Transform.World = world;
teapot.DrawSubset(0);

Und das wars schon. Was ganz wichtig ist, man darf vor dem rendern nicht vergessen, eine neue World Matrix zu setzen, denn
ansonsten wir weiterhin die Alte verwendet. Das könnt ihr ja ausprobieren. Kommentiert einfach mal den device.Transform.World =
world; vor dem teapit.DrawSubset(0); aus. Ihr werdet sehen, das die Teekanne dann auf der Box liegt. Kein schöner
Anblick(ich weis, die derzeitige Szene ist auch nicht gerade "schön", aber das muss man einfach können. Wenn wir dann
Spiele programmieren wollen, müssen wir uns auf diese Grundlagen zurückerinnern ^^)

Im nächsten Teil sehen wir uns dann eine einfache Benutzereingabe an. Wie immer gibt es den Source zum Download und seit
dem 5. Tutorial lege der zip Datei noch das Tutorial als txt File bei.

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Der Box eine Farbe zuweisen

Nun, wir haben jetzt zwar eine schöne Box, jedoch ist sie noch komplett weiß. Das bringt uns natürlich nicht viel,
da wir ja mal aufregende Spiele schreiben wollen. Wie bringen wir jetzt jedoch Direct3D dazu, die Box mit einer
Farbe zu rendern? Das ist eigentlich ganz einfach: Wir verändern einfach die Vertices der Box direkt. Und dazu
kommen wir wieder auf unsere Vertex Buffer zu sprechen, aber wir brauchen diesmal keinen selber erstellen, sondern
wir holen uns die Vertex Daten einfach aus der Mesh Klasse(die diese ja speichert).
Und das ist mit ein paar Handgriffen gemacht. Zuerst müssen wir unseren Mesh "klonen" und bei diesem Vorgang das
Vertex Format ändern. Dies ändern wir so ab, dass wir die Box ganz normal transformieren können, jedoch jedem Vertex noch
eine Farbe zuweisen können. Nachdem das getan ist, holen wir uns die Vertex Daten des Mesh und schreiben einfach unsere
gewünschte Farbe hinein und geben die Vertex Daten der Mesh Klasse wieder bekannt. Und hierbei verändern wir nur die
Farbkomponente, nicht die Koordinaten der Vertices, da diese ja bereits vorberechnet wurden.
Sehen wir uns nuneinmal an, wie wir unseren Mesh klonen und ihm ein neues Vertex Format zuweisen:


VertexFormats format = VertexFormats.PositionNormal | VertexFormats.Diffuse;
Mesh tempBox = box.Clone( box.Options.Value, format, dev );
box.Dispose();
box = tempBox;

Zuerst definieren wir eine Variable vom Typ VertexFormat das unser VertexFormat enthält. Das VertexFormat für uns ist
PositionNormal(das standardmäßig verwendet wird) und dazu fügen wir Diffuse hinzu. Diffuse beschreibt die diffuse Farbe
eines Vertex. Die diffuse Farbe können wir uns derzeit einfach als jene Farbe merken, die man direkt sieht. Wir werden
später, wenn wir unsere Szene beleuchten sehen, dass es noch andere Arten von Farben gibt bzw. Lichtfarben.
Danach verwenden wir die Funktion Clone um einen vorläufigen Mesh zu erstellen. Danach löschen wir den eigentlichen Mesh
wieder und weisem unserem Mesh den Vorläufigen zu.
Nun müssen wir an die Vertex Daten kommen. Das geht ebenfalls äußerst einfach: Wie im Kapitel über Vertex Buffer locken
wir ihn einfach und kommen so an seine Daten(Lock sperrt die Daten eines Vertex Buffers für weitere Zugriffe und gibt
uns eine Referenz aus diese zurück. Die Änderungen werden übernommen und der Vertex Buffer entsperrt, wenn wir Unlock
aufrufen)
Gespeichert werden sie natürlich in einem Array vom Typ PositionNormalColored

CustomVertex.PositionNormalColored[] verts = (CustomVertex.PositionNormalColored[])box.VertexBuffer.Lock( 0, 
															typeof( CustomVertex.PositionNormalColored ), 
															LockFlags.None, 
															box.NumberVertices );

Da uns Lock nur ein System.Array zurückgibt, müssen wir dies erst explizit auf CustomVertex.PositionNormalColored casten.
Der Erste Parameter bestimmt die Menge an Daten, die wir sperren wollen. Wenn wir 0 angeben, wird der gesamte Vertex
Buffer gesperrt. Beim zweiten Parameter müssen wir bestimmen, welchen Typ die zurückgegebenen Daten haben sollen.
Der Dritte bestimmt die Lock Flags, die wir hier jedoch vernachlässigen können. Der letzte Parameter bestimmt, wie viele
Vertices zurückgegeben werden sollen. Da wir ja jeden Vertex des Mesh verändern wollen, müssen wir auch alle angeben.
Der nächste Schritt ist, die Vertex Daten zu verändern. Dazu gehen wir jeden Vertex durch und ändern seine Farbe:

for(int i=0;i < verts.Length;++i)
{
	verts[i].Color = Color.Red.ToArgb();
}
Die Variable Color ist uns bereits im Kapitel über Vertex Buffer begegnet, sie bestimmt welche Farbe der Vertex haben soll.
Als Letztes müssen wir den Vertex Buffer wieder entsperren, um die Änderungen zu übernehmen.

box.VertexBuffer.Unlock();

Nun rotieren wir unseren Mesh noch:

Matrix world;
world = Matrix.Scaling(1.0f,2.0f,1.0f);
			
int iTime = Environment.TickCount % 1000;
float fAngle = iTime * (2.0f * (float)Math.PI) / 1000.0f;
			
world *= Matrix.RotationY(fAngle);
world *= Matrix.Translation(0.0f,0.0f,0.0f);

device.Transform.World = world;
box.DrawSubset(0);

Und das wars schon. Direct3D ist einfach, wenn man weis wie's geht ^^

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

3D Objekte

Bisher waren unsere Programme eher langweilig. Klar gibt es heute noch 2D Spiele und und 2D war mal das Maß aller Dinge, aber die richtige Action gibt's heute mit 3D. Und deshalb werden wir uns jetzt mal ansehen, wie man einfache 3D Objekte mit Direct3D erstellt und diese anzeigt.
Zunächst jedoch ein wenig Theorie, um überhaupt zu verstehen, wie 3D Objekte gespeichert werden: Wie unschwer zu erkennen ist der Monitor vor euch eine Fläche. Dh das er 2 Koordinaten hat. Die x und die y Koordinate(wie man es beim karthesischen Koordinatensystem in der Schule lernt ^^). Durch ein Koordinatenpaar x|y können wir nun jeden beliebigen Punkt auf diesem Monitor angeben. Aber wie kann man dann 3D Objekte, wie man sie in jedem Spiel hat, abbilden? Wie ist es möglich, dass man eine 3D Szene auf ein 2D Koordinatensystem abbildet? Die Antwort ist simpel: Man führt einfach noch eine Koordinate ein(die z Koordinate), die einfach mit den beiden vorhanden Koordinaten verknüpft wird. Nun, das klingt ein wenig schwer verständlich, jedoch ist es im Endeffekt für uns Programmierer sehr einfach: Wir geben einfach bei Koordinaten eine z Koordinate zusätzlich an, die Tiefeninformationen speichert. Eine positive z Koordinate zeigt dabei an, dass wir "in den Bildschirm hinein" wollen, eine negative "aus dem Bildschirm heraus". Mathematisch ausgedrückt müssen wir nun also eine Formel finden, die uns nun aus einem Koordinaten Tripel x|y|z ein Koordinatenpaar x|y macht. Dazu können wir nun auf etwas, das wir jeden Tag erleben: Wenn wir uns von einem Haus entfernen, dann erscheint es mit zunehmender Entfernung kleiner. Nähern wir uns dem Haus, wird es größer. Dazu dividieren wir x und y einfach durch z. Die Koordinaten, die wir dadurch erhalten nennt man projezierte Koordinaten. Die Formel lautet nun:
x' (x projeziert) = x / z
y' (y projeziert) = y / z

Wir müssen uns diese Formel nicht merken und uns um diese Umrechnung auch keine Sorgen machen: Direct3D bzw. die Grafikhardware macht dies automatisch.(dazu stecken wir ja mehrere hundert € in Grafikkarten(zumindest ich ^^))

Jetzt können wir uns wieder Direct3D zuwenden. Normalerweise würde hier nun ein Beispiel kommen, in dem man einen Vertex Buffer und einen Würfel oder eine Pyramide erzeugt, jedoch will ich jetzt mal nicht diesen Weg gehen. Und zwar nutzen wir einfach eine vorgefertige Funktion, die uns bereits eine "Box" aus 3 Parametern berechnet und die wir dann leicht anzeigen können.
Zunächst deklarieren wir eine neue Variable box vom Typ Mesh. Mesh ist eine Klasse, in der man genau solche Vertex Informationen leicht speichern und anzeigen kann(bisher haben wir uns ja um die Erstellung eines Vertex Buffers gekümmert und um dessen anzeigen ...).


Mesh box;

Nun verwenden wir die statische Funktion Box der Klasse Mesh, die uns aus 3 Parametern eine Box berechnet und uns eine Variable vom Typ Mesh zurückgibt.

public void OnCreateDevice(object sender, EventArgs e)
{
			Device dev = (Device)sender;

			box = Mesh.Box(dev,2.0f,1.0f,2.0f);
}
Die Parameter sind simpel: Der Erste ist einfach das device. Der zweite beschreibt die Ausdehnung auf der x Achse. Der dritte auf der y Achse und letzte schließlich, *trommelwirbel*, auf der z Achse.
Diese Funktion berechnet uns nun aus diesen Parametern eine Box die wir in der der Variable box speichern. Einfach, nicht wahr?

Nun kommen wir zum anzeigen. Das geht ebenfalls entsprechend einfach. Wir springen in unsere Render Funktion und rufen die Funktion DrawSubset auf. Fertig.

box.DrawSubset(0);
Um den Parameter brauchen wir uns erstmal nicht kümmern.(erst später, wenn wir dann zB Vertex Daten von Dateien laden o.ä.)

Die Mesh Klasse bietet uns jedoch nicht nur eine Funktion, für die Erstellung einer Box, sondern wir können mir ihr auch noch Teekannen, Zylinder, Kugeln und Ringe erzeugen. Und natürlich auch beliebige 2D Polygone(ein Polygon ist einfach der Sammelbegriff für Dreiecke, Vierecke, Sechsecke usw.). Einfach mal ein wenig in der Klasse rumstöbern ^^

Einen Schönheitsfehler hat das ganze jedoch. Die Box erscheint weiß. Logisch, wir haben ja auch keine Farbe angegeben. Wie können wir der Box jetzt jedoch eine Farbe zuweisen? Nun, dazu müssen wir einfach die Vertex Daten ändern, doch dazu im nächsten Kapitel mehr.

Wie immer gibt es nun auch den Source als VS.net 2003 Projektfiles als Zip File.

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Die World Matrix

Sehen wir uns nun die World Matrix einmal genauer an. Im letzten Beispiel haben wir ja das Dreieck rotiert, was ist aber, wenn wir es still stehen lassen wollen. Dann müssen wir die World Matrix auf die Identitätmatrix setzen(was mit 1 oder 0 verglichen wird. Also eine Matrix + der Identitätsmatrix ergibt wieder die Matrix selbst). Das machen wir so:


device.Transform.World = Matrix.Identity;

Damit steht unser Dreieck jetzt still. Kommen wir jetzt zum Rotieren. Wir können das Objekt um die x Achse, die y Achse und um die z Achse rotieren. Die Parameter beschreiben immer den Winkel, um den rotiert werden soll:

int  iTime  = Environment.TickCount % 1000;
float fAngle = iTime * (2.0f * (float)Math.PI) / 1000.0f;
device.Transform.World = Matrix.RotationX(fAngle);

Hier wird unser Objekt jetzt eine Rotation um die X Achse vollziehen. Es gibt noch die Funktionen Matrix.RotationY(für die Y Achse) und Matrix.RotationZ(für die Z Achse)

Nun zum Translieren oder verschieben. Erstmal ein Beisiel:

device.Transform.World = Matrix.Translation(1.0f,0.0f,0.0f);

Wie unschwer zu erkennen, haben wir hier unser Dreieck auf der x-Achse verschoben(Vektorangaben sind immer x,y,z).
Und zum Schluss das skalieren. Das skalieren bedeutet ja vergrößern oder verkleiner.

device.Transform.World = Matrix.Scaling(1.5f,1.0f,1.0f);
Auch hier können wir auf den verschiedenen Achsen skalieren. Wichtig zu wissen ist, dass der Wert 1 bedeutet, das das Objekt seine ursprüngliche Größe behalten soll. Jeder Wert kleiner 1 bedeutet eine Verkleinerung, jeder Wert größer 1(so wie hier), bedeutet eine Vergrößerung.

In einer echten Anwendung wollen wir jedoch nicht einfach nur mal rotieren und mal translieren, sondern diese Operationen auch kombinieren. Das ist eigentlich ganz einfach: Wir müssen einfach eine Matrix bilden und diese dann als World Matrix setzen. Wie wir bereits wissen, müssen wir zuerst skalieren, dann rotieren und dann translieren. Wichtig ist, das man die einzelnen Ergebnisse(Skalieren,rotieren,translieren) miteinander mulitplizieren muss.(Eine Matrix Multiplikation ist jedoch nicht assoziativ d.h. Marix M * Matrix B ist ungleich Matrix B * Matrix M)

Matrix world;
			
// skalieren
world = Matrix.Scaling(1.0f,1.0f,1.0f);
// rotieren
world *= Matrix.RotationY(1.0f);
// translieren
world *= Matrix.Translation(1.0f,0.0f,0.0f);
			
device.Transform.World = world;

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Transformationen

Bisher waren unsere Programme eher langweilig. Jetzt wird sich das aber ändern, da wir jetzt Bewegung in die ganze Sache bringen. Und dazu brauchen wir jedoch ein wenig Mathematik. Wie wir bereits gesehen haben haben wir 3 Werte um einen Punkt in unserer Szene zu beschreiben. Diese sind die x Koordinate, die y Koordinate und die z Koordinate. Währe es nun nicht gut, wenn wir diese Werte zusammenfassen könnten und mit ihnen rechnen? Nun, das geht natürlich und das ganze nennt sich einen Vektor. Wir verwenden einen 3D Vektor, da wir ja 3 Werte verwenden. Wie man damit rechnet will ich hier mal ausklammern, da es bereits auf Wikipedia einen ausgezeichneten Artikel zu diesem Thema gibt.
Das nächste, was wir wissen müssen, ist der Begriff der Matrix. Eine Matrix ist eine rechteckige Anordnung von Zahlen. Wir werden gleich sehen, wozu wir eine Matrix brauchen.(Für die Rechenregeln verweise ich wieder auf Wikipedia).
Nun kommen wir erstmal zu einer wichtigen Frage: Wie können wir usnere Szene nun animieren bzw. in Bewegung versetzen.
Um das zu programmieren, müssen wir erstmal verstehen, wie unsere Vertices aus unseren VertexBuffern auf der Grafikkarte behandelt werden. Und zwar wird jeder Vertex duch eine sogenannte Fixed Function Geometry Pipeline. Dort werden die Vertices(welche als Vektoren vorliegen) mit 3 verschiedenen Matrizen transformiert. Anschließend werden die Vertices geclippt(= Culling) und ihre Koordinaten werden auf den Monitor skaliert d.h. die Koordinaten werden so angepasst, das sie auf bzw. für den Monitor passen.
Für uns sind nun die ersten 3 Schritte dieser Pipeline wichtig. Diese 3 Transformationen sind: World Transformation, View Transformation und Projection Transformation.
Sehen wir uns diese 3 einmal genauer an:
World Transformation:
Normalerweise sind alle Vertices relativ zum Ursprung des Objekts(also in einem lokalen Koordinatensystem). Jedoch müssen wir, um das Objekt auch anzeigen zu können, dieses lokale Koordinatensystem zu einem sogenannten world space transformieren. Der world space ist nichts anderes, als ein Koordinatensystem, in dem alle Koordinaten relativ zu einem gemeinsamen Ursprung sind. Welche genauen mathematischen Vorgänge das nun sind, dies ist für uns eher uninteressant. Für uns ist es jetzt wichtig zu wissen, das wir mit dieser World Transformation unser Dreieck aus dem vorigen Beispiel bewegen können. Und diese World Transformation wird durch eine Matrix dargestellt, die World Matrix. Wir können nämlich auf die World Matrix 3 verschiedenen Operationen anwenden: Translieren, Rotieren und Skalieren.
Translieren bedeutet einfach ein Objekt zu verschieben. Man kann es nach oben,unten und links,rechts verschieben. Rotieren ist wohl klar. Man rotiert das Objekt entweder um die x-Achse oder um die y-Achse. Und beim Skalieren kann man ein Objekt um einen bestimmten Faktor vergrößern oder verkleinern.
Ich habe jetzt von Objekt gesprochen, nun warum rede ich hier von Objekt und nicht von Matrix? Nun, alle diese Operationen werden auf die World Matrix angewendet und diese World Matrix wird ja wiederrum auf alle Vertices eines Objektes angewendet(wir können die World Matrix während der Laufzeit jederzeit verändern). DirectX bietet uns natürlich mehrere Funktionen, damit wir uns nicht mit den genauen Rechnungen herumschlagen müssen. Wichtig ist außerdem, dass wir skalieren, translieren und rotieren nicht einfach in beliebiger Reiehenfolge durchführen dürfen(bzw, können schon, jedoch kommen dann unlogische Verschiebungen zum Vorschein...) Die richtige Reihenfolge lautet: Skalieren und danach zuerst rotieren und zum Schluss translieren. Man kann auch zuerst translieren und dann rotieren(skalieren kommt immer als erstes.). Der unterschied ist einfach der, das ja um den Koordinatenursprung rotiert wird. Wenn man nun zuerst transliert und dann rotiert, dann wird das Objekt zuerst irgendwohin in der Szene gesetzt und dann nochmal um die Rotierung verschoben. Um diesen Effekt zu vermeiden, rotieren wir zuerst und translieren erst später.
View Transformation
Mit der View Transformation können wir eine Kamera oder auch Viewport erzeugen. Damit ist einfach gemeint, wohin der Betrachter einer Szene schaut. Eine View Matrix wird aus 3 Vektoren gebildet. Diese sind der eye point Vektor, der look-at Vektor und der world's up Vektor. Der eye point Vektor beschreibt, wo der Augenpunkt(Also der Ausgangspunkt) des Betrachters ist. Der look-at Vektor gibt an, wohin(also zu welchem Punkt) der Betrachter schaut. Und der world's up Vektor beschreibt die Ausrichtig auf der y Achse.(Dieser Vektor ist normalerweise [ 0,1,0] außer man will die Kamera um ihre eigene z Achse drehen).
Um eine View Matrix zu bilden, bietet uns DirectX wie immer die Möglichkeit dies mit mehreren vorgefertigten Funktionen zu tun.
Projection Transformation
Die Projection Transformation(beschrieben durch die Projection Matrix) ist dafür verantwortlich, das wir auf dem 2D Monitor eine 3D Szene darstellen und auch sehen können. Und zwar sorgt sie dafür, dass Objekte, die weiter weg sind, kleiner sind und Objekte, die näher sind, größer sind(also wie, als wenn man aus dem Fenster schaut.)

Nun, jetzt wissen wir die Theorie, jedoch noch nicht, wie man das in der Praxis anwendet. In der Praxis ist das aber äußerst einfach: Man berechnet einfach die jeweiligen Matrizen und gibt sie dann dem Device bekannt. Alle Objekte, die wir danach rendern, werden mit den derzeit gesetzten Matrizen transformiert. Jedes Objekt wird immer nur einmal durch die Pipeline geschleust, außer man render es nochmal im selben Frame.

Aber wir müssen noch etwas bedenken. Unsere Initalisierung wird von nun an länger sein. Deshalb werden wir ab jetzt auch eine neue Struktur des Quellcodes haben(der dem aus dem Tutorial sehr ähnlich ist ^^).

Kommen wir nun endgültig zur Praxis. Jedoch vorher müssen wir noch den Typ unserer Vertices ändern. Bisher hatten wir sie vom Typ TransformedColored, dies müssen wir jetzt ändern. Das Transformed bedeutet nämlich, das wir uns nicht um die einzelnen Transformationen kümmern wollen und diese DirectX überlassen wollen(was bei statischen Objekten ja auch durchaus sinnvoll sein kann). Wir benötigen jetzt jedoch Vertices vom Typ PositionColored.

Die einzelnen Matrizen setzen wir über uns device. D.h.
device.Transform.View = View Matrix
device.Transform.World = World Matrix
device.Transform.Projection = Projection Matrix


Jetzt wird es aber ernst: Die Render Funktion. Hier setzen wir zuerst die Matrizen und rendern dann aus unseren Vertex Buffer ein Dreieck. Die Besonderheit: Es dreht sich um die y Achse. Sehen wir uns zuerst die World Matrix an:


int iTime = Environment.TickCount % 1000;
float fAngle = iTime * (2.0f * (float)Math.PI) / 1000.0f;
device.Transform.World = Matrix.RotationY(fAngle);

Zunächst berechnen wir den Winkel, in dem sich das Dreieck rotieren soll. Danach setzen wir die World Matrix einfach über die Funktion Matrix.RotationY, welche uns eine Roation um die Y Achse mit dem angegbenen Winkel(fAngle) berechnet.

Nun die View Matrix:

device.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 3.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) );

Die View Matrix ist nichts besonderes. Zuerst wird der eye Point definiert, dann der look-at Vektor und dann noch world's up.

device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );

Hier die die Projection berechnet. Ebenfalls nichts besonderes.

In den nächsten Programmen werden wie die Projections Matrix und die World Matrix eher in den Schatten stellen und uns dafür ausgiebig mit der World Matrix beschäftigen.

Etwas, das wir noch klären müssen, ist warum wir das Culling ausschalten. Wir rotieren ja das Dreieck. Und beim rotieren sind die Vertices ja einmal gegen den Uhrzeigersinn angeordnet und einmal im Uhrzeigersinn. Wenn wir jetzt das Culling einschalten würden, würden wir je nach gesetzen Wert eine Seite des Dreiecks nicht sehen(einfach mal ausprobieren).
Ansonsten gibt es nicht mehr viel zu sagen. Der Code ist halt vom Microsoft DirectX Tutorial übernommen, aber ich hoffe mal, das das kein Problem darstellt.
Der gesamte Sourcecode ist wie immer als Visual Studio .net 2003 Projekt(gepackt als zip) angehängt.

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Renderstates

Was ist ein Renderstate? Nun, ein Renderstate beschreibt, wie Direct3D unsere Dreiecke zeichnen soll. Es gibt sehr viele verschiedene Renderstates, daher kann ich jetzt nicht auf alle eingehen(abgesehen davon, könnten wir viele Renderstates mit unserem bisherigen Wissen ohnehin nicht verstehen). Daher will ich mal das grundlegende Konzept der RSs zeigen, damit wir später keine Probleme haben.
Also zuerst mal, beeinflusst ein Renderstate wie ein Dreieck gezeichnet wird. Ein einfacher Renderstate wäre z.B. der FillMode. Der sagt Direct3D, ob unser Dreieck, entweder solid(was der Standard Wert ist und mit dem haben wir auch in den bisherigen Anwendungen gearbeitet), ob nur die Eckpunkte oder nur die Linien gezeichnet werden sollen. Wir können disen RS vor dem Rendern unseres Dreiecks einsetzen:


....
m_Device.RenderState.FillMode = FillMode.WireFrame;

			m_Device.SetStreamSource(0,m_VertexBuffer,0);
			m_Device.DrawPrimitives(PrimitiveType.TriangleStrip,0,1);
....

Mit dem WireFrame Modus werden von unserem Dreieck nur die Linien gezeichnet. Daneben gibt es noch FillMode.Solid, der der Standardwert ist. Und dann gibts noch FillMode.Point, der nur die Eckpunkte zeichnet.(Bemerkung: Wenn wir den DrawPrimitive Aufruf auf m_Device.DrawPrimitives(PrimitiveType.PointList,0,3); abändern, hätte wir den selben Effekt wir mit dem Renderstate FillMode auf Point. )

Natürlich gibt es noch viel mehr RSs als nur FillMode, daher will ich hier noch ein paar vorstellen.

Der nächste ist DitherEnable. Beim Dithering wird da, wo mehrere verschiedene Farben aufeinandertreffen, ein Mittelwert aus diesen berechnet und dieser dann eingesetzt. Auf heutigen Grafikkarten macht es fast keinen Unterschied, ob Dithering eingeschalter ist oder nicht, daher schalten wir es ein:

m_Device.RenderState.DitherEnable = true;

Und noch einer ist das Culling. Das Culling entscheided, welche Objekte sichtbar sind und deshalb gezeichnet werden und welche nicht sichtbar sind und nicht gezeichnet werden.
Direct3D unterstüztt bereits von Haus aus 2 einfache Arten von Culling, die in unseren Beispielanwendungen vollkommen ausreichen werden. Bei Spielen/Grafikdemos würde man natürlich zum Standard Culling noch sein eigenes implementieren.
Direct3D bietet uns das clockwise(CW) culling und das counterclockwise(CCW) culling. Wenn wir unsere Vertices im Uhrzeigersinn anordnen, brauchen wir CCW culling, damit die "unsichtbaren" Vertices wegfallen, wenn unsere Vertices gegen der Uhrzeigersinn angeordnet sind, müssen CW culling verwenden.
Der Standard Wert dieses RS ist CCW. Natürlich können wir das Culling auch komplett abschalten:

m_Device.RenderState.CullMode = Cull.CounterClockwise; // Standard. Unser Dreieck aus dem vorigen Beispiel würde gezeichnet werden
m_Device.RenderState.CullMode = Cull.Clockwise; // CW Culling. Um unser Dreieck jetzt zu zeichnen müssten wir die Elemente 0 und 2 austauschen
m_Device.RenderState.CullMode = Cull.None; // Alles wird gezeichnet. Es ist egal wie wir unsere Vertices anordnen

Gut, das waren mal 3 Renderstate, wir werden jedoch im Laufe des Tutorials noch viele mehr kennen lernen...

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Rendern von Dreiecken

Gut, weiter gehts. Dieses Kapitel wird viele grundlegende Dinge beinhalten, also gut aufpassen. Zunächst wollen wir einmal sehen, wie ein Dreieck aufgebaut ist: Ein Dreieck besteht aus 3 Eckpunkten,die miteinander verbunden werden. Und für jedes Dreieck, dass wir zeichnen wollen, müssen wir diese 3 Eckpunkte definieren. Aber wie müssen wir diese 3 Eckpunkte definieren, damit DirectX sie zeichnen kann? Nun, dass ist relativ einfach: Für Direct3D ist der Bildschirm nichts weiter als ein Koordinatensystem. Wir müssen nur die Koordinaten für die einzelnen Eckpunkte an Direct3D schicken und Direct3D zeichnet uns dann ein Dreieck. Wie ist dieses Koordinatensystem nun aufgebaut? Ich denke mal, dass jeder weis, was ein (karthesisches)Koordinatensystem ist. Für Direct3D exestieren 3 Achsen. Die x Achse, die y Achse und die z Achse. Die x Achse verläuft auf der horizontalen, die y auf der vertikalen. Die z Achse geht in den Bildschirm hinein. Da wir ja jetzt erstmal nur 2D Objekte rendern wollen, brauchen wir uns darum nicht zu kümmern. Zu sagen bleibt hierzu eigentlich nur noch, dass die englische Bezeichnung für Eckpunkt Vertex lautet, im Plural Vertices.
Um solche Vertices zu speichern, bietet uns Direct3D eine ganze Reihe von Strukturen. Diese sind alle im Namespace Microsoft.DirectX.Direct3D.CustomVertex zusammengefasst. In diesem Namespace sind ziemlich viele unterschiedliche Strukturen zum Speichern von Vertices, für uns ist jedoch nur die Struktur CustomVertex.TransformedColored (erstmal) interessant. Das Transformed bedeutet das wir 2D Koordinaten angeben wollen und das Color das wir jeden Eckpunkt eine Farbe zuweisen wollen. Wenn wir jetzt jeden Eckpunkt eine eigene Farbe zuweisen, wird der unmittelbare Bereich zu diesem Eckpunkt mit der Farbe gefärbt. An den Übergängen zwischen den einzelnen Farben, werden die Farben interpoliert. Beim interpolieren wird einfach ein Mittelwert zwischen den einzelnen Farben berechnet und dadurch kommt ein Farbverlauf zwischen den Farben zustande.
Jetzt müssen wir noch wissen, wie wir die Vertices speichern. Dazu müssen wir zunächst mal ein Array von CustomVertex.TransformedColored erstellen und mit unseren Daten befüllen. Dazu fügen wir unserer Klasse aus dem 1. Kapitel eine weitere private Variable verts hinzu:


private CustomVertex.TransformedColored[] verts;
Nun, diese Vertices liegen jetzt aber im Hauptspeicher(dem RAM). Wenn wir nun unser Dreieck rendern wollen, muss Direct3D diese erst über den AG Port(bzw. PCI Port) zur Grafikkarte transportieren. Bei ein paar Vertices, wird sich das sicher nicht bemerkbar machen, aber wenn wir jetzt mehrere tausend Vertices haben? Deshalb wäre es ja von Vorteil, wenn die Vertices direkt auf dem Speicher der Grafikkarte liegen würden.(Video RAM) Der Vorteil des Video RAM ist, dass er eine extrem kurze Zugriffszeit hat und das wir nicht bei jedem Rendervorgang, die Daten über den AG Port transportieren müssen. Ein Nachteil ist jedoch, dass der Video RAM von der Größe her relativ begrenzt ist und teuer ist. Aber darum müssen wir uns nicht kümmern. Also wir speichern wir jetzt unsere Vertices im Video RAM? Ganz einfach: Mit einem VertexBuffer. Ein VertexBuffer ist nichts anderes als ein Speicherbereich im Video RAM, der unsere Vertices hält. Ein VertexBuffer wird durch die Klasse Direct3D.VertexBuffer repräsentiert.

private VertexBuffer m_VertexBuffer;

Nun müssen wir unserer Vertices noch definieren und nebenbei den VertexBuffer mit diesen Daten befüllen. Zuerst definieren wir die Vertices:

verts = new CustomVertex.TransformedColored[3];

			verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1;verts[0].Color = Color.Yellow.ToArgb();
			verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1;verts[1].Color = Color.Bisque.ToArgb();
			verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; ;verts[2].Color = Color.White.ToArgb();

Wir sehen also, dass wir jedem Vertex eine X Koordinate, eine Y Koordinate, eine Z Koordinate und eine Farbe zuweisen. Wie gesagt, müssen wir uns eigentlich nicht um die Z Koordinate kümmern, jedoch habe ich sie auf 0.5 gesetzt, da ein 0.0 bei manchen(älteren) Grafikkarten zu Problemen führen könnte.
Nun erstellen wir den VertexBuffer und zwar mit den folgenden Konstruktor:
Zitat
public VertexBuffer(
Type typeVertexType,
int numVerts,
Device device,
Usage usage,
VertexFormats vertexFormat,
Pool pool
);

Der erste Parameter bestimmt, welchen VertexType wir für unseren VertexBuffer verwenden wollen. Hier setzen wir einfach typeof(CustomVertex.TransformedColored) ein.
Der zweite Parameter bestimmt die Anzahl der Vertices, die wir in unserem VertexBuffer speichern wollen. Da wir nur ein Dreieck speichern wollen, setzen wir hier eine 3 ein.
Der vierte Parameter bestimmt das Device, in welchem Kontext der VertexBuffer erstellt werden soll: m_Device.
Der fünfte Parameter bietet uns einen Satz von Konstanten an, die bestimmen, wie der VertexBuffer intern aufgebaut ist. Hier setzen wir Usage.WriteOnly ein, das besagt, das wir nur in den VertexBuffer schreiben wollen, ihn jedoch nicht auslesen(das kann zu kleineren Performancegewinnen führen)
Der vorletze Parameter ist das VertexFormat: CustomVertex.TransformedColored.Format
Der letzte Parameter bestimmt schließlich, wo wir unseren VertexBuffer speichern wollen. Hier können wir Pool.Default einsetzen, was besagt, dass Direct3D die Vertices einfach in den Video RAM plaziert. Pool.Managed übergibt die Kontrolle des VertexBuffers an den Grafikkartentreiber. Der kann dann z.B., wenn der Platz auf dem Video RAM knapp wird, unsere Vertices wieder in den RAM verschieben. Pool.SystemMemory besagt schlieslich, dass wir unsere Vertices im System RAM plazieren wollen, was die Vorteile eines VertexBuffers jedoch wieder zunichte macht.
In der Praxis sieht das nun so aus:

m_VertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, m_Device, Usage.WriteOnly, CustomVertex.TransformedColored.Format, Pool.Default);

Nun müssen wir unsere Vertices noch in den VertexBuffer hineinschreiben. Dazu müssen wir ihn zuerst sperren(locken), um sicherzustellen, dass während unseres Schreibvorgangs niemand anders auf den Buffer zugreift. Dann schreiben wir unsere Daten in den VertexBuffer und schlieslich entsperren wir ihne wieder(unlocken).Das ganze sieht so aus:

GraphicsStream stream = m_VertexBuffer.Lock(0,0,0);
			
			stream.Write(verts);
			m_VertexBuffer.Unlock();
Der Code bedarf eigentlich keiner großartigen Erklärungen, außer das die Parameter von Lock angeben, dass wir den ganzen VertexBuffer sperren wollen.
Nun kommen wir zum rendern.
Bevor wir unser Dreieck renden können, müssen wir unserem Device noch sagen, in welchem Format(CustomVertex.xxx) unsere Vertices gespeichert sind:

m_Device.VertexFormat = CustomVertex.TransformedColored.Format;

Jetzt haben wir zwei Möglichkeiten. Entweder wir rendern direkt aus dem SystemMemory heraus(unser Array verts liegt ja immer noch da drinnen) oder wir rendern vom VertexBuffer heraus. Ich zeig zuerst mal die Variante aus dem Systemmory, dazu nutzen wir die Funktion Device.

public void DrawUserPrimitives(
    PrimitiveType primitiveType,
    int primitiveCount,
    object vertexStreamZeroData
);
Der erste Parameter bestimmt den Primitive Type. Hier können wir entweder Punkte, Linien oder Dreiecke einsetzen.(Ein Primitiv ist nichts anderes als ein Punkt,Linie oder Dreieck) Wir setzen natürlich PrimitiveType.TriangleStrip ein. Es gibt mehrere Varianten von jedem Primitiv, TriangleSrip besagt, das wir, falls wir evtl. mehrere Dreiecke haben, die Dreiecke in einem Band miteinander verbunden gerendert werden.
Der nächste Parameter bestimmt die Anzahl der Primitive, die gezeichnet werden soll. Wir können unser verts Array z.B. mit 6 Elementen befüllen, um dann zwei Dreiecke zu zeichnen. Da wir aber nur ein Dreieck zeichnen wollen, setzen wir hier eine 1 ein.
Der letze Parameter bestimmt nun das Array, in dem unsere Vertices liegen: verts
Also hier der Code:

m_Device.DrawUserPrimitives(PrimitiveType.TriangleStrip,1,verts);

Nun kommen wir zur Methode mit den VertexBuffer. Bevor wir aus einem VertexBuffer heraus rendern können, müssen wir unserem Device sagen, aus welchem wir überhaupt rendern wollen(ja, wir können mehrere VertexBuffer haben...). Dazu nutzen wir die Funktion Device.SetStreamSource

m_Device.SetStreamSource(0,m_VertexBuffer,0);

Der erste Parameter bestimmt welchen Kanal(Vertex Stream) wir nutzen wollen. Einfach 0 einsetzen, denn das ist der 1. Vertex Kanal, auf dem die Vertices fließen.
Der zweite Parameter bestimmt jenden VertexBuffer, von dem die Daten kommen sollen.
Der letzte Parameter gibt den Offset vom Beginn des Streams bis zu den ersten Vertex Daten an. Hier setzen wir einfach wieder 0 ein.
Nun steht uns nichts mehr im Wege, aus dem VertexBuffer zu rendern. Und das machen wir via Device.DrawPrimitives.

m_Device.DrawPrimitives(PrimitiveType.TriangleStrip,0,1);

Die Parameter unterscheiden sich nicht allzu sehr von den Parametern von DrawUserPrimitives, bis auf 2., der den Start Vertex angibt, also den Vertex, ab dem gerendert werden soll(einfach 0). Der Letzte gibt wieder an, wie viele Primitive wir zeichnen wollen.

Dieses Kapitel war jetzt schon länger als das vorangehende. Zum Schluss nochmal der gesamte Code, wie immer gibts auch die Visual Studio .net 2003 Projektdateien zum Download:

using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace MDXTutorial02
{
	
	public class MDXSampleApp : System.Windows.Forms.Form
	{
		private Device m_Device;
		private VertexBuffer m_VertexBuffer;
		private CustomVertex.TransformedColored[] verts;
		

		// ctor
		// do nothing...
		public MDXSampleApp()
		{
		}

		// dtor
		~MDXSampleApp()
		{
		}

		public void InitGfx()
		{
			try
			{
				this.ClientSize = new Size(800,600);
				this.Text = "Direct3D Tutorial 2: Rendering colored Vertices";

				this.KeyPress += new KeyPressEventHandler(OnKeyPress);

				PresentParameters pp = new PresentParameters();

				pp.Windowed = true;
				pp.SwapEffect = SwapEffect.Copy;
				
				
				m_Device = new Device(Manager.Adapters.Default.Adapter,DeviceType.Hardware,this,CreateFlags.	HardwareVertexProcessing,
					pp);
				CreateVertexBuffer();

				
				
			
			}
			catch(DirectXException e)
			{
				MessageBox.Show(e.Message);
				
			}
		}

		private void CreateVertexBuffer()
		{
		
			verts = new CustomVertex.TransformedColored[3];

			verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1;verts[0].Color = Color.Yellow.ToArgb();
			verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1;verts[1].Color = Color.Bisque.ToArgb();
			verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; ;verts[2].Color = Color.White.ToArgb();

			m_VertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, m_Device, Usage.WriteOnly, CustomVertex.TransformedColored.Format, Pool.Default);

			GraphicsStream stream = m_VertexBuffer.Lock(0,0,0);
			
			stream.Write(verts);
			m_VertexBuffer.Unlock();
		}

	
		public void Render()
		{
			

			m_Device.Clear(ClearFlags.Target ,Color.Blue,0.0f,0);
			
			m_Device.BeginScene();
			
			m_Device.VertexFormat = CustomVertex.TransformedColored.Format;

			m_Device.SetStreamSource(0,m_VertexBuffer,0);
			m_Device.DrawPrimitives(PrimitiveType.TriangleStrip,0,1);
		    //m_Device.DrawUserPrimitives(PrimitiveType.TriangleStrip,1,verts);
			
			m_Device.EndScene();
			m_Device.Present();

		}

		public void Shutdown()
		{
			m_Device.Dispose();
		}

		

	
		/// <summary>
		/// Der Haupteinstiegspunkt für die Anwendung.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			MDXSampleApp example = new MDXSampleApp();
			example.InitGfx();
			example.Show();

			while(example.Created)
			{
				example.Render();
				Application.DoEvents();
			}
			example.Shutdown();

		}

		private void OnKeyPress(object sender, KeyPressEventArgs e)
		{
			if((int)e.KeyChar == (int)Keys.Escape)	
				this.Close();
			
		}
	}
}

Thema: Managed Direct3D Tutorial
Am im Forum: Grafik und Sound

Ab sofort ist die neueste Version des Tutorials hier zu erreichen.

Hi!

weil hier immer wieder mal nach DirectX Tutorials gefragt wird, hab ich einfach mich mal dazu entschlossen eins zu schreiben. Um das hier zu verstehen braucht man keine besondere Erfahrung mit C#. Aber man sollte schon sicher mit C# umgehen können und auch mit WindowsForms sollte man schon ein wenig gearbeitet haben. Feedback etc. sind natürlich erwünscht. Der Sourcecode dieses Tutorials ist am Schluss als Zip angehängt.

DirectX: Eine Einführung

DirectX wurde 1995 erstmals von Microsoft unter dem Namen The Games SDK(oder so...) vorgestellt. Davor war(zu DOS Zeiten) musste man umständlich auf Assembler zurückgreifen, wenn man irgendwas mit Grafik machen wollte. DirectX vereinfachte dies extrem und wurde von Version zu Version immer weiter entwickelt und auch immer besser. Derzeit stehen wir bei Version DirectX 9. DirectX ist eigentlich eine Sammlung von mehreren APIs. Diese sind DirectInput um Daten von Tastaturen,Mäuse,Joysticks etc. zu empfangen und verarbeiten, DirectSound/Music um Sounds/Musik zu spielen, DirectPlay um Netzwerkprogramme wie Multiplayer Spiele zu schreiben, DirectShow um Videos abzuspielen und zu guter Letzt Direct3D um auf dem Bildschirm zu zeichnen. Daneben gibt es noch DirectDraw, mit dem man ausschließlich 2D Objekte zeichnen kann(mit Direct3D kann man sowohl 3D als auch 2D Objekte zeichnen) und DirectSetup, ein Setup Generationsprogramm spez. für DirectX Applikationen.
Dieses Tutorial befasst sich also nicht mit dem gesamten DirectX Multimedia Packet, sondern "nur" mit Direct3D. Es muss natürlich gesagt werden, dass jeder Unterbereich von DirectX schon allein ziemlich groß ist. So, nun wollen wir mal sehen, welche Möglichkeiten uns Direct3D bietet. Ebenso werden die nächsten Kapitel ziemlich Theorie beinhalten, mit nur relativ wenig Code. Aber durchhalten. Wir werden bald zu unseren ersten Zeichenoperationen kommen...

Direct3D: A closer look

Voll DirectX 9 kompatibel.
Damit wird seit längerer Zeit von vielen Grafikkartenherstellern geworben. Die Grafikkartenhersteller meinen damit natürlich Direct3D.(DirectInput auf der Grafikkarte? ^^) Aber was macht Direct3D eigentlich genau? Direct3D bietet uns die Möglichkeit auf dem Bildschirm Objekte zu zeichnen. Denkt einfach mal an ein Spiel wie Far Cry. Der ganze tolle Dschungel dort wird mit Direct3D gezeichnet.(achja, wir haben noch einen langen Weg vor uns, bis wir sowas wie Far Cry machen können). Aber wie sind diese Objekte jetzt aufgebaut? Die Antwort ist einfach: Aus Dreiecken. Denn aus Dreiecken kann man jedes beliebige Objekt zusammenstellen. Nehmt einfach einen Zettel und malt ein Rechteck drauf. Wie ihr vielleicht sehen könnt, besteht ein Rechteck aus zwei sich gegenüberliegenen rechtwinkeligen Dreiecken. Eine solche Aufteilung in Dreiecken lässt sich praktisch bei jedem Objekt machen. D.h. wir können also Dreiecke mit Direct3D zeichen.(man kann aber auch Punkte und Linien zeichnen, aber am öftesten verwendet man Dreieckte). Aber Direct3D kann noch mehr. Es kann diese Dreiecke nun texturieren. Normalerweise kann man einem Dreieck nur eine Farbe zuweisen(blau,gelb,rot....), aber das ist natürlich langweilig. Deshalb erfand man eine Technik namens Texturieren. D.h. das man einfach ein Bild über das Dreieck legt. Damit sehen Objekte viel realitätsnäher aus. Desweiteren kann man mit Direct3D auch Licht erzeugen.(Lights) Das ist allerdings ziemlich komplex, daher werden wir das erst später besprechen. Zum Schluss kann Direct3D Dreiecke noch verschieben,vergrößern und verkleinern. Aber das werden wir auch noch später genauer kennen lernen.
so, jetzt haben wir uns mal einen groben Überblick über Direct3D verschafft. Jetzt können wir näher auf die einzelnen Bereiche eingehen. Zuerst sehen wir mal, wie wir Direct3D dazu bringen, dass es uns erlaubt irgendwas zu zeichnen.

Direct3D: Erste Schritte

Überlegen wir uns erstmal, was wir in diesem Kapitel erreichen wollen. Wir wollen ganz einfach ein Fenster erzeugen, das Blau(oder in irgendeiner anderen Farbe) gefärbt ist. Das ist sozusagen das "Hello World" von DirectX.
Was braucht man dazu? Ich sage mal ganz einfach, dass man mit einer IDE arbeiten sollte. Warum? Weil es das Leben vereinfacht. Ich selbst nutze VS.net 2003. Als nächstes braucht man halt die Standardtools, um mit C# zu programmieren. Zu guter Letzt braucht man noch das so genannte DirectX SDK. Das beinhaltet alles, was man braucht um mit DirectX zu programmieren. Nachdem das SDK installiert wurde, können wir weitermachen.(irgendwie logisch...).
Zunächst referenzieren wir auf folgende DLLs: System.dll,System.Drawing.dll,System.Windows.Forms.dll,Microsoft.DirectX.dll,Microsoft.DirectX.Direct3D.dll Microsoft.DirectX.Direct3DX.dll.
Nun binden wir folgende Namespaces ein, die eigentlich selbsterklärend sind:


using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

Für unsere erste DirectX Anwendung brauchen wir nur eine einzige Membervariable. Das DirectX Device(Microsoft.DirectX.Direct3D.Device m_Device). Ein Device ist die elementare Grundverbindung zwischen unserer Anwendung und Direct3D. Mit einem Device können wir alle oben genannten Dinge machen. Nun implementieren wir eine Funktion InitGfx(), die uns das Device erstellt.
Die ersten Zeilen dieser Funktion sollten kein Problem darstellen:

public void InitGfx()
{
	try
	{
		this.ClientSize = new Size(1024,768);
		this.Text = "Direct3D Tutorial 1";

		this.KeyPress += new KeyPressEventHandler(OnKeyPress);

Nun kommen wir zum interessanten Teil: Die PresentParameter. Diese werden wir später zum erstellen des Devices benötige. Zuerst mal der Code:

PresentParameters pp = new PresentParameters();

pp.Windowed = true;
pp.SwapEffect = SwapEffect.Copy;

Die PresentParamter(Präsentations Parameter) bestimmen also wie sich das Device grundlegend verhalten soll.(es gibt noch mehr, aber in unserem Fall reichen diese aus). Für unsere Applikation brauchen wir zunächst nur diese beiden Parameter. Der erste Paramter zeigt an, das wir eine Fensteranwendung haben wollen. Der Zweite gibt an, wie wir die Bilder auf den Bildschirm bringen wollen. Copy bedeutet einfach, dass wir immer den gesamten Bildschirm neuzeichnen wollen.
Nun geht daran, das Device zu erstellen:

m_Device = new Device(Manager.Adapters.Default.Adapter,DeviceType.Hardware,this,CreateFlags.HardwareVertexProcessing,
										pp);

ok. Gehen wir Parameter für Parameter durch:
Manager.Adapters.Default.Adapter: Gibt an, auf welchem Adapter(=Bildschirm) wir zeichnen wollen. Normalerweise haben die meisten Systeme einen Bildschirm. Und diesen Bildschirm repräsentiert Manager.Adapters.Default.Adapter.
DeviceType.Hardware: Das bedeutet, das für alle möglichen Operationen von Direct3D die Grafikhardware verwendet wird. Man kann auch bestimmen, das das die CPU(Software) machen soll, was aber ziemlich langsam ist.
this: Zeigt einfach an, das das Devie einfach dieses Fenster zum zeichnen verwenden soll.
CreateFlags.HardwareVertexProcessing: Besagt ebenfalls grundsätzlich das selbe wie DeviceType.Hardware, aber ist trotzdem ein wenig anders, außerdem gibts da noch ein paar andere Paramter, die aber für uns(derzeit) nicht interessant sind. Ich werde später noch genauer darauf eingehen.
pp: Zeigt auf die ausgefüllte PresentParameters Struktur.

Und jetzt noch der Abschluss der Funktion:

}
			catch(DirectXException e)
			{
				MessageBox.Show(e.Message);
			}
		}

Gut. Nun kommen wir zum Zeichnen. Das wird als Rendern bezeichnet. Deshalb implementieren wir einfach mal eine Funktion namens Render.

public void Render()
		{
			m_Device.Clear(ClearFlags.Target ,Color.Blue,0.0f,0);
			m_Device.BeginScene();
                             // rendern
			m_Device.EndScene();
			m_Device.Present();

		}

Der erste Funktionsaufruf ist nicht sonderlich interessant(derzeit...) und besagt, dass das Fenster(Target) mit einem blauen Hintergrund gerendert werden soll.
Danach kommen wir zum eigentlichen rendern. Das rendern geschieht immer zwischen einem BeginScene und einem EndScene. Doch das werden wir später auch noch genauer besprechen. Das Present veranlsst Direct3D nun, alles auch wirkich zu rendern.
Nun brauchen wir noch eine Funktion, die Direct3D herunterfährt und noch die Main Funktion. Schließlich implementieren wir noch die OnKeyPress Funktion...

public void Shutdown()
		{
			m_Device.Dispose();
		}

		

	
		/// <summary>
		/// Der Haupteinstiegspunkt für die Anwendung.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			MDXSampleApp example = new MDXSampleApp();
			example.InitGfx();
			example.Show();

			while(example.Created)
			{
				example.Render();
				Application.DoEvents();
			}
			example.Shutdown();

		}

		private void OnKeyPress(object sender, KeyPressEventArgs e)
		{
			if((int)e.KeyChar == (int)Keys.Escape)	
				this.Close();
		}

Hier jetzt der gesamte Source: (insgesamt rund 100 Zeilen)

using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace MDXTutorial01
{
	/// <summary>
	/// Zusammenfassung für Form1.
	/// </summary>
	public class MDXSampleApp : System.Windows.Forms.Form
	{
		private Device m_Device;


		// ctor
		// do nothing...
		public MDXSampleApp()
		{
			
		}

		// dtor
		// shutdown D3D
		 ~MDXSampleApp()
		{
			
			 
		}

		public void InitGfx()
		{
			try
			{
				this.ClientSize = new Size(1024,768);
				this.Text = "Direct3D Tutorial 1";

				this.KeyPress += new KeyPressEventHandler(OnKeyPress);

				PresentParameters pp = new PresentParameters();

				pp.Windowed = true;
				pp.SwapEffect = SwapEffect.Copy;
				
				m_Device = new Device(Manager.Adapters.Default.Adapter,DeviceType.Hardware,this,CreateFlags.HardwareVertexProcessing,
										pp);

			}
			catch(DirectXException e)
			{
				MessageBox.Show(e.Message);
			}
		}
		public void Render()
		{
			m_Device.Clear(ClearFlags.Target ,Color.Blue,0.0f,0);
			m_Device.BeginScene();
			m_Device.EndScene();
			m_Device.Present();

		}

		public void Shutdown()
		{
			m_Device.Dispose();
		}

		

	
		/// <summary>
		/// Der Haupteinstiegspunkt für die Anwendung.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			MDXSampleApp example = new MDXSampleApp();
			example.InitGfx();
			example.Show();

			while(example.Created)
			{
				example.Render();
				Application.DoEvents();
			}
			example.Shutdown();

		}

		private void OnKeyPress(object sender, KeyPressEventArgs e)
		{
			if((int)e.KeyChar == (int)Keys.Escape)	
				this.Close();
		}
	}
}

So, das wars. Im nächsten Teil werden wir genauer aufs Rendern und auch auf den Fullscreen Modus zum sprechen kommen.

Thema: [Hinweis] zur FAQ
Am im Forum: FAQ

Du befindest dich momentan im FAQ Forum von myCSHARP.de Hier findest du häufig gestellte Fragen zu verschiedenen Themenbereichen aus der .NET Welt.

Falls du eine Idee für einen FAQ Beitrag haben solltest, so schickt bitte eine PM an das myCSharp.de-Team (siehe Kontakt zum Team).

Danke!

PS: Poweruser könnten im Forum "FAQ" direkt Themen erstellen und antworten (siehe Gruppe Poweruser/Experten).

Thema: serielle Schnittstelle unter C# ansprechen
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Boardsuche.

Serielle Schnittstelle
Serielle Schnittstelle ansprechen/auslesen
Frage zu MS-SQL und serieller Schnittstelle

Da solltest du genug finden -.-

Thema: DirectX: Tutorial
Am im Forum: Grafik und Sound

Der Indexbuffer - Indizieren von Vertices

Diesmal sehen wir uns den sogenannten Indexbuffer an. Indexbuffer sind dazu da um Vertices zu reduzieren.
Bei einer Indizierung fallen nämlich doppelte Vertices weg und man kann so einen Vertexbuffer deutlich optimieren.
Nehmen wir an wir wollen zwei Dreiecke zeichnen. Grafisch würde das so aussehen:
1 2|4


0|3 5

Die Nummern geben dabei die einzelnen Vertices an. Für dieses Beispiel bräuchten wir also 6 Vertices in einem
Vertexbuffer. Jedoch fällt uns auf das zwei Vertices mit den selben Koordinaten zweimal im Vertexbuffer stehen.
Ist das nicht sinnloser Verbrauch von Speicherplatz? Deshalb erstellt man nun einen Indexbuffer in dem man
speichert, an welcher Position welcher Vertex ist. (sry, aber ihr solltet den Beitrag quoten oder die im zip beiliegende Tutorial.txt ansehen, dort wird die Tabelle richtig dargestellt -.- )
Index Wert Vertex
0 0 (x0,y0)
1 1 (x1,y1)
2 2 (x2,y2)
3 0 (x0,y0)
4 2 (x2,y2)
5 5 (x5,y5)

Wie wir in der Tabelle sehen müssen wir nur mehr 4 verschiedene Vertices speichern, nicht mehr 6 verschiedene.
In diesem Beispiel mag das nicht als viel erscheinen, aber wenn man große Objekte hat, kann man mit Indexbuffer
viel einsparen und sehr gut optimieren. Zu beachten ist aber, dass man jedoch 6 Indices braucht. In DirectX SDK
Hilfe wird übrigens empfohlen nur mit indizierten Vertices zu arbeiten. Und nun können wir bereits zu Praxis
kommen. Direct3D stellt uns die Klasse IndexBuffer zur Verfügung, um einen IndexBuffer zu erstellen. Wir werden
jedoch nicht direkt mit dem Indexbuffer arbeiten sondern verwenden ein Mesh Objekt. Ein Mesh Objekt ist einfach
eine Klasse die das Arbeiten mit Vertexdaten vereinfacht.


Mesh Object;

Sehen wir uns nun die OnCreateDevice Funktion an. Hier erstellen wir zuerst 4 Vertices, danach 6 Indices und
speichern diese im Mesh Objekt:

		public void OnCreateDevice(object sender, EventArgs e)
		{
			Device dev = (Device)sender;

			CustomVertex.PositionOnly[] verts = { 			
										new CustomVertex.PositionOnly(-1f,  0f, -1f),
										new CustomVertex.PositionOnly( 1f,  0f, -1f),
										new CustomVertex.PositionOnly( 1f,  0f,  1f),
										new CustomVertex.PositionOnly(-1f,  0f,  1f),
			};

			short[] indices = { 0,1,2,		// erstes Dreieck
								  0,2,3 };	// zweites Dreieck

Dieser Code bietet uns keine Probleme. Wir verwenden short Indices aus Speicherplatzgründen, da wird ja nur kleine
Werte brauchen(von 0 bis 3) und so müssen wir auf dem RAM der Grafikkarte pro Index nur 2 Bytes verwenden anstatt
4 Byte wie bei int. Die Zahlen im indices Array weisen auf die Vertices hin, die beim Zeichnen verwendet werden.
Für das erste Dreieck verwenden wir die Vertices 0, 1 und 2. Fürs zweite 0, 2 und 3.

Object = new Mesh(indices.Length / 3,verts.Length,MeshFlags.WriteOnly,CustomVertex.PositionOnly.Format,
							  device);

			Object.VertexBuffer.SetData(verts,0,LockFlags.None);
			Object.IndexBuffer.SetData(indices,0,LockFlags.None);

		}

Hier erstellen wir ein neues Mesh Objekt und setzen die VertexBuffer und IndexBuffer Werte dafür. Die Parameter
des Mesh Konstruktors sind einfach:
Der erste Parameter gibt die Anzahl der Flächen eines Objektes an. Wir brauchen logischerweise 2 Flächen. Einmal
fürs erste Dreieck und einmal fürs Zweite.
Der zweite Paramter gibt dann die Anzahl der Vertices an. Der Dritte gibt sogenannte MeshFlags an. Diese können
dazu verwendet werden der Klasse gewisse Informationen zu geben, wie sie die Daten behandeln soll. Wir wollen nur
Daten in das Mesh Objekt schreiben, jedoch keine herauslesen. Dazu geben wir MeshFalgs.WriteOnly an. Das nächste
ist das Format der Vertexdaten. Der letzte Parameter gibt dann schließlich das Device an.
Danach greifen wir direkt auf den VertexBuffer und den IndexBuffer zu und setzen die Daten mit SetData.
Nun können wir auch schon zur Renderfunktion kommen.
Diese ist diesmal auch ganz einfach:

			device.Clear(ClearFlags.Target , System.Drawing.Color.Blue, 1.0f, 0);
			
			device.BeginScene();

			device.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 3.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) );
			device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );

			device.Transform.World = Matrix.Identity;
			
			device.RenderState.CullMode = Cull.Clockwise;
			Object.DrawSubset(0);

			device.EndScene();
			device.Present();

Der Code bietet eigentlich nur vertraute Dinge -.-

Was ist jetzt jedoch wenn wir direkt aus einem VertexBuffer und einem IndexBuffer heraus rendern wollen? Dazu
können wir die Funktion DrawIndexedPrimitives verwenden (oder DrawIndexedUserPrimitives wenn wir ohne Vertexbuffer
arbeiten wollen). Doch um diese Funktion müssen wir uns erstmal nicht kümmern, da uns ja die Mesh Klasse die
meiste Arbeit abnimmt.

Wie immer gibt es das gesamte Visual Studio 2003 .net Projekt als zip zum Download.(achtung, ich verwende immer jeweils das neueste SDK dh für diese Version braucht ihr das April Update des SDKs, ich glaube aber das es mit älteren Ausgaben des SDK auch funktionieren sollte)

Thema: .exe herstellen, die kein .NET Framework benötigt
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hi!

von Microsoft gibt es einen Setup Bootstrapper. Damit kannst du zu einem Windows Installer das .net Framework hinzufügen:
http://www.microsoft.com/downloads/details.aspx?familyid=66350891-d15b-446b-bd69-f7f849224a00&displaylang=en
http://support.microsoft.com/default.aspx?scid=kb;en-us;836158


Dann gibt es noch Thinstall: http://thinstall.com/help/index.html?linking_netframework.htm
Das analysiert deine Anwendung und linkt alle benötigen Assemblies zu deinem Programm hinzu. Dadurch wird das Programm größer, aber du brauchst das .net Framework nicht installieren

Thema: Wie gehts nun weiter mit C#
Am im Forum: Smalltalk

Zitat
Original von Rene Paschold
Ach echt, das war ein Aprilscherz ??????

Hmm ich habe jetzt aber schon zwei Java Bücher bestellt .. *grummel*

und ich hab mich grad bei der NASA für die Entwicklung des Mars Rover beworben -.-

Thema: [Aprilscherz] Bye Bye C# - Hello Java! / von myCSHARP.de zu myJAVA.de
Am im Forum: Ankündigungen

Ich darf mal kurz Leon Chism zitieren:

Zitat
"If you look at where Java is in the industry and marketplace, it's everywhere"

Und genau deswegen, Java ist überall. War .net schonmal am Mars? Java ist besser, schneller, einfacher als .net

Thema: .NET Assembly vor Disassemblern schützen
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Und wenn man gewisse Teile als Webservice implementiert und diese dann von seinem Programm aus aufruft? An den Code vom Webservice kommt man ja nicht so einfach ran.

Vorrausetzung ist halt Internetverbindung und ein eigener Server.

Thema: Raucht ihr? [Rauchen, Trinken, Ernährung, Sport]
Am im Forum: Smalltalk

Rauchen nein, Blutcolagehalt ist aber ziemlich hoch ^^
Und ich mach nur eine Kampfsportart. Ansonsten bin ich nicht soo sportlich(außer halt ski fahren usw.)

Thema: Optionale Parameter
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hi!

das ist die eigentlich Definiton, ja. Aber ich habe den Code etwas abgewandelt so das immer 91 herauskommt(indem ich zuerst jede Zahl > 101 auf < 101 bringe durch subtrahieren)

Thema: Optionale Parameter
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Noch nie was von der 91er Funktion gehört? IIRC heißt die auch McCarthy Funktion.
Definiert durch:
f(n) = 91
Man bekommt für jede beliebige Zahl 91 heraus(daher f91)