简体   繁体   中英

How to refactor code from Vertex Array to Vertex Array Object methods

I'm studying Opengl and the book i've been using is OpenGL(R) ES 3.0 Programming Guide, 2nd Edition. And at chapter 6 they talk about Vertex arrays and they have a example code that uses Vertex Array methods, which is the code below. Later down that chapter they are talking about Vertex Array Object and what I wanted to try is to take this example code and refactor the code into something that uses the Vertex Array Object methods. Problem is I have no idea how Vertex Array Object works and would be gratful if anyone could push me in the right direction.

The example code is here:

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 android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

import se.hig.dvg306.modul3app.R;
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, 4, 6);
        } 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 / 4;

        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;

        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);

        // Load the vertex data from mVertices
        GLES30.glVertexAttribPointer ( 0, 4, GLES30.GL_FLOAT, false, 0, mVertices );



        // Assign vertex data to 'in' variable bound to attribute with index 0:
        GLES30.glEnableVertexAttribArray ( 0 );

        // Load the normal data from mNormals
        GLES30.glVertexAttribPointer ( 1, 4, GLES30.GL_FLOAT, false, 0, mNormals );
        // Assign normal data to 'in' variable bound to attribute with index 1:
        GLES30.glEnableVertexAttribArray ( 1 );

        GLES30.glDrawArrays (GLES30.GL_TRIANGLES, 0, nbrOfVertices);

        GLES30.glDisableVertexAttribArray ( 1 );
        GLES30.glDisableVertexAttribArray ( 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;

    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];

    // 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";
}

I've tried for the past days now to understand how to write a code that uses the Object methods but I cant wrap my head around it and decided to ask. So I hope by asking I can get some understanding how to begin.

When you want to use a Vertex Array Object , you must create and bind the VAO. The vertex specification is stored in the state vector of the currently bound VAO. Therefore, you must do the vertex specification when the VAO is bound. I also suggest to put the attributes in Vertex Buffer Objects :

int vao;
int vboVertices;
int vboNormals;
vao = GLES30.glGenVertexArray();
GLES30.glBindVertexArray(vao);

vboVertices = GLES30.glGenBuffer();
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboVertices);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, mVertices.remaining() * 4, mVertices, GLES30.GL_STATIC_DRAW);
GLES30.glVertexAttribPointer(0, 4, GLES30.GL_FLOAT, false, 0, 0);
GLES30.glEnableVertexAttribArray(0);

vboNormals = GLES30.glGenBuffer();
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboNormals);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, mNormals.remaining() * 4, mNormals, GLES30.GL_STATIC_DRAW);
GLES30.glVertexAttribPointer(1, 4, GLES30.GL_FLOAT, false, 0, 0);
GLES30.glEnableVertexAttribArray(1);

Later you can use the VAO to draw the geometry. For this it is enough to bind the VAO:

GLES30.glBindVertexArray(vao);
GLES30.glDrawArrays (GLES30.GL_TRIANGLES, 0, nbrOfVertices);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM