Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android OpenGL ES 2, Drawing squares

EDIT: Problem solved! So I've been going through the official OpenGL ES 2 tutorials for Android, and I've gotten to the part that involves drawing shapes, but I can't seem to get a square to work. It draws a right triangle instead.

I've included the code that I'm using to define and draw the shape, which is copied almost exactly from the tutorial. The Renderer class simply creates an instance of this shape and calls the draw method.

For some reason, the tutorial does not give the values/declaration for vertexStride and vertexCount, so the ones I have in there are educated guesses. I've tried several values for vertexCount (1 thru 12), and none work.

Thanks in advance.

            public class Square {                  private FloatBuffer vertexBuffer;                 private ShortBuffer drawListBuffer;                  // number of coordinates per vertex in this array                 static final int COORDS_PER_VERTEX = 3;                 static float squareCoords[] = { -0.5f,  0.5f, 0.0f,   // top left                                                 -0.5f, -0.5f, 0.0f,   // bottom left                                                  0.5f, -0.5f, 0.0f,   // bottom right                                                  0.5f,  0.5f, 0.0f }; // top right                  private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices                 float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };                   private final String vertexShaderCode =                         "attribute vec4 vPosition;" +                         "void main() {" +                         "  gl_Position = vPosition;" +                         "}";                  private final String fragmentShaderCode =                     "precision mediump float;" +                     "uniform vec4 vColor;" +                     "void main() {" +                     "  gl_FragColor = vColor;" +                     "}";                  int mProgram;                  static final int vertexStride = COORDS_PER_VERTEX * 4;                 static final int vertexCount = 4;                  public Square() {                     // initialize vertex byte buffer for shape coordinates                     ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); // (# of coordinate values * 4 bytes per float)                     bb.order(ByteOrder.nativeOrder());                     vertexBuffer = bb.asFloatBuffer();                     vertexBuffer.put(squareCoords);                     vertexBuffer.position(0);                      // initialize byte buffer for the draw list                     ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); // (# of coordinate values * 2 bytes per short)                     dlb.order(ByteOrder.nativeOrder());                     drawListBuffer = dlb.asShortBuffer();                     drawListBuffer.put(drawOrder);                     drawListBuffer.position(0);                       int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);                     int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);                      mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program                     GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program                     GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program                     GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables                 }                  public static int loadShader(int type, String shaderCode){                      // create a vertex shader type (GLES20.GL_VERTEX_SHADER)                     // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)                     int shader = GLES20.glCreateShader(type);                      // add the source code to the shader and compile it                     GLES20.glShaderSource(shader, shaderCode);                     GLES20.glCompileShader(shader);                      return shader;                 }                  public void draw() {                     // Add program to OpenGL ES environment                     GLES20.glUseProgram(mProgram);                      // get handle to vertex shader's vPosition member                     int mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");                      // Enable a handle to the triangle vertices                     GLES20.glEnableVertexAttribArray(mPositionHandle);                      // Prepare the triangle coordinate data                     GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,                                                  GLES20.GL_FLOAT, false,                                                  vertexStride, vertexBuffer);                      // get handle to fragment shader's vColor member                     int mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");                      // Set color for drawing the triangle                     GLES20.glUniform4fv(mColorHandle, 1, color, 0);                      // Draw the triangle                     GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);                      // Disable vertex array                     GLES20.glDisableVertexAttribArray(mPositionHandle);                 }             } 
like image 492
Jon W Avatar asked Aug 04 '12 07:08

Jon W


2 Answers

vertexCount = squareCoords.length/COORDS_PER_VERTEX; //Vertex count is the array divided by the size of the vertex ex. (x,y) or (x,y,z)  vertexStride = COORDS_PER_VERTEX * 4;                //4 are how many bytes in a float 

Let me know if that worked out for you, good luck.

I think your also missing the ModelViewProjection Matrix used to convert 3D space to 2D screen space. mvpMatrix should be passed in by the draw function draw(float[] mvpMatrix) Forgot to mention you also should use DrawElements(...) (used in example) if you do there's no need for the count or stride, just the length of an idicies array and a drawing buffer.

    // Get handle to shape's transformation matrix     mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");      // Apply the projection and view transformation     GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);      // Draw the square     GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,                           GLES20.GL_UNSIGNED_SHORT, drawListBuffer); 
like image 125
Nate-Wilkins Avatar answered Oct 13 '22 22:10

Nate-Wilkins


The tutorial is missing some steps: the final code for the square is here.

The example was intended to use glDrawElements instead of glDrawArrays which is indicated by the presence of the line: private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices.

This array specifies the desired vertices of 2 triangles. 0, 1 and 2 for the first. Then 0, 2 and 3 for the second. GL_TRANGLE_FAN just happens to work because it will draw the next triangle using the first vertex in the buffer, the last vertex used in previous triangle and the next vertex. For the second triangle this is 0, 2 and 3. Then 0, 3 and 4, etc. Had vertex 2 been 5, 5 and vertex 3 been -5, 5, the resulting fan would not have been a square.

Replace these lines:

// Draw the triangle GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); 

With these:

// Draw the square GLES20.glDrawElements(     GLES20.GL_TRIANGLES, drawOrder.length,     GLES20.GL_UNSIGNED_SHORT, drawListBuffer); 
like image 34
mrfelis Avatar answered Oct 13 '22 23:10

mrfelis