Skip navigation

Well, XNA is a lot different than OpenGL.

I like it, though.

* XNA does NOT have glVertex3f() or glColor3f() equivalents. That is, you can’t specify a drawing by specifying a series of vertex points and colors like you might be used to in OpenGL.

glBegin( GL_LINES ) ;   // has
glVertex3f( 0, 0, 0 ) ;  // no
glVertex3f( 1, 0, 0 ) ;  // xna
glEnd() ; // equivalent.

* Strangely (and goodly, I suppose), the above method is used when batching calls to draw textures. Kind of neato, actually.

spriteBatch.Begin() ;
  spriteBatch.Draw( texture1 ... ) ;
  spriteBatch.Draw( texture2 ... ) ;
spriteBatch.End() ;

* You can’t specify line width in XNA.

glLineWidth( 4.0f ) ; // sorry, no xna equivalent.

* To simulate this (and accomodate for the deficiency), take a look at Manders vs machine thick lines demo, or consider drawing rotated rectangular textures instead of true lines, if working strictly in 2d.

* Here is how you handle it. The following Game1 class can be copy/pasted into a new project.


#region using...
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;
#endregion

public class Game1 : Microsoft.Xna.Framework.Game
{
  GraphicsDeviceManager graphics;
  
  ////
  // To draw, we'll need 3 basic objects:
  //   1.  A BasicEffect
  //   2.  A VertexBuffer
  //   3.  A VertexDeclaration

  // The BasicEffect will draw the vertices in the
  // VertexBuffer using the VertexDeclaration to
  // understand the type of vertices that are in 
  // the VertexBuffer.
  //
  ////


  //// The BasicEffect.
  // The BasicEffect object will be our rendering workhorse.
  // It will remember all the information about our model,
  // view and projection matrices.
 
  // Basically the renderer will take points from anywhere in space
  // and translate them into the canonical view volume (-1,-1,0), (1,1,1)
  BasicEffect renderer ;

  //// The VertexBuffer
  // Ah, a "vertex buffer".  What is a vertex buffer?
  // Its just a fancy name for "arrayful of vertices".
  // Isn't that just an arrayful of Vector3's, you say?
  // Well, no.  It will actually be an arrayful of
  // VERTICES which EACH have a COLOR __and__ a position
  // in space.

  // What's more is whatever you store inside this vertexbuffer
  // will actually go down and sit IN THE GPU.  That's right.
  // You will write code that downloads vertex data
  // directly into your graphics card!  Isn't this exciting?

  // When you call the renderer object to draw
  // your shapes, you will pass it your collection of
  // vertices that you place inside the vertex buffer.
  VertexBuffer vb ;
  

  //// The VertexDeclaration.
  // Ok, you know how above we said that the VertexBuffer
  // was going to be this collection of vertices that
  // sat in the GPU?

  // Well, the GPU isn't THAT smart.  UNless you tell it,
  // it will actually NOT KNOW which points in your VertexBuffer
  // are meant to be positions, and which points are meant to be colors.

  // So you need to tell it.  The VertexDeclaration
  // says WHAT KIND OF DATA is in the VertexBuffer.
  // Does each vertex have:
  //   * Just a position?
  //   * A position and a color?
  //   * A position and a color AND a texture coordinate?

  // The vertex declaration object is how you specify
  // exactly what data is IN that VertexBuffer.
  VertexDeclaration vd ;

  // And that's all!  With these 4 objects, we'll
  // be able to draw basic primitives to the screen.
  ////


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

  protected override void Initialize()
  {
    base.Initialize();
  }

  protected override void LoadContent()
  {
    /////
    // Initialization.
    // This is a really long set of steps we need to do
    // to load vertex data INTO THE GPU.

    // The way drawing happens in XNA is you kind of
    // "preload" the GPU up with all the vertices
    // you want it to draw.  Like, you place the
    // data DIRECTLY into the GPU card itself.

    // Then, in your Draw() function, you just
    // tell it what to draw, using data that you
    // previously already loaded into its memory.

    //////
    // Initialize the renderer as a BasicEffect:
    renderer = new BasicEffect(
      
      GraphicsDevice,  // represents the GPU.  We must tie
      // our renderer object to the physical GPU.

      null             // We do not need pooling.
    
    ) ;
    renderer.VertexColorEnabled = true ;  // make it actually
    // use the colors we specify to color the verticies.
    // 
    //////

    //////
    // Next, we will create and set up a bunch of vertices
    // that we can draw.

    // I've decided to go with 3 vertices.
    // You can change this if you like.
    /////////////////////////////
    int NUM_VERTICES = 3;      //
    /////////////////////////////



    // Now to make some vertices.  Here we go!
    // I'm using the native C# type VertexPositionColor because
    // I want each Vertex to have BOTH a POSITION IN SPACE,
    // AND a color specified for it.  There are other types,
    // like VertexPositionColorTexture if you want to add in
    // some tex coords.
    VertexPositionColor[] pointList = new VertexPositionColor[ NUM_VERTICES ];


    // Now, I'm going to actually go in and give each vertex
    // some point value.
    pointList[ 0 ] = new VertexPositionColor(

      new Vector3( 0, 0, 0 ),
      Color.Black

    );

    pointList[ 1 ] = new VertexPositionColor(

      new Vector3( 0.5f, 0, 0 ),
      Color.Red

    );

    pointList[ 2 ] = new VertexPositionColor(

      new Vector3( 0, 0.5f, 0 ),
      Color.GreenYellow

    );
    //
    ///////

    // ARE WE DONE YET???  We specified the vertices.  Can't
    // we just draw them?

    // NOT QUITE!!  We specified the vertices in C#, system
    // memory.  However, the GPU doesn't have them yet.
    
    // So, how are we gonna flush out the vertex
    // specification above out the GPU itself?

    /////
    // We first need to allocate memory for (ON THE GPU!!) our vertices.

    // Notice how this memory allocation statement doesn't 
    // seem to have have normal C# form.
    
    // Yes we are creating a VertexBuffer object, but nowhere
    // do you see normal array creation (new VertexColor[5] or something
    // like that).  However given the parameters, enough memory
    // will be allocated to store an arrayful of vertices,
    // each with its own position and color.
    
    vb = new VertexBuffer(
      
      GraphicsDevice,  // this is the GPU onto which to store
      // this actual vertex buffer.  Remember, we're writing
      // directly to the GPU here!

      VertexPositionColor.SizeInBytes * NUM_VERTICES, // AWKWARD!!
      // What an awkward way to say how many vertices we
      // want this vertex buffer to eventually hold.  Nonetheless,
      // this is how you do it.
      // Its pretty straightforward, no?
      
      BufferUsage.None  // This doesn't mean we AREN'T GOING TO
      // USE the buffer.  No.  Instead, it means that we have
      // "no special instructions" about how this buffer will
      // be used.

      // The two other options are BufferUsage.Points, which
      // says to XNA that the VertexBuffer we're creating here
      // is actually going to be used to render POINTS in space,
      // and not triangles or lines, so to be prepared for that.

      // The OTHER option is BufferUsage.WriteOnly, which is
      // to say to XNA that our software program will only
      // WRITE to this buffer and never directly read from it
      // (though the GPU itself will obviously read from it
      // to actually draw what we put in there).
      // Though .WriteOnly is a reasonable setting to use here
      // for this example, we're not going to bother.  In case
      // you're wondering, there is a method VertexBuffer.GetData<>
      // which you would use to "read" from a vertex buffer.
    
    );

    ////
    // Finally we need to SET IN that set of vertices we
    // declared above into the actual GPU VertexBuffer.

    // So the way we do that is by using
    vb.SetData<VertexPositionColor>( pointList ) ;

    //
    /////

    // OK ALMOST done here.  Just ONE LAST THING.

    // At draw time, the GPU will want to be notified AGAIN
    // what kind of vertex data you're trying to draw.

    // For this reason, we must initialize a VertexDeclaration
    // object:

    /////
    // The VertexDeclaration will tell
    // the GPU what KIND of vertex data it
    // shall be reading when it attempts to read
    // the VertexBuffer we just sent it in the 
    // lines of code above
    vd = new VertexDeclaration(

      GraphicsDevice,  // tie to the GPU

      VertexPositionColor.VertexElements  // its
      // going to be a bunch of vertices that
      // have a Position and a Color.

      // Autocomplete help is a bit misleading here:
      // "An array of vertex elements" - but this is
      // NOT the place to pass in your vertex data.
      // We already did that above.
    );

    // And DONE!
    //////
  }


  protected override void Update( GameTime gameTime )
  {
    // Esc. to exit.
    if( Keyboard.GetState().IsKeyDown(Keys.Escape) )
      this.Exit();

    base.Update( gameTime );
  }


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

    // Tell GPU again what kind of vertices it should
    // expect to be getting.
    renderer.GraphicsDevice.VertexDeclaration = vd ;


    renderer.Begin(); // start rendering.


    // Enter a loop.  You'll see this loop a lot,
    // basically the reason for it is some "EFFECTS" (aka "shaders")
    // have multiple passes.. that is, they actually draw out
    // each vertex more than one time.  They do this to achieve
    // neato effects like weird shell hulls in a light shaded purple
    // color around an object, etc.
    foreach( EffectPass pass in renderer.CurrentTechnique.Passes )
    {
      // begin this rendering pass.
      pass.Begin();

      // Set the size of the points
      renderer.GraphicsDevice.RenderState.PointSize = 8.0f ;

      // Tell the GPU what vertex array to pull vertex data from.
      renderer.GraphicsDevice.Vertices[0].SetSource( vb, 0, VertexPositionColor.SizeInBytes );

      // Actually draw.
      #region note
      // !! Note:  There is a mistake in the MSDN sample @
      // http://msdn.microsoft.com/en-us/library/bb196414.aspx
      // In that example, they use GraphicsDevice.DrawUserPrimitives<VertexPositionColor>
      // and that's wrong because DrawUserPrimitives doesn't draw
      // from a vertex buffer.
      #endregion
      renderer.GraphicsDevice.DrawPrimitives(
      
        PrimitiveType.PointList,  // they are points ...
        0, // ... start at the beginning of the list ...
        3  // ... and pull 3 points out of it.
        
      );

      // end the rendering pass.
      pass.End();
    }

    // Stop rendering.
    renderer.End();


    ////
    base.Draw( gameTime );
  }

  static void Main( string[] args )
  {
    Game1 game = new Game1() ;
    game.Run();
  }
}


About these ads

5 Comments

    • Terrick Mansur
    • Posted March 24, 2009 at 12:09 am
    • Permalink

    Awesome man thanks a million

    • Tom
    • Posted November 6, 2009 at 6:59 pm
    • Permalink

    Amazing tutorial man, thank you!
    Could you do one on 3D please ;)

    • Anonymous
    • Posted November 30, 2009 at 10:01 pm
    • Permalink

    Hi and thank you for the hints!
    Anyway if i draw lines with this method, or the one suggested by msdn, it slow down really bad the rendering process (it really sucks :()
    Do you have any tips to tune up the rendering process?

  1. I can’t seem to be able to reach this page from my smartphone!!!!

    • szendroib
    • Posted December 16, 2012 at 12:41 pm
    • Permalink

    Really great tutorial, the book i was learning from was wrong, it used the DrawUserPrimitives function, and I couldn’t figure out why could I delete all vertexbuffer code and the program still draws:D. It was a huge help!


One Trackback/Pingback

  1. [...] READING, this post explains vertex buffers and how you download vertices to the GPU using .SetData in greater [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 41 other followers

%d bloggers like this: