Why is my code not displaying on phone emulator with vertex array object in opengl

62 views Asked by At

I'm new to this but what I'm trying to do is using vertex array object to display something on a phone emulator. But the problem is that it isn't displaying anything on the phone. What I have understood of using vertex array objects is that a VAO is something like a folder that can points to different buffers and inside the VAO there is vertex buffer objects. What I have done in the code is create two buffers and a VAO. Bind the buffers to an array called mVBOIds. Then bind the VAO to it's own array then i setup the vertex with the buffers.

To populate these buffers I have a file named torus2.raw that has data that looks like this:

# Data order:
# Vertex
# Normal vector
# Texture coordinate
12.329425 0.0 -8.957851 1.0
-0.809017 1.0E-6 0.587785 0.0
0.05 1.0

Where we have the order of data, Vertex has 4 data, Normal Vector has 4 and then Texture coordinate has 2 data.

Here is the code for that part that creates the buffers and VAO and its inside the method onSurfaceCreated:

        // Generate VBO Ids and load the VBOs with data
        GLES30.glGenBuffers ( 2, mVBOIds, 0 );

        GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[0] );
        mVertices.position ( 0 );
        GLES30.glBufferData ( GLES30.GL_ARRAY_BUFFER, mVertices.remaining() * 4,
                mVertices, GLES30.GL_STATIC_DRAW );

        GLES30.glBindBuffer ( GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[1] );
        mNormals.position ( 0 );
        GLES30.glBufferData ( GLES30.GL_ELEMENT_ARRAY_BUFFER, 4 * mNormals.remaining(),
                mNormals, GLES30.GL_STATIC_DRAW );

        // Generate VAO Id
        GLES30.glGenVertexArrays ( 1, mVAOId, 0 );

        // Bind the VAO and then setup the vertex
        // attributes
        GLES30.glBindVertexArray ( mVAOId[0] );

        GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[0] );
        GLES30.glBindBuffer ( GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[1] );

        GLES30.glEnableVertexAttribArray (VERTEX_POS_INDX);
        GLES30.glEnableVertexAttribArray (VERTEX_NORM_INDX);

        GLES30.glVertexAttribPointer ( VERTEX_POS_INDX, VERTEX_POS_SIZE,
                GLES30.GL_FLOAT, false, VERTEX_STRIDE,
                0 );

        GLES30.glVertexAttribPointer (VERTEX_NORM_INDX, VERTEX_NORM_SIZE,
                GLES30.GL_FLOAT, false, VERTEX_STRIDE,
                ( VERTEX_POS_SIZE * 4 ) );

        // Reset to the default VAO
        GLES30.glBindVertexArray ( 0 );

        GLES30.glClearColor ( 0.15f, 0.15f, 0.15f, 1.0f );
        GLES30.glEnable(GLES30.GL_DEPTH_TEST);

After this when I have the buffer and VAO setup, I use onDrawFrame method to get it to show in display:

    public void onDrawFrame ( GL10 glUnused )
    {
        // Initiate the model-view matrix as identity matrix
        Matrix.setIdentityM(mViewMatrix, 0);

        // Define a translation transformation
        Matrix.translateM(mViewMatrix, 0, 0.0f, 0.0f, -60.0f);
        // Define a rotation transformation
        Matrix.rotateM(mViewMatrix, 0, 90.0f, 1.0f, 0.0f, 0.0f);

        // Calculate the model-view and projection transformation as composite transformation
        Matrix.multiplyMM (mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

        // Clear the color buffer
        GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT );

        // Use the program object
        GLES30.glUseProgram ( mProgramObject );

        // Make MVP matrix accessible in the vertex shader
        mMVPMatrixHandle = GLES30.glGetUniformLocation(mProgramObject, "uMVPMatrix");
        GLES30.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);

        // Light position:
        vLightPositionHandle = GLES30.glGetUniformLocation(mProgramObject, "vLightPosition");
        GLES30.glUniform4fv(vLightPositionHandle, 1, lightPosition, 0);

        // Light color:
        vLightColorDfHandle = GLES30.glGetUniformLocation(mProgramObject, "vLightColorDf");
        GLES30.glUniform4fv(vLightColorDfHandle, 1, lightColorDf, 0);

        // Material color:
        vMaterialColorDfHandle = GLES30.glGetUniformLocation(mProgramObject, "vMaterialColorDf");
        GLES30.glUniform4fv(vMaterialColorDfHandle, 1, materialColorDf, 0);

        GLES30.glBindVertexArray ( mVAOId[0] );

        // Draw with the VAO settings
        GLES30.glDrawElements ( GLES30.GL_TRIANGLES, mNormals.remaining(), GLES30.GL_UNSIGNED_SHORT, 0 );

        // Return to the default VAO
        GLES30.glBindVertexArray ( 0 );
    }

But the problem is that I can't get anything to display. I've tried to double check the variabels, check if if the variabels are empty etc but I could not find the culprit. It could also be that I've understood the code differently and made a logical error but I can't see what it is. The result should be a blue-ish donut shaped model.

This is the whole code:

    import android.content.Context;
    import android.opengl.GLES30;
    import android.opengl.GLSurfaceView;
    import android.opengl.Matrix;
    import android.util.Log;

    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.FloatBuffer;

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

    import se.hig.dvg306.modul3app.tools.ResourceHandler;

    public class Modul3Renderer implements GLSurfaceView.Renderer
    {
    //
    // Constructor - loads model data from a res file and creates byte buffers for
    // vertex data and for normal data
    //
    public Modul3Renderer (Context context)
    {
        appContext = context;

        Log.e(TAG, "--->>>      Creating ModelLoader...");
        ModelLoader modelLoader = new ModelLoaderImpl ();
        Log.e(TAG, "--->>>      ...finished.");

        Log.e(TAG, "--->>>      Loading model...");
        Log.e(TAG, "--->>>      Starting with vertices...");
        float[] mVerticesData; //= new float[0];

        try {
            mVerticesData = modelLoader.loadModel (context, R.raw.torus2, 0, 10, 0);
        } catch (IOException e) {
            throw new RuntimeException (e);
        }
        Log.e(TAG, "--->>>      ...finished.");

        // Process vertex data
        // 4: because of 4 elements per vertex position
        nbrOfVertices = mVerticesData.length / 10;

        mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mVertices.put(mVerticesData).position(0);

        Log.e(TAG, "--->>>      Starting with normals...");
        float[] mNormalData; //= new float[0];

        try {
            mNormalData = modelLoader.loadModel (context, R.raw.torus2, 4, 4, 6);
        } catch (IOException e) {
            throw new RuntimeException (e);
        }
        Log.e(TAG, "--->>>      ...finished.");

        // Process normal data
        // 4: because of 4 elements per vertex position
        nbrOfNormals = mNormalData.length / 4;

        mNormals = ByteBuffer.allocateDirect(mNormalData.length * 4)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mNormals.put(mNormalData).position(0);
    }

    ///
    // Create a shader object, load the shader source, and
    // compile the shader.
    //
    private int createShader(int type, String shaderSrc )
    {
        int shader;
        int[] compiled = new int[1];

        // Create the shader object
        shader = GLES30.glCreateShader ( type );

        if ( shader == 0 )
        {
            return 0;
        }

        // Load the shader source
        GLES30.glShaderSource ( shader, shaderSrc );

        // Compile the shader
        GLES30.glCompileShader ( shader );

        // Check the compile status
        GLES30.glGetShaderiv ( shader, GLES30.GL_COMPILE_STATUS, compiled, 0 );

        if ( compiled[0] == 0 )
        {
            Log.e ( TAG, GLES30.glGetShaderInfoLog ( shader ) );
            GLES30.glDeleteShader ( shader );
            return 0;
        }

        return shader;
    }

    ///
    // Initialize the shader and program object
    //
    public void onSurfaceCreated ( GL10 glUnused, EGLConfig config )
    {
        int vertexShader;
        int fragmentShader;
        int programObject;
        int[] linked = new int[1];


        // Load the source code for the vertex shader program from a res file:
        try {
            vShaderStr = ResourceHandler.readTextData(appContext, R.raw.vertex_shader);
        } catch (IOException e) {
            Log.e ( TAG, "--->>>      Could not load source code for vertex shader.");
            throw new RuntimeException (e);
        }
        Log.e ( TAG, "--->>>      Loaded vertex shader: " + vShaderStr);

        // Load the source code for the fragment shader program from a res file:
        try {
            fShaderStr = ResourceHandler.readTextData(appContext, R.raw.fragment_shader);
        } catch (IOException e) {
            Log.e ( TAG, "--->>>      Could not load source code for fragment shader.");
            throw new RuntimeException (e);
        }
        Log.e ( TAG, "--->>>      Loaded fragment shader: " + fShaderStr);

        // Create the vertex/fragment shaders
        vertexShader = createShader( GLES30.GL_VERTEX_SHADER, vShaderStr );
        fragmentShader = createShader( GLES30.GL_FRAGMENT_SHADER, fShaderStr );

        // Create the program object
        programObject = GLES30.glCreateProgram();

        if ( programObject == 0 )
        {
            return;
        }

        GLES30.glAttachShader ( programObject, vertexShader );
        GLES30.glAttachShader ( programObject, fragmentShader );

        // Bind vPosition to attribute 0
        GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );

        // Bind vNormal to attribute 1
        GLES30.glBindAttribLocation ( programObject, 1, "vNormal" );

        // Link the program
        GLES30.glLinkProgram ( programObject );

        // Check the link status
        GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );

        if ( linked[0] == 0 )
        {
            Log.e ( TAG, "Error linking program:" );
            Log.e ( TAG, GLES30.glGetProgramInfoLog ( programObject ) );
            GLES30.glDeleteProgram ( programObject );
            return;
        }

        // Store the program object
        mProgramObject = programObject;

        // Generate VBO Ids and load the VBOs with data
        GLES30.glGenBuffers ( 2, mVBOIds, 0 );

        GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[0] );
        mVertices.position ( 0 );
        GLES30.glBufferData ( GLES30.GL_ARRAY_BUFFER, mVertices.remaining() * 4,
                mVertices, GLES30.GL_STATIC_DRAW );

        GLES30.glBindBuffer ( GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[1] );
        mNormals.position ( 0 );
        GLES30.glBufferData ( GLES30.GL_ELEMENT_ARRAY_BUFFER, 4 * mNormals.remaining(),
                mNormals, GLES30.GL_STATIC_DRAW );

        // Generate VAO Id
        GLES30.glGenVertexArrays ( 1, mVAOId, 0 );

        // Bind the VAO and then setup the vertex
        // attributes
        GLES30.glBindVertexArray ( mVAOId[0] );

        GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[0] );
        GLES30.glBindBuffer ( GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[1] );

        GLES30.glEnableVertexAttribArray (VERTEX_POS_INDX);
        GLES30.glEnableVertexAttribArray (VERTEX_NORM_INDX);

        GLES30.glVertexAttribPointer ( VERTEX_POS_INDX, VERTEX_POS_SIZE,
                GLES30.GL_FLOAT, false, VERTEX_STRIDE,
                0 );

        GLES30.glVertexAttribPointer (VERTEX_NORM_INDX, VERTEX_NORM_SIZE,
                GLES30.GL_FLOAT, false, VERTEX_STRIDE,
                ( VERTEX_POS_SIZE * 4 ) );

        // Reset to the default VAO
        GLES30.glBindVertexArray ( 0 );

        GLES30.glClearColor ( 0.15f, 0.15f, 0.15f, 1.0f );
        GLES30.glEnable(GLES30.GL_DEPTH_TEST);
    }

    //
    // Draw a torus using the shader pair created in onSurfaceCreated()
    //
    public void onDrawFrame ( GL10 glUnused )
    {
        // Initiate the model-view matrix as identity matrix
        Matrix.setIdentityM(mViewMatrix, 0);

        // Define a translation transformation
        Matrix.translateM(mViewMatrix, 0, 0.0f, 0.0f, -60.0f);
        // Define a rotation transformation
        Matrix.rotateM(mViewMatrix, 0, 90.0f, 1.0f, 0.0f, 0.0f);

        // Calculate the model-view and projection transformation as composite transformation
        Matrix.multiplyMM (mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

        // Clear the color buffer
        GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT );

        // Use the program object
        GLES30.glUseProgram ( mProgramObject );

        // Make MVP matrix accessible in the vertex shader
        mMVPMatrixHandle = GLES30.glGetUniformLocation(mProgramObject, "uMVPMatrix");
        GLES30.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);

        // Light position:
        vLightPositionHandle = GLES30.glGetUniformLocation(mProgramObject, "vLightPosition");
        GLES30.glUniform4fv(vLightPositionHandle, 1, lightPosition, 0);

        // Light color:
        vLightColorDfHandle = GLES30.glGetUniformLocation(mProgramObject, "vLightColorDf");
        GLES30.glUniform4fv(vLightColorDfHandle, 1, lightColorDf, 0);

        // Material color:
        vMaterialColorDfHandle = GLES30.glGetUniformLocation(mProgramObject, "vMaterialColorDf");
        GLES30.glUniform4fv(vMaterialColorDfHandle, 1, materialColorDf, 0);

        GLES30.glBindVertexArray ( mVAOId[0] );

        // Draw with the VAO settings
        GLES30.glDrawElements ( GLES30.GL_TRIANGLES, mNormals.remaining(), GLES30.GL_UNSIGNED_SHORT, 0 );

        // Return to the default VAO
        GLES30.glBindVertexArray ( 0 );
    }

    //
    // Handle surface changes
    //
    public void onSurfaceChanged ( GL10 glUnused, int width, int height )
    {
        mWidth = width;
        mHeight = height;

        GLES30.glViewport(0, 0, width, height);

        float ratio = (float) width / height;

        // this projection matrix is applied to object coordinates
        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1.0f, 1.0f, 0.5f, 1000.0f);
    }

    // Member variables

    private Context appContext;

    private int mWidth;
    private int mHeight;

    private int nbrOfVertices;
    private FloatBuffer mVertices;

    final int VERTEX_POS_SIZE   = 4; // x, y and z
    final int VERTEX_NORM_SIZE = 4; // r, g, b, and a

    final int VERTEX_POS_INDX   = 0;
    final int VERTEX_NORM_INDX = 1;

    private int [] mVBOIds = new int[2];
    private int [] mVAOId = new int[1];

    private int nbrOfNormals;
    private FloatBuffer mNormals;

    private int mProgramObject;
    private int mMVPMatrixHandle;

    // Transformation data:
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];

    final int VERTEX_STRIDE = ( 4 * ( VERTEX_POS_SIZE +  VERTEX_NORM_SIZE ) );

    // Light position and color (only diffuse term now):
    private int vLightPositionHandle;
    private final float lightPosition [] = {175.0f, 75.0f, 125.0f, 0.0f};
    // Light color (only diffuse term now):
    private int vLightColorDfHandle;
    private final float lightColorDf [] = {0.98f, 0.98f, 0.98f, 1.0f};
    // Material color (only diffuse term now):
    private int vMaterialColorDfHandle;
    private final float materialColorDf [] = {0.62f, 0.773f, 0.843f, 1.0f};

    // To be read when creating the instance:
    private String vShaderStr;
    private String fShaderStr;

    private static String TAG = "Modul3Renderer";
    }
1

There are 1 answers

0
Rabbid76 On BEST ANSWER

A GL_ELEMENT_ARRAY_BUFFER object is meant for the indices and should conitain integral data. You should use a GL_ARRAY_BUFFER for the normal vectors:

GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[1] );
        mNormals.position ( 0 );
GLES30.glBufferData ( GLES30.GL_ARRAY_BUFFER, 4 * mNormals.remaining(),
        mNormals, GLES30.GL_STATIC_DRAW );

When glVertexAttribPointer is called the buffer which is currently bound to the target ARRAY_BUFFER, is associated to the specified attribute index and the ID of the object is stored in the state vector of the currently bound VAO. So you have to bind the buffer object before calling glVertexAttribPointer:

GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBOIds[0]);
GLES30.glVertexAttribPointer ( VERTEX_POS_INDX, VERTEX_POS_SIZE,
                GLES30.GL_FLOAT, false, VERTEX_STRIDE,
                0 );

GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBOIds[1]);
GLES30.glVertexAttribPointer (VERTEX_NORM_INDX, VERTEX_NORM_SIZE,
                GLES30.GL_FLOAT, false, VERTEX_STRIDE,
                ( VERTEX_POS_SIZE * 4 ) );