如何从顶点数组重构代码到顶点数组对象方法



我正在学习Opengl,我一直在使用的书是Opengl (R) ES 3.0编程指南,第二版。在第6章,他们讨论了顶点数组,他们有一个使用顶点数组方法的示例代码,就是下面的代码。在那一章的后面,他们讨论了顶点数组对象,我想尝试的是把这个例子代码重构成使用顶点数组对象方法的代码。问题是我不知道顶点数组对象是如何工作的,如果有人能把我推向正确的方向,我将不胜感激。

示例代码如下:
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";
}

在过去的几天里,我一直在努力理解如何编写一个使用Object方法的代码,但我无法理解它,于是决定问一下。因此,我希望通过询问我能得到一些如何开始的理解。

当你想要使用顶点数组对象时,你必须创建并绑定VAO。顶点规范存储在当前绑定的VAO的状态向量中。因此,当VAO被绑定时,必须执行顶点规范。我还建议把属性放在顶点缓冲对象:

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

稍后您可以使用VAO来绘制几何图形。为此,绑定VAO就足够了:

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