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\$
3
  • \$\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, 2018 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, 2018 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, 2018 at 15:23

1 Answer 1

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\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .