|
Visualizzazione di un modello 3D in rotazione su 1 asse XNA è un ambiente di sviluppo bivalente, ovvero è possibile compilare un progetto per la piattaforma Windows oppure per la piattaforma Xbox 360, per la quale è necessario pagare l’abbonamento al club. Vedremo più avanti come compilare il progetto per Xbox 360 e scaricare l’applicazione sulla console (deploy), per adesso ci limitiamo a realizzare un semplice progetto tratto dal tutorial ufficiale atto a realizzare un modello 3D texturizzato in rotazione, dapprima su un solo asse (da tutorial originale), in seguito su tutti i 3 assi (modificando il codice del tutorial). Innanzitutto lanciamo XNA Game Studio Express utilizzando l’apposito collegamento nel menù d’avvio. Verrà avviato Visual C# Express 2005. Selezioniamo dunque nuovo progetto e nel wizard scegliamo Windows Game. Assegnamo al progetto un nome e un percorso. Nel menù dell’applicazione scegliamo VIEW quindi OUTPUT, in modo tale da avere sempre sott’occhio il debugging (errori di sintassi o semplici warnings) di tutto ciò che andremo a scrivere. La struttura dell’interfaccia vede un frame a sinistra in cui viene scritto il codice, un frame sulla destra definito SOLUTION EXPLORER e un frame in basso per il debugging. Iniziamo dunque il progetto. Innanzitutto scompattiamo l’allegato RAR scaricabile da qui , ottenendo una cartella denominata CONTENT contenente il modello 3D (nella cartella MODELS), le textures (nella cartella TEXTURES) e gli effetti sonori (nella cartella AUDIO. I medesimi files sono reperibili creando una nuova soluzione MySpaceWarXbox1 dal wizard di XNA Studio Express, richiudendola e prelevando la cartella CONTENT dalla directory in cui risiede il progetto (che porta il medesimo nome del progetto).
Il presente tutorial si propone solamente un’introduzione alla programmazione con C# e DirectX per la console di casa Microsoft, ragion per cui la costruzione del modello tridimensionale e delle relative textures esula dagli scopi della guida. A titolo informativo, il modello consiste in un file .fbx, un formato di interscambio e creazione 3D, contenente i vettori che descrivono il modello generato grazie ad un CAD 3D. Il software di modellazione solida 3D Studio Max è in grado di esportare i modelli direttamente in .fbx. Esistono opportuni convertitori (dell'Autodesk per esempio) che convertono in fbx i files vettoriali prodotti con i tradizionali CAD 3D (e viceversa) quali per esempio AutoCAD (con moduli 3D), Pro Engineer, Solidworks, Solidedge ecc... Per visualizzare il modello utilizzato in questo esempio, ho convertito il file in .dxf (presente nell'allegato) e ho utilizzato AutoCAD 2007: Il modello aperto con 3D Studio Max è ancora più eloquente:
Le textures sono contenute in un file .tga, esplorabile ad esempio grazie a Photoshop: Nel frame SOLUTION EXPLORER selezioniamo il progetto in corso di sviluppo, premiamo il tasto destro del mouse e selezioniamo ADD – NEW FOLDER: assegniamo alla nuova cartella il nome CONTENT. Portiamo il puntatore del mouse sulla nuova cartella appena creata, premiamo il tasto destro e selezioniamo ADD – NEW FOLDER: assegniamo alla nuova cartella il nome MODELS. Ripetiamo la precedente operazione, creiamo dunque una nuova cartella a cui assegniamo il nome TEXTURES. Posizioniamo il puntatore del mouse su MODELS e selezioniamo ADD - EXISTING ITEM: selezioniamo dunque il file p1_wedge.fbx estratto dal file RAR nella cartella CONTENT – MODELS. Posizioniamo il puntatore del mouse su TEXTURES e selezioniamo ADD - EXISTING ITEM: selezioniamo dunque il file wedge_p1_diff_v1.tga estratto dal file RAR nella cartella CONTENT – TEXTURES. Andiamo adesso a scrivere il codice. Come si può facilmente vedere, il progetto si apre con un set di istruzioni base che consentono la compilazione del progetto. Per caricare e animare il modello 3D importato, dobbiamo aggiungere alcune istruzioni all’interno del progetto. Innanzitutto cerchiamo il metodo LoadGraphicsContent e modifichiamo il codice come riportato di seguito: protected override void LoadGraphicsContent(bool loadAllContent) { if (loadAllContent) { myModel = content.Load< Model >("Content\\Models\\p1_wedge"); } } Immediatamente sopra al metodo LoadGraphicsContent inseriamo le seguenti stringhe: //3d model to draw Model myModel; NOTA: Le stringhe che iniziano con il doppio slash // denotano commenti. Ogni riga deve terminare con il punto e virgola ; Cerchiamo ora il metodo Draw, incaricato di rappresentare il modello 3D sullo schermo con relative textures e con gli effetti di luce. Modifichiamo il codice come riportato di seguito: protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); //Copy any parent transforms Matrix[] transforms = new Matrix[myModel.Bones.Count]; myModel.CopyAbsoluteBoneTransformsTo(transforms); //Draw the model, a model can have multiple meshes, so loop foreach (ModelMesh mesh in myModel.Meshes) { //This is where the mesh orientation is set, as well as our camera and projection foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationY(modelRotation) * Matrix.CreateTranslation(modelPosition); effect.View = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up); effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 1.0f, 10000.0f); } //Draw the mesh, will use the effects set above. mesh.Draw(); } } Immediatamente sopra al metodo Draw inseriamo le seguenti stringhe: //Position of the model in world space, and rotation Vector3 modelPosition = Vector3.Zero; float modelRotation = 0.0f; //Position of the Camera in world space, for our view matrix Vector3 cameraPosition = new Vector3(0.0f, 50.0f, 5000.0f); //Aspect ratio to use for the projection matrix float aspectRatio = 640.0f / 480.0f; Compilando il progetto già ora è possibile visualizzare il modello sullo schermo in forma statica. La rotazione del modello intorno a 1 asse è il compito del metodo Update, il cui codice deve essere modificato nel modo seguente: protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); modelRotation += (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.1f); base.Update(gameTime); } A questo punto salviamo il progetto ed eseguiamolo premendo F5. 
VIDEO Qualora non vogliate modificare i singoli metodi manualmente (cosa che suggerisco per farsi un'idea di ciò che si scrive e si modifica), il file Game1.cs integrale è riportato di seguito: #region Using Statements using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; #endregion public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; ContentManager content; public Game1() { graphics = new GraphicsDeviceManager(this); content = new ContentManager(Services); } protected override void Initialize() { base.Initialize(); } //3d model to draw Model myModel; protected override void LoadGraphicsContent(bool loadAllContent) { if (loadAllContent) { myModel = content.Load< Model >("Content\\Models\\p1_wedge"); } } protected override void UnloadGraphicsContent(bool unloadAllContent) { if (unloadAllContent == true) { content.Unload(); } } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); modelRotation += (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.1f); base.Update(gameTime); } //Position of the model in world space, and rotation Vector3 modelPosition = Vector3.Zero; float modelRotation = 0.0f; //Position of the Camera in world space, for our view matrix Vector3 cameraPosition = new Vector3(0.0f, 50.0f, 5000.0f); //Aspect ratio to use for the projection matrix float aspectRatio = 640.0f / 480.0f; protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); //Copy any parent transforms Matrix[] transforms = new Matrix[myModel.Bones.Count]; myModel.CopyAbsoluteBoneTransformsTo(transforms); //Draw the model, a model can have multiple meshes, so loop foreach (ModelMesh mesh in myModel.Meshes) { //This is where the mesh orientation is set, as well as our camera and projection foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationY(modelRotation) * Matrix.CreateTranslation(modelPosition); effect.View = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up); effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 1.0f, 10000.0f); } //Draw the mesh, will use the effects set above. mesh.Draw(); } } }
|