PSM Tutorial #2-3 : Texture Coordinates

2013-01-22 2:01 AM

In thehttp://levelism.com/vita-psm-tutorial-2-part-2-drawing-something-on-the-screen-verticies-indicies-and-vertex-colors/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