XNA und Blender: SimpleCube

Wer meinen Blog verfolgt, dem ist sicherlich aufgefallen, daß ich in letzter Zeit häufiger mit Blender gearbeitet habe. Dies liegt daran, daß ich von Blender seit der ersten stabilen Beta-Version 2.5x ziemlich überzeugt bin. In das „alte“ Blender konnte ich mich – genau wie viele andere – einfach nicht richtig einarbeiten, da die Benutzeroberfläche nicht besonders zugänglich ist. Dies hat sich mit der neuen Version grundlegend geändert. Es ist immer noch nicht einfach sich in ein so komplexes Programm einzuarbeiten, aber es macht nun deutlich mehr Spaß und die Einstiegshürde ist sehr viel kleiner geworden.

Da Blender kostenlos ist, bietet es sich für den Hobby- und Indie-Entwickler natürlich besonders an, da ja nicht jeder einen so dicken Geldbeutel hat, daß er sich 3D-Studio max, Maya oder Cinema 4D leisten kann.

In diesem Artikel und vielleicht sogar noch in Folgeartikeln möchte ich euch das Zusammenspiel von Blender und XNA 4.0 näher bringen. In diesem ersten Artikel fangen wir ganz einfach an. Wir werden uns nicht großartig mit Modellieren und auch nicht großartig mit Programmieren aufhalten und einige der notwendigen Grundlagen werde ich schlicht und einfach nur als Links auf andere meiner Tutorials bereitstellen.

Genug vom Vorgeplänkel, los geht es…

Grundvoraussetzungen

Für dieses Tutorial benötigen wir XNA 4.0 und Visual Studio 2010 (oder besser), daß im Windows Phone SDK enthalten ist. Achtet bitte darauf, daß ihr das vollständige Paket runterladet und installiert. Dabei bitte beachten, daß ihr die Beta-Versionen, die auf der verlinkten Seite angeboten werden nur dann installieren solltet, wenn ihr wisst, wofür ihr die braucht. Im Zweifelsfall sollte immer auf eine Stable-Version zurückgegriffen werden.

Wer noch WindowsXP verwendet, der kann das Paket „XNA Game Studio 4.0“ herunterladen. Für Windows Vista und 7 Anwender rate ich davon ausdrücklich ab.

Achtet bitte auch darauf, daß ihr die passenden Aktualisierungen bzw. Service Packs installiert. Zum aktuellen Zeitpunkt ist dies das „Windows Phone Developer Tools January 2011 Update“. Dieses ist auf der gleichen Seite verfügbar und verlinkt.

Wie schon im Vorwort und im Titel dieses Artikels angemerkt, verwenden wir Blender aus der 2.5-Reihe, die derzeit aktuell ist. Ich beziehe mich in diesem Artikel auf die heute erschienene Version 2.59, die wahrscheinlich die letzte stabile Version aus der Reihe sein wird. Die Entwickler beginnen gerade damit, den 2.6er Zweig von Blender zu entwickeln. In diesem wird es einige ziemlich interessante Neuerungen geben, eine stabile Version wird aber noch einige Monate auf sich warten lassen.

Soviel zu den Voraussetzungen. Alles notwendige sollte nun installiert sein und wir können loslegen.

Erstellen des Modells in Blender

Dieser Artikel soll kein Blender-Tutorial sein, daher werden wir uns für den Anfang auf eine ganz einfache Szene konzentrieren. Ein simpler Würfel. Dieser wird von Blender bei Programmstart als Standard bereitgestellt. Das Modellieren beschränkt sich also in diesem ersten Artikel schlicht und einfach darauf, daß wir Blender starten.

XNA und Blender Tutorial: Blender Programmstart

XNA und Blender Tutorial: Blender Programmstart

In Blender 2.59 wurde im Exporter für .FBX-Dateien, die wir hier verwenden werden, einige Verbesserungen in Sachen XNA vorgenommen. Es gibt einen sogenannten „XNA Strict Options“ Modus der eine verbesserte Kompatibilität bietet.

XNA und Blender Tutorial: FBX-Export MenüpunktExportieren wir also unseren Würfel, um ihn in XNA weiter zu verwenden. Dazu muss dieser markiert sein (rechte Maustaste im Objekt-Modus). Standardmäßig ist dieser bereits markiert, was durch den orangen Rahmen symbolisiert wird. Der Export ist sehr einfach: Wir wählen einfach den Menüpunkt File/Export/Autodesk FBX, wie im nebenstehenden Screenshort dargestellt.

Es öffnet sich ein Datei-Dialog, in dem wir den Dateinamen festlegen können und ein passendes Verzeichnis auswählen können. Im linken unteren Bereich können wir ein paar Einstellungen vornehmen. Auch davon habe ich einen Screenshot erstellt. Wichtig sind eigentlich momentan nur zwei Punkte. Zunächst muss der Punkt „Selected Objects“ ausgewählt sein. Dies bewirkt, daß nur markierte Objekte der Szene exportiert werden und so später der einzige Mesh in unserem Model in XNA sein wird. Da wir nur den Default-Würfel markiert haben, ist dies auch exakt das, was wir bewirken wollen.


Der zweite wichtige Punkt ist „XNA Strict Options“. Dieser nimmt ein paar Einstellungen vor, die eine Art Kompatibilitätsmodus speziell für XNA aktivieren. Nachdem man diesen Punkt ausgewählt hat, sollte man die Optionen nicht mehr verändern, denn sonst werden unter Umständen vorgenomme Einstellungen zurückgesetzt.

Rechts oben klicken wir nun auf „Export FBX“ und unser erstes Modell ist exportiert. Im Grunde genommen haben wir nun einen Index- und Vertex-Buffer erzeugt, der im FBX-Format auf der Festplatte liegt. Was ein Index- und Vertex-Buffer ist, erkläre ich im Artikel Terrain 101: Vertex- und Index-Buffer.

Darstellung in XNA

Im nächsten Schritt wollen wir nun dieses Objekt in XNA rendern.

XNA ist – zumindest für einfachere Dinge – eine extrem große Hilfe. Wie ihr in den nächsten paar Minuten sehen werdet, ist es extrem einfach, ein Objekt in XNA zu rendern. Dazu starten wir nun zunächst unser Visual Studio 2010, daß wir entweder eben installiert haben, oder schon vorher installiert hatten. Über den Menüpunkt Datei/Neu/Projekt erzeugen wir ein neues Projekt. In diesem Fall wählen wir in der Dialogbox, die daraufhin erscheint: „Windows Game (4.0)“ aus.

Wir nennen das Projekt „SimpleCube“.

Danach erscheint im Projektmappen-Explorer eine sogenannte Solution oder Projektmappe. Dies ist eine Zusammenfassung von mehreren Projekten. In unserem Beispiel haben wir nun zwei Projekte: Das erste ist das eigentliche Programm. In diesem werden wir programmieren, Klassen erzeugen und alles machen was notwendig ist um tolle Spiele zu entwickeln. Das zweite ist das sogenannte Content-Projekt. Im Content-Projekt werden wir Content hinzufügen. Das ist z.B. unser 3D-Modell, aber auch Texturen, Schriftarten, Musik und Soundeffekte. Näheres zur Content-Pipeline findest du in meinem Artikel: Die Content-Pipeline: Grundlagen.

Im Screenshot sind schon die beiden Modelle enthalten, die wir am Ende dieses Tutorials in unserem Projekt haben werden. Im gerade erstellen sind jedoch noch keinerlei Dateien enthalten. Daher fügen wir nun eine Datei hinzu: Rechte Maustaste auf das Content-Projekt und Hinzufügen/Vorhandenes Element auswählen. Wir suchen dann unsere zuvor exportierte .FBX-Datei mit unserem Würfel-Model und fügen diese so zum Content-Projekt hinzu. Das war es auch schon in diesem Teil mit dem Content-Projekt.

Fangen wir nun mit dem zugegebenermaßen recht überschaubaren Code an. Keine Angst, ich werde am Ende dieses Tutorials nochmals den gesamten Code in einem Stück präsentieren, damit die Übersicht gewahrt bleibt.

Als erstes definieren wir ein paar Member-Variablen, die wir im weiteren Verlauf benötigen werden. Dies sind im einzelnen folgende und wir definieren diese im Kopf der Game-Klasse direkt nach der Definition des SpriteBatch.

        Model cubeModel;

        Matrix worldMatrix;
        Matrix viewMatrix;
        Matrix projectionMatrix;

Die erste Variable enthält später unser Würfel-Model, die restlichen drei Variablen sind Matrizen und enthalten die World-Matrix, die View-Matrix und die Projection-Matrix. Wozu diese sind und was die Hintergründe sind, habe ich bereits in einem anderen Tutorial erklärt. Näheres findet man dazu im Artikel Terrain 101: Transformationen.

Weiter geht es in der LoadContent-Methode der Game-Klasse, die unmittelbar nach der Initalisierung des GraphicsDevice aufgerufen wird. Dort erzeugen wir unsere Matrizen und laden unser Modell.

            // setup the matrices
            this.worldMatrix = Matrix.Identity;
            this.viewMatrix = Matrix.CreateLookAt(new Vector3(5.0f, 5.0f, 5.0f), new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up);
            this.projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1.0f, 100.0f);

            // Load and setup the model
            this.cubeModel = Content.Load("cube");
            foreach (ModelMesh m in this.cubeModel.Meshes)
            {
                foreach (BasicEffect e in m.Effects)
                {
                    e.EnableDefaultLighting();
                }
            }

Dieser Code bedient sich einiger Methoden aus dem XNA-Framework zur Erzeugung der Matrizen. Näheres dazu auch im Terrain 101 bzw. in der MSDN.

Danach laden wir das Model über die ContentPipeline. Wichtig ist hierbei, daß wir nur den Namen des Modells wie im Content-Projekt angeben, aber vollkommen ohne Endung. Die Endung bestimmt die Content-Pipeline selbständig. Um das geladene Modell anständig darzustellen, müssen wir noch den Effekt konfigurieren. Standardmäßig ist dies der BasicEffect und da wir es einfach halten wollen, behalten wir diesen auch bei. Wir schalten einfach das DefaultLighting ein, was mit der doppelt geschachtelten foreach-Schleife geschieht.

Warum benötigen wir nun die äussere Schleife? Ganz einfach: Ein Model kann mehrere Meshes haben. Ein Mesh ist ein Drahtgittermodell aus Vertices und Indices. Da jedes Mesh nur ein einziges Material haben kann, besteht ein Model durchaus aus mehreren Meshes. Diese Erklärung ist nicht ganz vollständig. Es gibt nämlich noch ModelMeshParts, aber dazu in einem späteren Tutorial mehr. Erstmal ist wichtig zu wissen, daß ein Model sozusagen Untermodelle enthalten kann, die jeweils Effecte haben. Mit der inneren Schleife greifen wir darauf zu und konfigurieren den BasicEffect.

Die Vorbereitungen sind abgeschlossen, nun geht es ans Rendern. Das geschieht in der Draw-Methode und ist in diesem einfachen Beispiel eine einzige Zeile, da für solch einfachen Anwendungsfälle das XNA-Framework wieder eine phantastische Hilfe ist. Die folgende Zeile fügen wir direkt nach dem Löschen des Bildschirms mit GraphicsDevice.Clear ein.

this.cubeModel.Draw(this.worldMatrix, this.viewMatrix, this.projectionMatrix);

Drücken wir nun F5 zum kompilieren und starten, erhalten wir folgende Ausgabe.

Dies ist eindeutig ein Würfel, aber irgendwie sieht der nicht wirklich richtig aus. Irgendwas stimmt mit dem Shading anscheinend nicht. Warum dies so ist, dazu kommen wir nun.

Shading und Normals

Das Problem was wir haben ist das sogenannte Shading. Dieses interpoliert Farbwerte über die einzelnen Flächen anhand der angrenzenden Normalen. Dazu erstmal ein kleines Bild aus Blender, in dem die Normalen unseres Würfels blau dargestellt sind.

In diesem Screenshot erkennen wir, daß jeder Vertex unseres Würfels eine Normale hat, die senkrecht auf dem Vertex steht. Da die Normale aber von mehreren angrenzenden Seiten des Würfels verwendet wird, da auch mehrere Dreiecke, aus denen diese Seiten bestehen sich einen der Eck-Vertices teilen, stehen diese nicht senkrecht auf den Flächen, wie wir das für schöne, harte Kanten benötigen würden. Die Normale ist der Mittelwert aus den Normalen, die die Vertices der angrenzenden Kanten hätten. Die Kanten werden dadruch „weich“ dargestellt, was zum eigenartig aussehenden Shading führt. Dies kann durchaus erwünscht sein und bei einer Kugel oder Objekten mit weichen Kanten gut aussehen, bei unserem Würfel wollen wir aber scharfe Kanten.

Wir müssten also eine Möglichkeit finden, wie wir für jede Fläche Normalen hinbekommen, die senkrecht auf der Fläche stehen und nicht von den anderen Seiten beeinflusst werden, so wie dies im folgenden Screenshot zu erkennen ist. Da jeder Vertex nur eine Normale hat, brauchen wir also für jede Seite einzelne Vertices. Dies bedeutet, daß an jeder Ecke drei Vertices existieren, die exakt übereinander liegen. Es sind genau drei Vertices, weil wir für jede angrenzende Seite der Ecke einen eigenen Vertex benötigen. Insgesamt benötigen wir also für unseren Würfel 24 anstatt 8 Vertices. Wenn wir nun die Normalen berechnen, dann entsteht daraus folgendes Bild.

Wie bekommen wir das nun hin? Dazu müssen wir erneut Blender starten und unseren Würfel bearbeiten.

Wir haben dazu zwei Möglichkeiten. Die erste Möglichkeit ist die einfachere, aber auch weniger mächtige. Es ist der sogenannte Edge-Split-Modifier. Der Vorteil ist, daß dieser automatisch arbeitet und auch nicht unser Objekt zerstört. Modifier werden zwar auf das Objekt angewendet, können aber jederzeit wieder entfernt werden.

Diese Modifier finden wir im rechten Bereich, direkt unter der Baumansicht des Szene. Zur Orientierung steht links ein entsprechender Screenshot bereit. Wir wählen einfach den Modifier-Reiter und fügen über das Drop-Down einen neuen Edge-Split-Modifier hinzu. Dieser ist auch sofort korrekt konfiguriert.

Im Grunde genommen schneidet der Edge-Split-Modifier das Modell an bestimmten Stellen auseinander und zwar, wie der Name bereits aussagt, an den Kanten. Bei unserem Würfel sind dies exakt vier Kanten je Seite und würde dazu führen, daß wir 6 freigestellte Seitenflächen haben. Doch wie entscheidet der Modifier, welche Kanten geschnitten werden sollen? In der Standardeinstellung geschieht dies über den „Edge Angle“ von 30°, also dem Winkel der beiden angrenzenden Flächen. Ist dieser Winkel größer als 30°, so wird die Kante geteilt. Liegt er darunter, wird sie nicht geteilt. Die zweite Einstellung nennt sich „Sharp Edges“. Dies bedeutet schlicht und einfach, daß alle als scharf markierten Kanten geteilt werden.

Wie kann ich nun eine Kante als scharf markieren? Ganz einfach. Objekt auswählen (rechte Maustaste), Tabulator-Taste um in den Edit-Modus für das Objekt zu gehen. Strg-Tabulator drücken und Edge auswählen. Nun befinden wir uns im Auswahlmodus für Kanten. Wir wählen nun mit der rechten Maustaste (Shift festhalten um mehrere zu wählen) die Kante aus, die scharf gemacht werden soll. Danach wählen wir im Menü unterhalb des 3D-Viewports Mesh/Edges/Mark Sharp aus. Alternativ können wir auch die Leertaste drücken und danach „Mark Sharp“ eintippen. Die Kante wird nun rot und ist damit als scharf markiert.

Der zweite Weg, um die Seiten freizustellen ist destruktiv. Das Modell wird dazu also verändert. Dieser Weg ist auch nicht schwierig. Wir gehen wieder in den Edit-Mode und dann in den Face-Select Modus (Strg-Tab, Face). Wir drücken sooft auf A, bis alle Flächen deselektiert sind (also nicht mehr gelb sind). Wir wählen nun mit der rechten Maustaste eine Fläche, die freigestellt werden soll und drücken Y. Dieser Befehl bedeutet „Split“. Die Fläche wird einfach abgetrennt. Ein anderer Weg wäre P zu drücken. Dann würde die Fläche jedoch in ein eigenständiges Objekt separiert, was in XNA zu Performance-Problemen führt.

Unser so vorbereitetes Modell exportieren wir nun auf die Art und Weise, wie ich es zuvor bereits beschrieben hatte. Wir verwenden diesmal als Namen „cubeEdgeSplit“, wie dies schon im Screenshot des Content-Projektes sichtbar war. Um diesen Zustand herzustellen, fügen wir diese neue FBX-Datei auch unserem Projekt hinzu.

Um dieses Modell zu verwenden, müssen wir den Namen in der LoadContent-Methode entsprechend anpassen. Sobald wir dies gemacht haben, können wir das Ergebnis durch drücken von F5 bewundern.

Wunderschöne scharfe Kanten…

Abschluss

In diesem Artikel haben wir eine Menge gelernt und festegestellt, daß für Standardaufgaben XNA und seine Content-Pipeline ein extrem mächtiges Werkzeug sind. Mit wenigen Mausklicks und wenigen Zeilen Code haben wir ein 3D-Objekt aus Blender importiert und mit XNA in Echtzeit gerendert. Mit Hilfe der verlinkten anderen Artikel von mir, haben wir ein paar wichtige Grundlagen gelernt und wenn wir die ersten fünf Teile des Terrain 101 durcharbeiten, dann sind wir sogar in der Lage, diesen Würfel zu drehen, zu skalieren und zu positionieren und könnten so bereits einfache Animationen erzeugen.

Es gibt zwar noch keine konkrete Planung und die Leser der Reihe Terrain 101 erwarten auch die nächsten Artikel, aber ich werde trotzdem nach und nach noch weitere Teile auf dieses Grundlagen-Tutorial folgen lassen. Im nächsten Teil werde ich auf Texturen und Texturkoordinaten eingehen und erklären, wie man so die Oberflächen von Objekten etwas realistischer gestalten kann.

Weitere Themen, die ich wahrscheinlich in weiteren Teilen behandeln werde:

  • Details backen (Lightmaps, Schatten, Licht, Ambient Occlusion)
  • Erzeugung von Normal-Maps und Verwendung in XNA
  • Animationen
  • Optimierung der Modellstruktur
  • Vorbereitungen für Physik

Wie ihr seht: genügend Material für weitere Tutorials in einem doch recht komplexen Thema.

Der gesamte Sourcecode

Zum Abschluss noch mal der gesamte Source-Code der Game-Klasse aus Visual Studio zur besseren Übersicht.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace SimpleCube
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Model cubeModel;

        Matrix worldMatrix;
        Matrix viewMatrix;
        Matrix projectionMatrix;

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

        protected override void Initialize()
        {
            this.Window.Title = "XNA und Blender: SimpleCube - Tutorial #01";

            base.Initialize();
        }

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

            // setup the matrices
            this.worldMatrix = Matrix.Identity;
            this.viewMatrix = Matrix.CreateLookAt(new Vector3(5.0f, 5.0f, 5.0f), new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up);
            this.projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1.0f, 100.0f);

            // Load and setup the model
            this.cubeModel = Content.Load<Model>("cubeSharpEdges");
            foreach (ModelMesh m in this.cubeModel.Meshes)
            {
                foreach (BasicEffect e in m.Effects)
                {
                    e.EnableDefaultLighting();
                }
            }
        }

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

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

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

            this.cubeModel.Draw(this.worldMatrix, this.viewMatrix, this.projectionMatrix);

            base.Draw(gameTime);
        }
    }
}
Advertisements

Veröffentlicht am 13.08.2011 in 3D, Blender, Grundlagen, Tutorial, Windows Phone, XBox360, XNA, XNA 4.0 und mit , , , , , getaggt. Setze ein Lesezeichen auf den Permalink. 10 Kommentare.

  1. Oh ja freue mich auf den Details backen Artikel!!

  2. Und ich freue mich auf alle Artikel 😛
    Aber insbesondere auf den Animation Artikel..

  3. Ohja, Animationen würden mich auch brennend interessieren 🙂

  4. Ein super Artikel! Hat mir enorm geholfen, dass was ich in anderen Tutorials zu diesem Thema gelesen habe, in Gedanken zu sortieren und letztendlich auf meinen eigenen Code zu übertragen! Freue mich auf die angekündigten Artikel!

  5. Eine Frage, warum
    „Wer noch WindowsXP verwendet, der kann das Paket „XNA Game Studio 4.0″ herunterladen. Für Windows Vista und 7 Anwender rate ich davon ausdrücklich ab.“

    rätst du ausdrücklich davon ab? Ich habe vor nur XNA 4.0 zu installieren, ohne die ganzen Windows Phone 7 Sachen.. was soll ich machen?

    • Ja, ich rate ausdrücklich davon ab. Das Paket „XNA Game Studio 4.0“ ist ausschliesslich für WindowsXP mit vorheriger Installation von Visual Studio 2010 Express, Professional oder höher gedacht.

      XNA gibt es in einer aktuellen und gepflegten Version nur noch mit den „Phone Sachen“, die hauptsächlich aus Projekt-Templates, dem Device-Manager und dem Phone-Emulator bestehen. Mit Beta-Versionen, Service-Packs und Lokalisierung derselben würde ich nur bei der „korrekten“ Version rechnen. Auch die Release Notes der jeweiligen Pakete schreiben zu den Systemanforderungen ganz klar: „XNA Game Studio 4.0 Standalone“ => WindowsXP und beim „Windows Phone SDK“ => Windows Vista / Windows 7.

  6. Hallo,

    ich bin über Google auf diesen älteren Beitrag gestossen. Gilt Ihre Aussage zur korrekten Paketwahl denn noch immer? Wenn ich nämlich heute nach „XNA für Windows 7“ suche, werde ich auf diese Seite (http://www.microsoft.com/en-us/download/details.aspx?id=23714) geleitet. Dort steht unter „Supported Operating System“: Windows 7, Windows Vista und Windows XP.

    Viele Grüße,
    Alexander

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: