PSM Tutorial #2-4 : Vertex Buffers

2013-02-13

In the previous tutorial we went over the concepts of texture coordinates. Now we only have one major topic to go over before wrapping everything up. Vertex Buffers.

Now we will look at the next set of declarations in the code. As always I will start by including the full code sample.

public class AppMain
{
static protected GraphicsContext graphics;
static ShaderProgram shaderProgram;
static Texture2D texture;

static float[] vertices=new float[12];

static float[] texcoords = {
0.0f, 0.0f,// 0 top left.
0.0f, 1.0f,// 1 bottom left.
1.0f, 0.0f,// 2 top right.
1.0f, 1.0f,// 3 bottom right.
};

static float[] colors = {
1.0f,1.0f,1.0f,1.0f,// 0 top left.
1.0f,1.0f,1.0f,1.0f,// 1 bottom left.
1.0f,1.0f,1.0f,1.0f,// 2 top right.
1.0f,1.0f,1.0f,1.0f,// 3 bottom right.
};

const int indexSize = 4;
static ushort[] indices;

static VertexBuffer vertexBuffer;

// Width of texture.
static float Width;

// Height of texture.
static float Height;

static Matrix4 unitScreenMatrix;

public static void Main (string[] args)
{
Initialize ();

while (true) {
SystemEvents.CheckEvents ();
Update ();
Render ();
}
}

public static void Initialize ()
{
graphics = new GraphicsContext();
ImageRect rectScreen = graphics.Screen.Rectangle;

texture = new Texture2D("/Application/resources/Player.png", false);
shaderProgram = new ShaderProgram("/Application/shaders/Sprite.cgx");
shaderProgram.SetUniformBinding(0, "u_WorldMatrix");

Width = texture.Width;
Height = texture.Height;

vertices[0]=0.0f;// x0
vertices[1]=0.0f;// y0
vertices[2]=0.0f;// z0

vertices[3]=0.0f;// x1
vertices[4]=1.0f;// y1
vertices[5]=0.0f;// z1

vertices[6]=1.0f;// x2
vertices[7]=0.0f;// y2
vertices[8]=0.0f;// z2

vertices[9]=1.0f;// x3
vertices[10]=1.0f;// y3
vertices[11]=0.0f;// z3

indices = new ushort[indexSize];
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 3;

//vertex pos,               texture,       color
vertexBuffer = new VertexBuffer(4, indexSize, VertexFormat.Float3, VertexFormat.Float2, VertexFormat.Float4);

vertexBuffer.SetVertices(0, vertices);
vertexBuffer.SetVertices(1, texcoords);
vertexBuffer.SetVertices(2, colors);

vertexBuffer.SetIndices(indices);
graphics.SetVertexBuffer(0, vertexBuffer);

unitScreenMatrix = new Matrix4(
 Width*2.0f/rectScreen.Width,0.0f,    0.0f, 0.0f,
 0.0f,   Height*(-2.0f)/rectScreen.Height,0.0f, 0.0f,
 0.0f,   0.0f, 1.0f, 0.0f,
 -1.0f,  1.0f, 0.0f, 1.0f
);

}

public static void Update ()
{

}

public static void Render ()
{
graphics.Clear();

graphics.SetShaderProgram(shaderProgram);
graphics.SetTexture(0, texture);
shaderProgram.SetUniformValue(0, ref unitScreenMatrix);

graphics.DrawArrays(DrawMode.TriangleStrip, 0, indexSize);

graphics.SwapBuffers();
}
}

Now as we browse past the declarations covered in the previous tutorials we arrive at the vertex buffer declaration:

static VertexBuffer vertexBuffer;

In OpenGL there are numerous ways to send data to the GPU to be drawn on the screen. The modern way of doing this is via vertex buffers.

A vertex buffer is a contiguous stream of data that you send to the GPU from your program. The data structure used for storing this data is an array. In plain OpenGL you setup an array of data then call a function that tells OpenGL which array to stream into memory along with some other information such as the size of the array and type of data it represents.

In PSM it’s essentially the same but Sony provides a VertexBuffer object that encapsulates a lot of the common functionality you tend to use with a vertex buffer. We can define a vertex buffer that associates vertex, UV, and color data with the same object. You can also associate other types of data if you wish to do so. Sony also specifically takes in the index buffer size in the VertexBuffer constructor.

So lets take a look at the code where we setup out vertex buffers.


//vertex pos,               texture,       color
vertexBuffer = new VertexBuffer(4, indexSize, VertexFormat.Float3, VertexFormat.Float2, VertexFormat.Float4);

vertexBuffer.SetVertices(0, vertices);
vertexBuffer.SetVertices(1, texcoords);
vertexBuffer.SetVertices(2, colors);

vertexBuffer.SetIndices(indices);
graphics.SetVertexBuffer(0, vertexBuffer);

First we create out VertexBuffer object. In the constructor we first pass the number of vertices we will be sending to the GPU. We then pass the number of indices we will be passing. After the first 2 arguments we have a variable length of arguments we can pass to the constructor.

Variable length arguments are very similar to C’s varargs functionality. For more information about c#’s feature for non variable length arguments see this page.

http://msdn.microsoft.com/en-us/library/w5zay9db(v=vs.71).aspx

Each of the arguments for the variable portion of the parameters defines a vertex buffer. The buffer is declared by an enum that describes the format of data that will be passed in through that buffer.

//vertex pos,               texture,       color
vertexBuffer = new VertexBuffer(4, indexSize, VertexFormat.Float3, VertexFormat.Float2, VertexFormat.Float4);

So here we say we want to pass in 4 vertices, 4 indices (the value of indexSize at the time), a set of 3 floats per vertex, a set of 2 floats per vertex and a set of 4 floats per vertex. The reason for these sizes will be more apparent if you look the following code:

vertexBuffer.SetVertices(0, vertices);
vertexBuffer.SetVertices(1, texcoords);
vertexBuffer.SetVertices(2, colors);

vertexBuffer.SetIndices(indices);
graphics.SetVertexBuffer(0, vertexBuffer);

As you can see we use the SetVertieces method to assign which array represents which piece of data. The first coordinate is the index of the array we are passing into the VertexBuffer object. This corresponds to the order that we entered the variable length parameters in the VertexBuffer constructor. In index 0 we pass in the vertices which need 3 floats per vertex to describe. In index 1 we pass the texture coordinates which take 2 floats per vertex to describe and finally in index 2 we pass the colors which take 4 floats per vertex to describe.

Then we send our index array to the VertexBuffer via the SetIndicies method.

Finally we send the entire vertex buffer to the graphics context.

Since we covered most of the more difficult to grasp concepts in previous tutorials this one ended up being fairly short. In the next tutorial we will go over the render method and wrap up this tutorial series!

After that we can get into more interesting things like making a game

Tags: psm_tutorial

PSM Tutorial #2-3 : Texture Coordinates

2013-01-22

In the previous tutorial we went over the concepts of vertices, indices and vertex colors. Now we will go over an important concept : Texture coordinates.

Now we will look at the next set of declarations in the code. As always I will start by including the full code sample.

public class AppMain
{
static protected GraphicsContext graphics;
static ShaderProgram shaderProgram;
static Texture2D texture;

static float[] vertices=new float[12];

static float[] texcoords = {
0.0f, 0.0f,// 0 top left.
0.0f, 1.0f,// 1 bottom left.
1.0f, 0.0f,// 2 top right.
1.0f, 1.0f,// 3 bottom right.
};

static float[] colors = {
1.0f,1.0f,1.0f,1.0f,// 0 top left.
1.0f,1.0f,1.0f,1.0f,// 1 bottom left.
1.0f,1.0f,1.0f,1.0f,// 2 top right.
1.0f,1.0f,1.0f,1.0f,// 3 bottom right.
};

const int indexSize = 4;
static ushort[] indices;

static VertexBuffer vertexBuffer;

// Width of texture.
static float Width;

// Height of texture.
static float Height;

static Matrix4 unitScreenMatrix;

public static void Main (string[] args)
{
Initialize ();

while (true) {
SystemEvents.CheckEvents ();
Update ();
Render ();
}
}

public static void Initialize ()
{
graphics = new GraphicsContext();
ImageRect rectScreen = graphics.Screen.Rectangle;

texture = new Texture2D("/Application/resources/Player.png", false);
shaderProgram = new ShaderProgram("/Application/shaders/Sprite.cgx");
shaderProgram.SetUniformBinding(0, "u_WorldMatrix");

Width = texture.Width;
Height = texture.Height;

vertices[0]=0.0f;// x0
vertices[1]=0.0f;// y0
vertices[2]=0.0f;// z0

vertices[3]=0.0f;// x1
vertices[4]=1.0f;// y1
vertices[5]=0.0f;// z1

vertices[6]=1.0f;// x2
vertices[7]=0.0f;// y2
vertices[8]=0.0f;// z2

vertices[9]=1.0f;// x3
vertices[10]=1.0f;// y3
vertices[11]=0.0f;// z3

indices = new ushort[indexSize];
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 3;

//vertex pos,               texture,       color
vertexBuffer = new VertexBuffer(4, indexSize, VertexFormat.Float3, VertexFormat.Float2, VertexFormat.Float4);

vertexBuffer.SetVertices(0, vertices);
vertexBuffer.SetVertices(1, texcoords);
vertexBuffer.SetVertices(2, colors);

vertexBuffer.SetIndices(indices);
graphics.SetVertexBuffer(0, vertexBuffer);

unitScreenMatrix = new Matrix4(
 Width*2.0f/rectScreen.Width,0.0f,    0.0f, 0.0f,
 0.0f,   Height*(-2.0f)/rectScreen.Height,0.0f, 0.0f,
 0.0f,   0.0f, 1.0f, 0.0f,
 -1.0f,  1.0f, 0.0f, 1.0f
);

}

public static void Update ()
{

}

public static void Render ()
{
graphics.Clear();

graphics.SetShaderProgram(shaderProgram);
graphics.SetTexture(0, texture);
shaderProgram.SetUniformValue(0, ref unitScreenMatrix);

graphics.DrawArrays(DrawMode.TriangleStrip, 0, indexSize);

graphics.SwapBuffers();
}
}

Texture coordinates are interesting concept. They define how a 2d image is mapped onto a 3d plane. It’s a concept that is used heavily in both 2d and 3d rendering and is a very useful bit of foundation knowledge.

If you want to apply a texture to a plane you need to be able to define how it maps to that plane. As such each vertex requires a extra 2D set of coordinates which define what parts of an image to apply to the plane. UV coordinate space extends from 0 to 1. On the X-Axis of an image file 0 would be the left side of the image and 1 would be the right-most pixel of the image (equal to the width of the image. The concept is the same for the Y-Axis. So if we wanted to show a whole image on a square plane then we would have the following coordinates:

  • Top left vertex

  • X = 0 - Y = 0

  • Bottom left vertex

  • X = 0 - Y = 1

  • Top right vertex

  • X = 1 - Y = 0

  • Bottom right vertex

  • X = 1 - Y = 1

Now if you wanted to only show the half top of an image on a plane you would have the following coordinates:

  • Top left vertex

  • X = 0 - Y = 0

  • Bottom left vertex

  • X = 0 - Y = 0.5

  • Top right vertex

  • X = 1 - Y = 0

  • Bottom right vertex

  • X = 1 - Y = 0.5

Now nothing helps more than a visual example so here is a image that describes the two situations we have just outlined. Notice the effect of displaying half a square image on a square plane results in stretching distortion.

resources/images/2013/01/uvexample.png

Now lets take a look at this in code.

static float[] texcoords = {
0.0f, 0.0f,// 0 top left.
0.0f, 1.0f,// 1 bottom left.
1.0f, 0.0f,// 2 top right.
1.0f, 1.0f,// 3 bottom right.
};

Here we have a float array declaration with UV coordinates for each vertex on the quad we wish to draw. As usual this goes counter-clockwise along the vertices. If you compare these declarations to the previous example in this tutorial you most likely will have deduced that a quad with these coordinates will display an entire image.

Before I end this section I would like you to think about some of the uses of displaying the subsection of an image.

  • You can use this for animations. Have all your animated frames of a character on one image and “slide” the coordinates each frame over a portion of the image. This is a technique used very frequently for animation. - You can have effects like moving water by moving a sub rectangle over a large image of water.

One last thing Ihaven’taddress is it’s entirely possible to have your texture coordinate ranges outside of the 0-1 coordinate space. The effect this has is different depending on your renderer and settings. One very common usage of this is tiling. If you have a plane whose coordinates extend from 0 to 10 then the image will repeat 10 times across the plane. This is used a lot in 3d rendering for tiling textures like grass or brick.

That’s all there really is to UV coordinates. Next up we will focus on Vertex Buffers.

Tags: psm_tutorial

Preview #01 of my new PSM/Vita game Neko Rush

2013-01-13

Here’s the first screenshots of my new game NekoRush. It’s first game for the PSP-Vita / PSM. It’s a continuous runner where you are a cat running through the neighborhood and must recruit other cats while avoiding obstacles. The two main cats you play as are my cats that are currently staying with my family in Canada while I’m in Japan.

Cat artwork is done my talented SO when she has time.

This is also using the custom 2D engine I developed for PSM. I’ve been doing a lot of reworking on it over the weekend and hope to eventually be able to release it to the public for anyone to use.

resources/images/2013/01/nekorush_01_02.png

resources/images/2013/01/nekorush_01_01.png

Tags: nekorush