Saturday, June 4, 2011

Texturing Cube : Applying (Same) Texture on All Faces of Cube

I became over-enthusiastic and tried to leap too far before covering my ground, soon i found myself facing ground.

I tried to go for cube map directly before applying texture with texture2D on cube. then i realised my mistake and here we are applying same texture to cube faces.

Screen shot:

there are changes in cube definition compared to previous post. Now, all the face are drawn Counter Clock Wise and back face culling. following is the cube definition.

  1: float[] cube = {
  2:     2,2,2, -2,2,2, -2,-2,2, 2,-2,2, //0-1-2-3 front
  3:     2,2,2, 2,-2,2,  2,-2,-2, 2,2,-2,//0-3-4-5 right
  4:     2,-2,-2, -2,-2,-2, -2,2,-2, 2,2,-2,//4-7-6-5 back
  5:     -2,2,2, -2,2,-2, -2,-2,-2, -2,-2,2,//1-6-7-2 left
  6:     2,2,2, 2,2,-2, -2,2,-2, -2,2,2, //top
  7:     2,-2,2, -2,-2,2, -2,-2,-2, 2,-2,-2,//bottom
  8:   };

here we are defining all the faces of cube, and we use indexes to define the triangles for drawing. and texture co-ordinates for each face.

  1: short[] indeces = {
  2:       0,1,2, 0,2,3,
  3:       4,5,6, 4,6,7,
  4:       8,9,10, 8,10,11,
  5:       12,13,14, 12,14,15,
  6:       16,17,18, 16,18,19,
  7:       20,21,22, 20,22,23,
  8:      
  9:       };
 10:  
 11:   float[] tex = {
 12:       1,0, 0,0, 0,1, 1,1,
 13:       0,0, 0,1, 1,1, 1,0,
 14:       1,1, 0,1, 0,0, 1,0,
 15:       0,0, 1,0, 1,1, 0,1,
 16:       0,1, 0,0, 1,0, 1,1,
 17:       0,0, 1,0, 1,1, 0,1,
 18:      
 19:       };

In constructor, added code to load texture co-ordinates into a buffer.

  1: public ViewPortRenderer(ES2SurfaceView view)
  2:   {
  3:     curView = view;
  4:     cubeBuffer = ByteBuffer.allocateDirect(cube.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
  5:     cubeBuffer.put(cube).position(0);
  6:    
  7:     colorBuffer = ByteBuffer.allocateDirect(colors.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
  8:     colorBuffer.put(colors).position(0);
  9:    
 10:     indexBuffer = ByteBuffer.allocateDirect(indeces.length * 4).order(ByteOrder.nativeOrder()).asShortBuffer();
 11:     indexBuffer.put(indeces).position(0);
 12:    
 13:     texBuffer = ByteBuffer.allocateDirect(tex.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
 14:     texBuffer.put(tex).position(0);
 15:   }

Let’s have a look at changes in shaders.

Vertex Shader:

  1: String strVShader = "attribute vec4 a_position;" +
  2:         "uniform mat4 u_VPMatrix;" +
  3:         "attribute vec2 a_texCoords;" +
  4:         "varying vec2 v_texCoords;" +
  5:         "void main()" +
  6:         "{" +
  7:           "v_texCoords = a_texCoords;" +
  8:           "gl_Position = u_VPMatrix * a_position;" +
  9:         "}";

instead of color we are taking texture co-ordinates.

Fragment Shader:

  1: String strFShader = "precision mediump float;" +
  2:         "varying vec4 v_color;" +
  3:         "uniform sampler2D u_texId;" +
  4:         "varying vec2 v_texCoords;" +
  5:         "void main()" +
  6:         "{" +
  7:           "gl_FragColor = texture2D(u_texId, v_texCoords);" +
  8:         "}";

here we took texture in a sampler2D, since we are loading texture as GL_TEXTURE_2D.

texture2D function gives the fragment color at texture position in loaded texture.

changes in onSurfaceCreated

  1: GLES20.glFrontFace(GLES20.GL_CCW);
  2: GLES20.glEnable(GLES20.GL_CULL_FACE);
  3: GLES20.glCullFace(GLES20.GL_BACK);

here we telling opengl that all the triangles are drawn in counter clock wise and enable cull face.

Changes in onDrawFrame

  1: texBuffer.position(0);
  2: GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 0, texBuffer);
  3: GLES20.glEnableVertexAttribArray(iTexCoords);
  4:    
  5: GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
  6: GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iTexId);
  7: GLES20.glUniform1i(iTexLoc, 0);

Just here we are activating texture0 and binding the loaded texture to it. passing the texture index to shader with glUniform1i.