- Disegnare un triangolo tridimensionale che ruota -
 
COSA SERVE PER QUESTO TUTORIAL
Download | Chiedi sul FORUM | Glossario cognizioni basiche di C# e sul framework XNA
Introduzione alla creazione di giochi 3D con XNA

UN TRIANGOLO IN UNO SPAZIO TRIDIMENSIONALE
Come servirsi di BasicEffect per creare una semplice realtà 3D.

Questo è il primo, introduttivo, articolo alla programmazione di videogiochi tridimensionali con XNA 4.0. Per ora ci limiteremo a creare una realtà tridimensionale e ad inserire un triangolo, farlo ruotare e far ruotare la camera. Per fare questo ci serviremo di un oggetto di tipo BasicEffect, che andrà configurato con una matrice di vista (View), una di proiezione (Projection) e una per la trasformazione da applicare al mondo (World). In particolare la matrice per la vista sarà ottenuta a partire da tre vettori: uno per la posizione della camera (CameraPosition), uno per il suo obiettivo (CameraTarget) e una per la direzione che punta in alto rispetto alla camera (CameraUp):


public class Triangolo3DGame : Microsoft.Xna.Framework.Game {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    // Matrice che descrive la vista della camera
    Matrix View;
    // Matrice che determina la prospettiva
    Matrix Projection;
    // Matrice delle trasformazione da applicare al mondo
    Matrix World;

    // Posizione della camera
    Vector3 CameraPosition = new Vector3(0.0f, 0.0f, 5.0f);
    // Punto osservato dalla camera
    Vector3 CameraTarget = Vector3.Zero;
    // L'alto rispetto alla camera
    Vector3 CameraUp = Vector3.Up;
    VertexPositionColor[] vertices;

    // Effetto per renderizzare la realtà tridimensionale
    BasicEffect Effect;

    // Fattore di rotazione
    float Rotation = 0.0f;

    // ...

}

Rotation è una variabile che indica la rotazione, in gradi, da applicare alla camera e al mondo.
Per prima cosa inizializziamo i vertici dei due triangoli. Dobbiamo crearne due in modo che risulti uno solo ma sia visibile su entrambi i lati:


protected override void Initialize() {
    // Creiamo due triangoli, uno per quando viene visualizzato davanti e uno per dietro
    this.vertices = new VertexPositionColor[]
    {
        //Triangle 1
        new VertexPositionColor( new Vector3(-1,-1,0), Color.Red),
        new VertexPositionColor( new Vector3(0,1,0), Color.Green),
        new VertexPositionColor( new Vector3(1,-1,0), Color.Blue),
        //Triangle 2
        new VertexPositionColor( new Vector3(1,-1,0), Color.Blue),
        new VertexPositionColor( new Vector3(0,1,0), Color.Green),
        new VertexPositionColor( new Vector3(-1,-1,0), Color.Red),

    };

    // ...

}

Quindi, sempre nel metodo Initialize, inizializziamo le tre matrici suddette:


// Creiamo la matrice della vista a partire da posizione, direzione e orientamento della camera
View = Matrix.CreateLookAt(CameraPosition, CameraTarget, CameraUp);

// Creiamo la matrice di proiezione prospettica
Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 
    this.GraphicsDevice.Viewport.Width / this.GraphicsDevice.Viewport.Height, 0.01f, 1000.0f);

// Inizialmente non applichiamo nessuna trasformazione alla realtà 3D
World = Matrix.Identity;

La vista (View) è ottenuta combinando tramite l'apposita funzione Matrix.CreateLookAt la posizione della camera (CameraPosition), precedentemente inizializzata alle coordinate (0, 0, 5), la direzione in cui guardare (CameraTarget), ovvero l'origine, e infine un vettore che indica la direzione che è "su" rispetto alla camera, semplicemente Vector3.Up in questo caso.
La proiezione (Projection) è invece ottenuta tramite Matrix.CreatePerspectiveFieldOfView, ponendoci ad un'angolazione di un quarto P greco, secondo le proporzioni della finestra e con due valori di orizzonte prestabiliti. Infine la matrice di trasformazione del mondo è inizialmente la matrice identità, ovvero nessuna trasformazione  è applicata.

Ad ogni Update non dovremo far altro che incrementare il fattore di rotazione (Rotation) di un paio di gradi:


protected override void Update(GameTime gameTime) {
    // Ad ogni update incrementiamo la rotazione di 2.0 gradi
    Rotation += MathHelper.ToRadians(2.0f);

    base.Update(gameTime);
}

È infine nel metodo Draw impostare il nostro BasicEffect con tutte le matrici preordinate e con qualche rotazione a piacere, ad esempio


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

    // Impostiamo l'effetto


    // Impostiamo la vista su quella della camera
    Effect.View = View;

    // Impostiamo la proiezione
    Effect.Projection = Projection;

    // Ruotiamo l'intera realtà 3D attorno alla asse Y
    Effect.World = World * Matrix.CreateRotationY(Rotation);

    Effect.VertexColorEnabled = true;

    // Disegnamo il triangolo
    foreach (EffectPass pass in Effect.CurrentTechnique.Passes) {
        pass.Apply();
        this.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3);
    }

    base.Draw(gameTime);
}

Come si può vedere abbiamo moltiplicato la matrice World per una rotazione attorno all'asse Y determinata dalla nostra variabile Rotation. Quindi non abbiamo fatto altro che applicare l'effetto e disegnare i nostri vertici tramite il metodo DrawUserPrimitives.
In alternativa avremmo potuto aggiungere una rotazione del mondo anche attorno all'asse X e un'altra attorno all'asse Z ma questa volta della camera:


// Ruotiamo la camera attorno al suo asse Z
effect.View = View * Matrix.CreateRotationZ(Rotation);

// Impostiamo la proiezione
Effect.Projection = Projection;

// Ruotiamo l'intera realtà 3D attorno alla asse Y (o X, o entrambi)
effect.World = World * Matrix.CreateRotationX(Rotation) * Matrix.CreateRotationY(Rotation);

Effect.VertexColorEnabled = true;

 

<< INDIETRO by VeNoM00