Σάββατο 25 Δεκεμβρίου 2010

XNA - Indices

Μάθημα 7ο

  • Θα χρησιμοποιήσουμε τον κώδικα του προηγούμενου μαθήματος (μην ξεχάσετε την δήλωση του namespace αλλιώς θα υπάρξει σφάλμα). Υπάρχει όμως ένα μικρό πρόβλημα με τον κώδικα αυτό. Αν και φτιάχνουμε ένα τετράγωνο από δύο τρίγωνα, στην πραγματικότητα έχουμε εισάγει 6 σημεία ενώ χρειαζόμαστε μόνο τέσσερα. Υπάρχουν δύο ζεύγη σημείων τα οποία είναι όμοια μεταξύ τους. Για να λυθεί αυτό το πρόβλημα, χρησιμοποιούμε indices. Έτσι η κάρτα γραφικών μας θα γλιτώνει από περιττό κόπο.

Τα σημεία A και C πρέπει να οριστούν μία φορά

  • Ορίζουμε λοιπόν μόνο τα σημεία που χρειαζόμαστε στην συνάρτηση SetUpVertices:      

    vertices = new VertexPositionColor[4];
    vertices[0].Position = new Vector3(0f, 0f, 0f);
    vertices[1].Position = new Vector3(10, 10f, 0f);
    vertices[2].Position = new Vector3(20f, 0f, 0f);
    vertices[3].Position = new Vector3(10, -10f, 0f);

    vertices[3].Color = Color.Blue;
    vertices[0].Color = Color.Blue;
    vertices[1].Color = Color.Green;
    vertices[2].Color = Color.Yellow





    Το ήξερες? : Το XNA θεωρεί ότι ο άξονας z αυξάνεται προς τα εμάς, και μειώνεται καθώς πηγαίνουμε πιο μακριά.
    Χ,Υ,Ζ άξονες





     
  • Τώρα θα δηλώσουμε τα indices. Στην αρχή της κλάσης δηλώνουμε:

    int[] indices;

    Έπειτα δημιουργούμε μια συνάρτηση , την SetUpIndices:

    private void SetUpIndices()
    indices = new ints[6];
    indices[0] = 0;
    indices[1] = 1;
    indices[2] = 2;
    indices[3] = 0;
    indices[4] = 2;
    indices[5] = 3; 
    } 

  • Τώρα καλούμε την μέθοδο SetUpIndices μέσα στην LoadContent:

    SetUpIndices();

  • Τώρα πρέπει στην Draw μέθοδο να αλλάξουμε την κλήση της σχεδίασης από:

    Gdevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, 2);
    σε:

    Gdevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3);

    Κλασσικά, λέμε ποιο είναι το array των vertices/indices, από ποιο σημείο του να ξεκινήσουμε και τέλος, πόσα τρίγωνα θα φτιάξουμε (6/3 = 2 τρίγωνα, αφού 3 indices φτιάχνουν ένα τρίγωνο). Το vertices.Length δείχνει πόσα vertices υπάρχουν στο array vertices; 
    Το ήξερες? : μπορείς να ζωγραφίσεις μόνο το περίγραμμα των τριγώνων με τον παρακάτω κώδικα (πρώτη γραμμή στην μέθοδο Draw):

    Gdevice.RenderState.FillMode = FillMode.WireFrame;

Το 7ο μάθημα έφτασε στο τέλος του.


Το τρίγωνο αποτελείται από μόνο 4 vertices!

Ασχολίες για εξάσκηση:
  1. Δημιουργήστε δύο τρίγωνα με ένα κοινό σημείο
Πηγές: Riemer's Tutorial

_________________________________________

Απλοποιημένος κώδικας (χωρίς περιττά σχόλια)





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;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

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

        GraphicsDevice Gdevice;

        Effect myEffect;

        VertexPositionColor[] vertices;
        int[] indices;

        VertexDeclaration myVertexDeclaration;

        Matrix viewMatrix;
        Matrix projectionMatrix;

        float angle = 0f;

        private void SetUpCamera()
        {
            viewMatrix = Matrix.CreateLookAt(new Vector3(0f, 50.0f, 50.0f), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Gdevice.Viewport.AspectRatio, 1.0f, 300.0f);
        }   

        private void SetUpVertices()
        {
            myVertexDeclaration = new VertexDeclaration(Gdevice, VertexPositionColor.VertexElements);

            vertices = new VertexPositionColor[4];

            vertices[0].Position = new Vector3(0f, 0f, 0f);
            vertices[1].Position = new Vector3(10, 10f, 0f);
            vertices[2].Position = new Vector3(20f, 0f, 0f);

            vertices[0].Color = Color.Blue;
            vertices[1].Color = Color.Green;
            vertices[2].Color = Color.Yellow;

            vertices[3].Position = new Vector3(10, -10f, 0f);

            vertices[3].Color = Color.Red;
        }


        private void SetUpIndices()
        {
            indices = new int[6];

            indices[0] = 0;
            indices[1] = 1;
            indices[2] = 2;
            indices[3] = 0;
            indices[4] = 2;
            indices[5] = 3;
        }
        

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

        // Init
        protected override void Initialize()
        {
            graphics.PreferredBackBufferHeight = 600;
            graphics.PreferredBackBufferWidth = 800;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();
            Window.Title = "Το αλμυρό φυστίκι";

            base.Initialize();
        }

        // Load Content
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Gdevice = graphics.GraphicsDevice;
            myEffect = Content.Load("effects");

            SetUpVertices();
            SetUpCamera();
            SetUpIndices();
        }

        protected override void UnloadContent()
        {

        }

        // Update (60 times per second)
        protected override void Update(GameTime gameTime)
        {
            angle += 0.005f;

            base.Update(gameTime);
        }

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

            Gdevice.RenderState.CullMode = CullMode.None;

            myEffect.Parameters["xView"].SetValue(viewMatrix);
            myEffect.Parameters["xProjection"].SetValue(projectionMatrix);
         
            Matrix worldMatrix = Matrix.CreateTranslation(-10f,0, 0) * Matrix.CreateRotationY(3*angle);

            myEffect.Parameters["xWorld"].SetValue(worldMatrix);

            myEffect.CurrentTechnique = myEffect.Techniques["Colored"];

            myEffect.Begin();

            foreach (EffectPass pass in myEffect.CurrentTechnique.Passes)
            {
                pass.Begin();

                Gdevice.VertexDeclaration = myVertexDeclaration;
                Gdevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length,indices,0,indices.Length/3);

                pass.End();
            }
            myEffect.End();

            base.Draw(gameTime);
        }
    }

}