Wednesday, May 18, 2011

Drawing and Texturing Triangle

Today I learned way to draw triangle and texture the same.

Screen Shot


As usual code is available in Google Code.

It is very easy to draw a triangle with Shaders.

First, let's look at the Vertex Shader

String strVShader =
        "attribute vec4 a_position;" +
        "attribute vec2 a_texCoords;" +
        "varying vec2 v_texCoords;" +
        "void main()" +
        "{" +
              "gl_Position = a_position;" +
              "v_texCoords = a_texCoords;" +
        "}";

Here, I have declared 2 new variables:

a_texCoords, to get the texture co-ordinates while rendering

v_texCoords, is a varying variable to feed as a input variable for Fragment Shader for texture co-ordinates.

So I have just stored input, a_texCoords, to vertex shader's output, v_texCoords, variable.

Fragment Shader

String strFShader =
        "precision mediump float;" +
        "varying vec2 v_texCoords;" +
        "uniform sampler2D u_texId;" +
        "void main()" +
        "{" +
          "gl_FragColor = texture2D(u_texId, v_texCoords);" +
        "}";

Here, if you observe we have same, v_texCoords, variable is declared, which is a input from Vertex Shader.

And as in the previous post, we are taking the Fragment Color from the texture with texture2D function.

Now, let's go to drawing function.

OnDrawFrame function

First let's have a look at our vertex array declaration.

float[] fVertices =

{0,0.5f,0, 0,0,

-0.5f,-0.5f,0, 1,0,

0.5f,-0.5f,0, 1,1};

Values colored green are vertices for drawing triangle. And values in red are texture co-ordinates. We need not have separate arrays for vertices and texture co-ordinates.

Let's look at how to use this array for drawing triangle and texturing as well.

public void onDrawFrame(GL10 gl) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    GLES20.glUseProgram(iProgId);
   
    vertexBuffer.position(0);
    GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 5 * 4, vertexBuffer);
    GLES20.glEnableVertexAttribArray(iPosition);
   
    vertexBuffer.position(3);
    GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 5* 4, vertexBuffer);
    GLES20.glEnableVertexAttribArray(iTexCoords);
   
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iTexId);
    GLES20.glUniform1i(iTexLoc, 0);
   
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
  }

There are 2 distinct changes when compared to previous post,
We are setting current position to zero for vertices and 3 for texture coordinates, this way we telling Opengl, that vertices starts at zero with stride of 5 * 4 (number of byte to skip for next set of vertices) and texture co-ordinates start from position 3 with same stride. Finally glDrawArrays to draw triangle.