Terrain 101: Transformationen

Nachdem ich im letzten Teil meiner Artikelreihe „Terrain 101“ erklärt hatte, wie das erste Dreieck auf den Bildschirm gezaubert wird, möchte ich in diesem Teil nun erklären, wie dieses Wissen auszubauen ist, damit wir unserem Ziel näher kommen. Wir werden in diesem Artikel lernen, wie wir Geometrien und Meshes transformieren können (und müssen) und wozu die unterschiedlichen Koordinatensysteme da sind und warum diese überhaupt existieren. Ziel dieser Übung ist es, am Ende der Artikelreihe eine dreidimensionale Landschaft entwickeln zu können. Dabei möchte ich mich nicht nur auf eine winzig kleine Landschaft beschränken, wie dies in vielen anderen Tutorials gemacht wird, sondern ich möchte riesige, detaillierte Landschaften mit euch gemeinsam erschaffen, die soweit ausgebaut werden, daß man sie auch in einem Spiel verwenden kann.

Ich werde jeden Artikel – um die Navigation zu erleichtern – mit einer Art Inhaltsverzeichnis beginnen. Dieses wird alle Artikel der Reihe enthalten und so einfach ermöglichen, daß man in diesen Artikel navigiert und bestimmte Themen einfach überspringen kann. Das Inhaltsverzeichnis in den älteren Artikeln werde ich dann jeweils aktualisieren.

Das Inhaltsverzeichnis

Terrain 101: Eine Einführung in dreidimensionale Landschaften in Echtzeit
Terrain 101: Die Entwicklungsumgebung und das XNA 4.0 Projekt
Terrain 101: Das erste Dreieck
Terrain 101: Transformationen
Terrain 101: Vertex- und Index-Buffer
Terrain 101: Land in Sicht
Terrain 101: Technische Rafinessen
Terrain 101: Neue Sichtweisen
Terrain 101: Kamera ab und Action

Die Projektion

3D-Grafik ist eine Annäherung an die Wirklichkeit und versucht diese mehr oder weniger detailliert darzustellen. Dabei müssen ein paar Kompromisse eingegangen werden, sowohl in Qualität, als auch in Quantität. Bestimmte Dinge sind auf einem Computer einfach nicht möglich und um unser Ziel zu erreichen müssen wir in die Trickkiste greifen und ein wenig improvisieren.

Einer dieser Tricks ist die sogenannte Projektion. Diese ist notwendig, da unser Rechner bzw. besser gesagt unser Monitor keine dreidimensionalen Objekte darstellen kann. Kann er nicht? Wie könnte ich dann ein 3D-Spiel spielen? Es werden zwar 3D-Objekte dargestellt, aber natürlich nicht in echtem 3D. Irgendwie müssen wir die Objekte plattdrücken und dabei den Eindruck eines dreidimensionalen Raumes wahren. Und exakt das ist die Aufgabe der Projektion. Wir verändern die Koordinaten unserer Vertices so, daß diese nur noch zwei Dimensionen haben und dabei trotzdem ein Tiefeneindruck entsteht. Dies nennt man perspektivische Projektion.

Die perspektivische Projektion ist die Projektion, die wir praktisch immer verwenden werden, sozusagen der Standard für 3D-Grafik. Die Besonderheit dabei ist, daß Objekte die weiter weg sind kleiner erscheinen und Objekte die näher am Betrachter sind, größer erscheinen. Das ist das Geheimnis dieser Projektion. Mathematisch gesehen – auch wenn ich an dieser Stelle wieder nicht auf die genauen Hintergründe eingehen möchte – wird einfach eine spezielle Matrix auf jede 3D-Koordinate angewendet um diesen Effekt zu erzielen. Dies ist die sogenannte Projektions-Matrix.

Der aufmerksame Leser meines Blogs hat sicherlich vor wenigen Tagen bereits meinen Grundlagenartikel über die Matrix gelesen. Wer dies nicht getan hat: Dies ist der richtige Zeitpunkt es nachzuholen. Diesen Artikel hatte ich nämlich geschrieben, um in diesem Artikel ein wenig schneller voran zu kommen und dem etwas erfahreneren Leser nicht alles nochmal vorkauen zu müssen. Auch wird dieser Artikel dadurch nicht ganz so umfangreich.

Wir benötigen also eine Projektions-Matrix und erzeugen diese mit Hilfe des XNA-Frameworks mit einem einfachen Methodenaufruf. Zunächst deklarieren wir eine Member-Variable, in der wir unsere Matrix speichern können. Dies erfolgt wie immer direkt am Anfang der Klasse.

Matrix projectionMatrix;

Zu Erzeugung der Matrix verwenden wir die Methode CreatePerspectiveFieldOfView der Matrix-Struktur. Diese nette Methode nimmt uns die harte Arbeit ab und erzeugt die Projektions-Matrix für uns. Dafür müssen wir allerdings ein paar Parameter liefern und selbstverständlich auch die entsprechende Methode aufrufen. Dafür verwenden wir die Initialize-Methode aus der Game-Klasse, die nach dem einfügen der Methode wie folgt aussieht.

protected override void Initialize()
{
  projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1.0f, 1000.0f);

  base.Initialize();
}

Der erste Parameter ist das sogenannte FieldOfView. Dieser Parameter wird im Bogenmaß angegeben, also in Radians. Dies ist eine Winkelangabe, die man mittels MathHelper.ToRadians von „normalen“ Winkeln in Grad errechnen kann. Dieser Parameter bestimmt das sogenannte Gesichtsfeld. Je größer dieser Winkel gesetzt ist, desto breiter ist das Sichtfeld. MathHelper.PiOver4 ist hierbei eine Art Standardwert und ist mit einem Winkel von 45° gleichzusetzen.

Der zweite Parameter bestimmt das Verhältnis zwischen Höhe und Breite und wird AspectRatio genannt. Dieser Parameter muss zur jeweils angezeigten Auflösung passen, da sonst Verzerrungen auftreten, die ziemlich hässlich aussehen können. Wir können dieses Parameter einfach ausrechnen, indem wir die aktuelle Breite der gewünschten Auflösung durch deren Höhe dividieren. Natürlich können wir auch, wie ich es hier gemacht habe, die entsprechende Eigenschaft des aktuellen Viewports heranziehen.

Die letzten beiden Parameter sind die NearPlane und die FarPlane. Diese beiden Parameter sind hauptsächlich für das Culling interessant, auf das ich in einem späteren Artikel noch genauer eingehen werde. Wir legen mit diesen beiden Parametern einfach fest, wo der Sichtbereich beginnt (NearPlane) und wo dieser aufhört (FarPlane). Alles was näher an uns liegt, als die NearPlane wird nicht dargestellt, ebenso wie alles das weiter entfernt ist, als die FarPlane nicht angezeigt wird.

Damit haben wir unsere erste Projektionsmatrix erzeugt und den Sichtbereich festgelegt.


An dieser Stelle möchte ich noch kurz auf eine weitere Projektion eingehen, die hin und wieder benötigt wird. Wir werden diese zwar nicht für unser Terrain einsetzen, aber da ich ja auch ein paar Grundlagen erklären möchte, wird diese Projektion nicht verschwiegen. Ich spreche von der orthographischen Projektion.

Die orthographische Projektion macht im Grunde genommen das Gleiche wie die perspektivische Projektion, allerdings erscheinen Objekte, die weiter hinten sind, nicht kleiner. Da dies normalerweise zwar zu weniger realistischen Ergebnissen führt, erhöht dies jedoch oft die Übersicht in einer 3D-Szene, weshalb diese Projektion oft auch bei technischen Zeichnungen, Level-Editoren oder in 3D-Programmen eingesetzt wird. Auch hier möchte ich nicht näher auf die mathematischen Hintergründe eingehen, da diese nicht unbedingt erforderlich sind. Die beiden Screenshots – die ich übrigens mit Blender gemacht habe und die beide die gleiche Szene zeigen, lediglich die Projektion wurde verändert – zeigen den Unterschied ganz gut.

Übrigens setzt der SpriteBatch von XNA auch eine orthographische Projektion ein. Mehr zu diesem Thema findet ihr in meiner Artikelreihe SpriteBatch Magic. In diesem Fall macht das Sinn, da der SpriteBatch dazu da ist 2D-Grafiken darzustellen. Diese haben keine Tiefe und daher müssen auch Sprites, die weiter hinten liegen nicht kleiner sein. Die orthographische Projektion bietet sich daher an.

Festzuhalten ist jedenfalls, daß wir immer eine Projektions-Matrix benötigen, wenn wir mit dreidimensionaler Grafik arbeiten. Kurz und bündig beschrieben:

Die Projektions-Matrix überführt Koordinaten aus dem View-Space in den Screen-Space.

Es werden also aus 3D-Koordinaten 2D-Koordinaten gemacht und zwar genau die Koordinaten, die wir im vorherigen Artikel über das erste Dreieck manuell erzeugt haben.

Der View-Space

Die nächste wichtige Transformation bei dreidimensionalen Darstellung ist die sogenannte ViewMatrix, die wir auch direkt in unserem Programm einbauen werden. Dazu erzeugen wir wie bei der Projektionsmatrix eine Member-Variable, in der wir sie speichern können.

Matrix viewMatrix;

Wozu ist nun die View-Matrix notwendig?

Die View-Matrix überführt Koordinaten aus dem World-Space in den View-Space.

Was bedeutet dies nun und wofür benötigt man dies? Das ist relativ einfach zu erklären. Unsere 3D-Szene befindet sich im sogenannten World-Space und ist dort unabhängig vom Betrachter oder einer Kamera gespeichert. Was wir dort aber nicht gespeichert haben, ist die Blickrichtung aus der wir die Szene betrachten. Und das ist es, was die View-Matrix macht. Sie stellt im Grunde genommen eine Art virtuelle Kamera dar. Die Kamera ist lediglich virtuell, da eine echte Kamera nicht möglich ist. Der Monitor stellt schliesslich die Fläche und Richtung dar und der Monitor steht ja bekanntlich fest. Bleibt also nur folgende Möglichkeit: Die Szene hinter der Mattscheibe wird so bewegt, daß der Eindruck entsteht, daß wir eine Kamera hätten. Und bekanntlich – kennt ja jeder, der schon mal ein 3D Spiel gespielt hat – funktioniert dies absolut problemlos.

Auch hier bekommen wir wieder eine Menge Unterstützung vom XNA-Framework in Form von vorgefertigten Methoden zur Erzeugung dieser Matrix.

Die wichtigste Methode ist Matrix.CreateLookAt. Mit den drei Parametern dieser Methode erzeugen wir unsere View-Matrix und damit die virtuelle Kamera. Der erste Parameter gibt die Position unserer Kamera an, das zweite Argument ist der Punkt, den die Kamera betrachten soll. Gibt man hier z.B. bei jedem Update-Zyklus die Position der eigenen Spielfigur an, so folgt die Kamera der Spielfigur. Der letzte Paramter – der sogenannte Up-Vektor – bestimmt die Lage der Kamera in der Welt. Der Up-Vektor zeigt, wie der Name bereits andeutet, nach oben. Normalerweise zeigt in XNA die Y-Achse nach oben und somit muss dieser Vektor den Wert {0, 1, 0} haben. Dafür gibt es eine Abkürzung, nämlich die statische Eigenschaft Vector3.Up (diese und weitere praktische Eigenschaften findet ihr in der MSDN). Diese Variante ist besser lesbarer, schneller zu instanzieren und auch noch etwas weniger Schreibarbeit.

Nun geht es an das eigentliche Erzeugen der Matrix. Wie bereits beschrieben, ist dies sehr einfach möglich und erfolgt in diesem Fall direkt unter der Erzeugung der Projektions-Matrix.

viewMatrix = Matrix.CreateLookAt(new Vector3(2.0f, 2.0f, 2.0f), Vector3.Zero, Vector3.Up);

Dieser Code ist nicht weiter kompliziert und mit meinen Ausführungen in diesem Abschnitt und evtl. den Erklärungen in der MSDN sehr einfach zu verstehen.

Ein Satz noch zum Verständnis: Wenn wir eine dynamische Kamera erzeugen wollen, dann muss die View-Matrix immer dann neu erzeugt werden, wenn die virtuelle Kamera sich bewegt.

Der World-Space

Der World-Space ist eine Geschichte, die der Einsteiger oft vollkommen ignoriert bzw. falsch anwendet. In einer 3D-Szene sollte es nämlich nicht so sein, daß die ganzen Objekte so in der Welt positioniert werden, wie die Position es erfordert. Ich will damit sagen, daß die Vertex-Positionen, also die einzelnen Punkte des Meshes nicht direkt in der Welt positioniert werden. Es ist viel praktischer und vor allem viel wiederverwendbarer, wenn dies einfach um den Nullpunkt herum geschieht. Dies hat zum einen große Vorteile bei der Genauigkeit (Stichwort Fließkommagenauigkeit) und zum anderen können wir ein Objekt in mehreren Szenen verwenden, ohne es neu berechnen zu müssen. Und genau hier kommt die World-Matrix ins Spiel.

Die World-Matrix legt die Position, Rotation und Skalierung eines Objektes in der Welt fest und überführt das Objekt vom Object-Space in den World-Space.

Dies ist sehr einfach zu verstehen. Wir erzeugen z.B. einen sogenannten Unit-Cube. Dieser hat eine Kantenlänge von 1.0f in alle Richtungen und das Zentrum des Würfels befindet sich exakt an Position {0.0f, 0.0f, 0.0f}. Eine Rotation ist auf keiner Achse vorhanden. Der Würfel befindet sich nun im Object-Space und kann den vollen Wertebereich und damit die volle Genauigkeit des Floats ausnutzen.

Mit der World-Matrix legen wir nun die tatsächliche Größe fest und die Position in der Welt.

Das XNA-Framework bietet zwar hier auch eine Hilfe, nämlich Matrix.CreateWorld, aber diese Methode mag ich nicht, da diese etwas eigenartige Parameter hat. Im Grunde genommen erzeugen wir einfach eine Skalierungsmatrix mit Matrix.CreateScale, eine Translationsmatrix mit Matrix.CreateTranslation und eine Rotationsmatrix mit Matrix.CreateFromYawPitchRoll (oder mit CreateFromAxisAngle, CreateFromQuaternion oder CreateRotationX/Y/Z). Diese kombinieren wir einfach in der richtigen Reihenfolge, so wie in „Die Matrix“ beschrieben und schon haben wir unsere World-Matrix.

Der große Vorteil dabei ist, daß wir nur die Elemente erzeugen müssen, die wir benötigen. Oft wird nur die Position des Objektes in der Welt verändert und daher müssen wir nur die Translationsmatrix erzeugen.

Um es etwas einfacher zu machen, verwenden wir in diesem Teil des Tutorials keine World-Matrix und stellen das Objekt einfach auf dem sogenannten Ursprung, also {0.0f, 0.0f, 0.0f} dar.

Der Vertex-Shader

Unser Vertex-Shader wird nun auch ein klein wenig komplizierter. Zunächst benötigen wir drei neue Parameter im Shader, damit wir unsere drei Matrizen übergeben können. Dies ist sehr einfach und wird am Anfang der Effekt-Datei vorgenommen.

float4x4 World;
float4x4 View;
float4x4 Projection;

In der eigentlichen Vertex-Shader-Position müssen wir nun die Koordinaten die wir als Eingabe erhalten mit diesen Matrizen transformieren und dann als Ergebnis zurückgeben. Daher ersetzen wir die bisherige, einfache Zuweisung output.Position = input.Position; im Vertex-Shader durch folgende Transformation.

float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);

Keine Angst, ich springe bewusst etwas schneller über den Vertex-Shader. Erstens befindet sich der gesamte Code nochmal am Ende dieses Artikels und zum zweiten mache ich an dieser Stelle diese Ausführung lediglich zum besseren Verständnis und da diese einfach notwendig sind. Ich werde in einem zusätzlichen Artikel noch näher auf den Vertex-Shader eingehen, dies jedoch losgelöst von dieser Artikelreihe, da man über dieses Thema viele Artikel schreiben kann. Diese findet ihr bzw. werdet ihr in der Kategorie Shader in meinem Blog finden.

Wer meinen bisherigen Ausführungen einigermaßen aufmerksam gefolgt ist, der sollte jedenfalls keine größeren Schwierigkeiten damit haben, diese drei neuen Zeilen zu verstehen. In der ersten wird das Objekt (dessen Vertices als Eingabeparameter dienen) vom Object- in den World-Space transformiert. In der zweiten Zeile wenden wir unsere Kamera darauf an und überführen die Koordinaten nun in den View-Space und zum Schluß führen wir noch die Projektion durch, damit die Vertices auch schön auf dem Bildschirm erscheinen.

Der letzte Schritt in diesem Tutorial ist, daß wir dem Shader natürlich noch mitteilen müssen, daß wir unsere Matrizen als Parameter übergeben. Dies nehmen wir in der Draw-Methode vor und setzen unmittelbar vor der Aktivierung des Shaders mit .Apply() unsere drei Parameter.

triangleEffect.Parameters["World"].SetValue(Matrix.Identity);
triangleEffect.Parameters["View"].SetValue(viewMatrix);
triangleEffect.Parameters["Projection"].SetValue(projectionMatrix);

Starten wir nun unser Projekt mit F5, dann sollten wir folgendes Bild sehen, unser erstes, transformiertes und dreidimensionales Dreieck.

Man erkennt jedenfalls gut, daß wir nun unser Dreieck nicht mehr platt von vorne betrachten, sondern das wir die Kamera von rechts oben auf das Objekt herunterschauen lassen. Sofort entsteht ein dreidimensionaler Eindruck und damit ist das Ziel dieses Teils der Artikelreihe Terrain 101 erreicht.

Zusammenfassung und Ausblick

In diesem Teil haben wir den Schritt aus der flachen, zweidimensionalen Welt des Screen-Space in die dreidimensionale und interessante Welt der 3D-Grafik gewagt. Wir haben unserem platten Dreieck aus dem letzten Teil ein wenig Tiefe spendiert und dieses im Raum gedreht. Wir können nun mit Projektionen umgehen, wissen wie man eine rudimentäre virtuelle Kamera definiert und was es mit dem Object- und World-Space auf sich hat.

Nachdem wir nun in diesem Teil die Grundlagen erarbeitet haben, werde ich im nächsten Teil darauf eingehen, wie wir ein paar mehr Polygone auf den Bildschirm zaubern können, da ein einzelnes Dreieck schnell langweilig werden dürfte. Wir werden uns dazu mit dem sogenannten Vertex-Buffer beschäftigen und weil es passt natürlich auch mit dem Index-Buffer. Um dies etwas interessanter zu gestalten, werden wir ab dem nächsten Teil bereits anfangen, die erste Geometrie unserer Landschaft zu erzeugen und es wird langsam sichtbar werden, wo die Reise hingeht.

Ich hoffe dieser doch recht lang gewordene Artikel war gut zu lesen und verständlich geschrieben. Anregungen und Fragen könnt ihr natürlich gerne mit der Kommentarfunktion los werden.

Da ich bereits im letzten Teil angedeutet habe, daß ich ab sofort immer ein paar Aufgaben stellen möchte um den engagierten Leser zu fordern, möchte ich auch in diesem Artikel nicht damit aufhören und die Aufgaben für den Leser damit zu einer Tradition machen. Im Anschluss daran findet ihr noch den kompletten Sourcecode des C#-Codes und des HLSL-Effekts.

Aufgaben für den Leser

In diesem Bereich möchte ich den Leser dazu ermutigen, sich ein wenig mit dem hier vermittelten Wissen zu beschäftigen und dieses auszubauen. Diese Aufgaben sind optional, aber sehr gut dazu geeignet das Erlernte zu festigen. Probleme diesbezüglich können in den Kommentaren natürlich gerne diskutiert werden.

  • Spiele mit der Kamera und zeige das Dreieck von links unten
  • Erzeuge eine World-Matrix für das Dreieck und rotiere es
  • Erzeuge eine orthographische Projektion und erforsche die Unterschiede zur perspektivischen Projektion
  • Animiere die Kamera und bewege diese von links nach rechts

Der gesamte Sourcecode dieses Artikels

Wie auch schon im letzten Teil möchte ich durch eine zusammenhängende Darstellung des Quellcodes den Überblick erhöhen. Daher liste ich hier nochmal den gesamten Quellcode aus diesem Artikel auf.

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Terrain_101
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Effect triangleEffect;
        VertexPositionColor[] vertices;

        Matrix projectionMatrix;
        Matrix viewMatrix;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1.0f, 1000.0f);
            viewMatrix = Matrix.CreateLookAt(new Vector3(2.0f, 2.0f, 2.0f), Vector3.Zero, Vector3.Up);

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            triangleEffect = Content.Load<Effect>("Triangle");

            vertices = new VertexPositionColor[] { new VertexPositionColor(new Vector3( 0.0f,  0.5f, 0.0f), Color.Red),
                                                   new VertexPositionColor(new Vector3( 0.5f, -0.5f, 0.0f), Color.Green),
                                                   new VertexPositionColor(new Vector3(-0.5f, -0.5f, 0.0f), Color.Blue),
                                                 };
        }

        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            triangleEffect.Parameters["World"].SetValue(Matrix.Identity);
            triangleEffect.Parameters["View"].SetValue(viewMatrix);
            triangleEffect.Parameters["Projection"].SetValue(projectionMatrix);

            triangleEffect.CurrentTechnique.Passes[0].Apply();
            GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, vertices, 0, 1);

            base.Draw(gameTime);
        }
    }
}

Das Effekt-File sieht mittlerweile wie folgt aus.

float4x4 World;
float4x4 View;
float4x4 Projection;

struct VertexShaderInput
{
    float4 Position : POSITION0;
	float4 Color    : COLOR0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
	float4 Color    : COLOR0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
	output.Color = input.Color;

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    return input.Color;
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

Veröffentlicht am 09.07.2011 in 3D Terrain, Tutorial, XNA, XNA 4.0 und mit , , , , , , , , , , , getaggt. Setze ein Lesezeichen auf den Permalink. 17 Kommentare.

  1. Super Tutorial!!

    nur leider stellt sich der Quellcode falsch dar und man sieht nur einen Teil des Codes.
    Ich kann dir auch germe Screenshots schicken aber im Firefox sieht das leider so aus.

    • Erstmal danke… Freut mich, daß dir das Tutorial bisher gefällt 🙂

      Hmmm, eigenartig mit dem Quellcode. Ich habe bisher nur mit dem IE 7,8,9 und einigen Chrome-Versionen getestet. Ich hoste den Blog aber auch nicht selber, sondern der kommt direkt von WordPress… Sollte also grundsätzlich alles klappen.

      Kannst du denn wenigstens auf den „Copy“-Button für den Quellcode klicken?

  2. Ich habe ein Problem:
    Ich habe Visual Studio 2010 pro und kann unter „Vorhandesnes Element hinzufügen“ keine Effectfile finden. Dort kann ich nur Klassen und Codedateien hinzufügen, allerdings gibt es keinen Eintrag „Effect-File“. Soll ich dann einfach eine Codedatei nehmen oder wie?

    • Das deutet darauf hin, dass das „Windows Phone Developer SDK“ nicht korrekt in Visual Studio registriert wurde. Wurde die Express-Variante von Visual Studio installiert? Damit sollte es in jedem Fall gehen. Eine normale Code-Datei nützt dir nichts, da diese von der Content-Pipeline nicht, oder nicht richtig erkannt werden wird.

      • Hi, srry das war mein Fehler^^.
        Unter Visual Basic werden irgendwie 2 Projekte angelegt.
        Einmal war es WindowsGame3 und einmal WindowsGame3Content^^
        Ich hatte es versucht in das falsche einzufügen, da ich nicht wusste das das auch eine „Art Content“ ist.
        Habe das jetzt auch hinbekommen mit der fx-Datei, aber irgendwie habe ich jetzt ein komisches Problem:
        Immer, egal welchen Namen ich bei Loadcontent eingebe kommt „Datei nicht gefunden“
        Da kam noch nie, wieso zeigt der das an? Die Datei existiert doch

  3. nachdem ich den Gesammten code aus dem Projekt in ein neues kopiert habe, ging es auf einmal mit dem Laden.
    Ich habe allerdings ein weiteres Problem in der „SetupFirstChunk()“-Sub
    Ich habe allerdings deinen Code in Visual Basic umgeschrieben, ich denke das ich da irgendwo einen Fehler gemacht habe. Denn: In der letzten Zeile (also:
    Me.indexBuffer.SetData(Of Integer)(indices)
    Kommt folgender Fehler:
    Das Array hat nicht die richtige Größe für die Menge der angeforderten Daten.
    Hier mein gesammter Code aus der sub:

    Private Sub SetupFirstChunk()

    Dim heights As Color() = New Color(heightmap.Width * heightmap.Height – 1) {}
    heightmap.GetData(Of Color)(heights)

    Dim vertices As VertexPositionColor() = New VertexPositionColor(128 * 128 – 1) {}
    Dim index As Integer = 0

    For z As Integer = 0 To 128 – 1
    For x As Integer = 0 To 128 – 1
    vertices(z * 128 + x) = New VertexPositionColor(New Vector3(x * 10.0F, heights(z * 128 + x).R, z * 10.0F), Color.Green)
    Next
    Next

    Me.vertexBuffer = New VertexBuffer(GraphicsDevice, GetType(VertexPositionColor), 128 * 128, BufferUsage.[WriteOnly])
    Me.vertexBuffer.SetData(Of VertexPositionColor)(vertices)

    Dim indices As Integer() = New Integer(127 * 127 * 6 – 1) {}
    index = 0

    For z As Integer = 0 To 127 – 1

    For x As Integer = 0 To 127 – 1

    indices(index + 0) = z * 128 + x
    indices(index + 1) = indices(index + 0) + 128 + 1
    indices(index + 2) = indices(index + 0) + 128
    indices(index + 3) = indices(index + 0)
    indices(index + 4) = indices(index + 0) + 1
    indices(index + 5) = indices(index + 0) + 128 + 1

    index += 6
    Next
    Next

    Me.indexBuffer = New IndexBuffer(GraphicsDevice, IndexElementSize.SixteenBits, 127 * 127 * 6, BufferUsage.[WriteOnly])

    Me.indexBuffer.SetData(Of Integer)(indices)

    End Sub

    Kannst du da mal drübergucken?
    Danke dir 🙂
    Ach übrigens: Super Tutorials hier, relativ leicht verständlich, auch für nen noob wie mich hehe^^

  4. Eine Auflösung für die Übungen wäre voll cool 🙂 weil ich schaff die mit der info die heir geliefert wird nicht ganz 😦 danke im vorraus

  1. Pingback: Terrain 101: Das erste Dreieck « "Mit ohne Haare"

  2. Pingback: Terrain 101: Die Entwicklungsumgebung und das XNA 4.0 Projekt « "Mit ohne Haare"

  3. Pingback: Terrain 101: Vertex- und Index-Buffer « "Mit ohne Haare"

  4. Pingback: Terrain 101: Eine Einführung in dreidimensionale Landschaften in Echtzeit « "Mit ohne Haare"

  5. Pingback: XNA und Blender: SimpleCube « "Mit ohne Haare"

  6. Pingback: Terrain 101: Land in Sicht « "Mit ohne Haare"

  7. Pingback: Terrain 101: Technische Rafinessen « "Mit ohne Haare"

  8. Pingback: Terrain 101: Neue Sichtweisen « "Mit ohne Haare"

  9. Pingback: Terrain 101: Kamera ab und Action « "Mit ohne Haare"

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: