Android上的OpenGL ES 2:如何使用VBO

时间:2014-07-31 08:07:03

标签: android opengl-es-2.0 vbo

这个问题类似于我在这里问的问题Android OpenGL ES 2: Introduction to VBOs 但是从那时起我尝试了多次aproaches,我仍然没有成功,所以我认为发布另一个我提供附加细节的问题将是一个更好的方法。

我是Android上的OpenGL ES 2的新手(我从未使用过另一个OpenGL,我只需要为我正在为Android开发的应用程序绘制内容)而且我非常想了解如何使用VBO。在绘制三角形时,我尝试修改此OpenGL ES 2 for Android tutorial以使用VBO。我尝试使用this step by step guidethis tutorial,但我仍然不了解所有内容,我对所有这些事情都很陌生。我的应用程序目前在启动时崩溃。这就是我所拥有的:

public class Triangle {

private final String vertexShaderCode =
        // This matrix member variable provides a hook to manipulate
        // the coordinates of the objects that use this vertex shader
        "uniform mat4 uMVPMatrix;" +
        "attribute vec4 vPosition;" +
        "void main() {" +
        // the matrix must be included as a modifier of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        "  gl_Position = uMVPMatrix * vPosition;" +
        "}";

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

private final FloatBuffer vertexBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private final int buffer[] = new int[1];

// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = {
        // in counterclockwise order:
        0.0f,  0.622008459f, 0.0f,   // top
       -0.5f, -0.311004243f, 0.0f,   // bottom left
        0.5f, -0.311004243f, 0.0f    // bottom right
};
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f };

/**
 * Sets up the drawing object data for use in an OpenGL ES context.
 */
public Triangle() {
    // initialize vertex byte buffer for shape coordinates
    ByteBuffer bb = ByteBuffer.allocateDirect(
            // (number of coordinate values * 4 bytes per float)
            triangleCoords.length * 4);
    // use the device hardware's native byte order
    bb.order(ByteOrder.nativeOrder());

    // create a floating point buffer from the ByteBuffer
    vertexBuffer = bb.asFloatBuffer();
    // add the coordinates to the FloatBuffer
    vertexBuffer.put(triangleCoords);
    // set the buffer to read the first coordinate
    vertexBuffer.position(0);

    // First, generate as many buffers as we need.
    // This will give us the OpenGL handles for these buffers.

    GLES20.glGenBuffers(1, buffer, 0);

    // prepare shaders and OpenGL program
    int vertexShader = MyGLRenderer.loadShader(
            GLES20.GL_VERTEX_SHADER, vertexShaderCode);
    int fragmentShader = MyGLRenderer.loadShader(
            GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

    mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
    GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
    GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables

}

/**
 * Encapsulates the OpenGL ES instructions for drawing this shape.
 *
 * @param mvpMatrix - The Model View Project matrix in which to draw
 * this shape.
 */
public void draw(float[] mvpMatrix) {


    // get handle to fragment shader's vColor member
    mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

    // Set color for drawing the triangle
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);

    // get handle to shape's transformation matrix
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    MyGLRenderer.checkGlError("glGetUniformLocation");

    // get handle to vertex shader's vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");



    //these I don't fully understand
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffer[0]);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,vertexBuffer.capacity() * 4,vertexBuffer,GLES20.GL_STATIC_DRAW);

    // Add program to OpenGL environment
    GLES20.glUseProgram(mProgram);


    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(
            mPositionHandle, COORDS_PER_VERTEX,
            GLES20.GL_FLOAT, false,
            vertexStride, 0);




    // Apply the projection and view transformation
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
    MyGLRenderer.checkGlError("glUniformMatrix4fv");

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

//        //is this still necesary? or do i have to use glDeleteBuffers?
//        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}

}

当我在vertexBuffer内放0而不是glVertexAttribPointer()时,我收到错误消息,说我没有提供necesarry参数:expected parameter: ptr: java.nio.Buffer; actual arguments: 0(int)

1 个答案:

答案 0 :(得分:3)

由于数据指针的使用,向VBO的转换可能有点奇怪。

快速检查您的主要问题是

GLES20.glVertexAttribPointer(
            mPositionHandle, COORDS_PER_VERTEX,
            GLES20.GL_FLOAT, false,
            vertexStride, vertexBuffer);

因为这应该是

 GLES20.glVertexAttribPointer(
            mPositionHandle, COORDS_PER_VERTEX,
            GLES20.GL_FLOAT, false,
            vertexStride, 0);

关于这个缓冲区:VBO是GPU上的自定义缓冲区,通常用于优化以将顶点数据直接存储到GPU。通过这样做获得的性能是在每次绘制调用时都不需要将顶点数据复制到GPU。

这些缓冲区仍然是自定义的,在生成它们时,您需要设置它们的大小。假设浮点值的大小为4个字节,我看到你在顶点计数上使用因子* 4,这不是最好的主意,因为这可能并不总是真的。如果可能的话,总是尝试使用某种形式的“sizeOf”。无论如何,您的缓冲区已正确创建,数据将被发送到它。

将数据发送到VBO后,您应该将它们保存在那里,直到您需要它们为止。这意味着您通常会为每个唯一对象(例如正方形)创建一个VBO,然后只保留其ID。无论何时你想绘制它,你只需简单地绑定缓冲区并像你一样绘制。换句话说,永远不应该在draw方法中创建缓冲区。你所做的是内存泄漏,因为一旦不再需要缓冲区,你负责释放缓冲区。

关于glVertexAttribPointer上的指针问题:有两种方法可以使用此方法。没有VBO,最后一个参数是指向CPU上数据的指针。使用VBO,您需要将其设置为VBO中的相对指针。这意味着当VBO被绑定时,缓冲区的开头将是NULL(0),您甚至可能需要对该值进行类型转换。对于缓冲区中的其他位置,您需要手动计算它们。

您专门发布的代码:

    // First, generate as many buffers as we need.
    // This will give us the OpenGL handles for these buffers.
    final int buffer[] = new int[1];
    GLES20.glGenBuffers(1, buffer, 0);

    //these I don't fully understand
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffer[0]);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,vertexBuffer.capacity() *    4,vertexBuffer,GLES20.GL_STATIC_DRAW);

这一切都进入了一些加载时间并且引用了旁边的buffer[],您应该添加GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);此调用的作用是取消绑定缓冲区。这不是你需要做的事情,但你最好这样做,你不会混淆什么缓冲区绑定。

在调用glVertexAttribPointer之前,您需要绑定缓冲区。然后如上所述设置最后一个参数。

完成使用此缓冲区(完成绘图)后,您应该(再次没有必要)取消绑定缓冲区。