3
\$\begingroup\$

I am migrating an app that draws on OpenGL ES 1.0 to OpenGL ES 2.0.

The app used to draw multiple 2D triangles, as a vertex array, where the vertices matched the pixels on screen.

I made a sample project to reproduce the problem.

The data

static ShortBuffer provideData() {
    final ByteBuffer data = ByteBuffer.allocateDirect(12 * BYTES_PER_SHORT);
    data.order(ByteOrder.nativeOrder());

    final ShortBuffer floatData = data.asShortBuffer();
    floatData.put(new short[]{
            351, 22, 361, 22, 361, 32, 351, 22, 351, 32, 361, 32
    });

    return floatData;
}

OpenGL 1.0: works as expected:

final class FirstGenRenderer implements GLSurfaceView.Renderer {

    private static final int VERTICES_PER_PARTICLE = 6;

    private final ShortBuffer coordinates = DataProvider.provideData();

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();

        final int color = Color.DKGRAY;
        gl.glClearColor(
                Color.red(color) / 255f,
                Color.green(color) / 255f,
                Color.blue(color) / 255f, 0f);

        final int particleColor = Color.WHITE;
        gl.glColor4f(
                Color.red(particleColor) / 255f,
                Color.green(particleColor) / 255f,
                Color.blue(particleColor) / 255f, 0f);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
        gl.glOrthof(0, width, 0, height, 1, -1);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

        coordinates.position(0);

        gl.glVertexPointer(2, GL10.GL_SHORT, 0, coordinates);
        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, VERTICES_PER_PARTICLE);

        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    }
}

The output: clear color and a small white square at the bottom enter image description here

The same implementation on GL 2.0: does not produce desired results:

package com.doctoror.ortho;

import android.graphics.Color;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.support.annotation.NonNull;

import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public final class SecondGenRenderer implements GLSurfaceView.Renderer {

    private static final int COORDINATES_PER_VERTEX = 2;
    private static final int VERTICES_PER_PARTICLE = 6;

    private static final String VERTEX_SHADER_CODE =
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = uMVPMatrix * vPosition;" +
                    "}";

    private static final String FRAGMENT_SHADER_CODE =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    private final ShortBuffer coordinates = DataProvider.provideData();

    private final float[] mvpMatrix = new float[16];
    private final float[] projectionMatrix = new float[16];
    private final float[] viewMatrix = new float[16];

    private int program;

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        final int vertexShader = loadShader(
                GLES20.GL_VERTEX_SHADER,
                VERTEX_SHADER_CODE);

        final int fragmentShader = loadShader(
                GLES20.GL_FRAGMENT_SHADER,
                FRAGMENT_SHADER_CODE);

        program = GLES20.glCreateProgram();
        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);
        GLES20.glLinkProgram(program);

        final int color = Color.DKGRAY;
        GLES20.glClearColor(
                Color.red(color) / 255f,
                Color.green(color) / 255f,
                Color.blue(color) / 255f, 0f);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        Matrix.orthoM(projectionMatrix, 0, 0f, width, 0f, height, 1, -1);

        Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f);
        Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glUseProgram(program);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        final int positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
        checkGlError("glGetAttribLocation");

        GLES20.glEnableVertexAttribArray(positionHandle);
        checkGlError("glEnableVertexAttribArray");

        coordinates.position(0);

        GLES20.glVertexAttribPointer(
                positionHandle,
                COORDINATES_PER_VERTEX,
                GLES20.GL_FLOAT,
                false,
                0,
                coordinates);

        checkGlError("glVertexAttribPointer");

        final int colorHandle = GLES20.glGetUniformLocation(program, "vColor");
        checkGlError("glGetUniformLocation");

        final float[] color = new float[]{1f, 1f, 1f, 1f};
        GLES20.glUniform4fv(colorHandle, 1, color, 0);

        final int mvpMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        checkGlError("glGetUniformLocation");

        GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);
        checkGlError("glUniformMatrix4fv");

        GLES20.glDrawArrays(GL10.GL_TRIANGLES, 0, VERTICES_PER_PARTICLE);
        checkGlError("glDrawArrays");

        GLES20.glDisableVertexAttribArray(positionHandle);
    }

    private static int loadShader(final int type, @NonNull final String shaderCode) {
        final int shader = GLES20.glCreateShader(type);

        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;
    }

    private static void checkGlError(@NonNull final String glOperation) {
        int error;
        if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            throw new RuntimeException(glOperation + ": glError " + error);
        }
    }
}

The output: a clear color.

enter image description here

Expected output: as with GLES10, above.

\$\endgroup\$
  • \$\begingroup\$ Once a shader is bound any time you call glDrawArray/Elements the shader program is used automatically. Have you made sure your vertex structure is compatible? \$\endgroup\$ – Sidar Jun 3 '18 at 11:35
  • \$\begingroup\$ To clarify your vertex shader only expects the vertex position. So if your mesh has more attributes ( uv, color, etc ) the data wouldn't make sense and whatever you see on screen probably looks botched. \$\endgroup\$ – Sidar Jun 3 '18 at 12:13
  • \$\begingroup\$ I highly recommend you use an android graphics debugger If you have android 7 or higher renderdoc is an excellent contender. You can actually see how your quads are transformed. \$\endgroup\$ – Sidar Jun 4 '18 at 15:23
0
\$\begingroup\$

I have accidentally copy-pasted GL_FLOAT instead of GL_SHORT for my glVertexAttribPointer.

GLES20.glVertexAttribPointer(
    positionHandle,
    COORDINATES_PER_VERTEX,
    GLES20.GL_FLOAT, // With the sample data, SHOULD BE GL_SHORT
    false,
    0,
    coordinates);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.