Android上的OpenGL ES 2:如何使用VBO [英] OpenGL ES 2 on Android: how to use VBOs

查看:94
本文介绍了Android上的OpenGL ES 2:如何使用VBO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题类似于我在这里问的问题 Android OpenGL ES 2:简介到VBO 但是从那以后我尝试了多种方法,但我仍然没有成功,因此我认为在另一个问题上我提供附加细节会是更好的方法.

this question is similar to something I asked here Android OpenGL ES 2: Introduction to VBOs however I tried multiple aproaches since then and I still haven't succeeded, so I think posting another question where I offer aditional details would be a better aproach.

我是Android上的OpenGL ES 2的新手(我从未使用过其他OpenGL,我只需要为我为Android开发的应用绘制一些东西),我非常想了解如何使用VBO.我试图修改此适用于Android教程的OpenGL ES 2 以使用VBO绘制三角形时.我尝试使用此逐步指南

I am new to OpenGL ES 2 on Android (I have never worked with another OpenGL, I just need to draw something for an app I am developing for Android) and I would very much like to understand how to use VBOs. I tried to modify this OpenGL ES 2 for Android tutorial to use VBOs when drawing the triangle. I tried to use this step by step guide and this tutorial but I still don't understand everything, I am rather new to all of these things. My app currently crashes on start. Here's what I have:

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

}

当我在glVertexAttribPointer()中放入0而不是vertexBuffer时,出现错误,提示我未提供necesarry参数:expected parameter: ptr: java.nio.Buffer; actual arguments: 0(int)

when I put 0 instead of vertexBuffer inside glVertexAttribPointer() I get an error saying I don't provide the necesarry parameter: expected parameter: ptr: java.nio.Buffer; actual arguments: 0(int)

推荐答案

由于数据指针的使用,向VBO的转换可能会有些奇怪.

The transition to the VBO can be a bit strange due to the data pointer usage.

通过快速检查,您的主要问题是

From a quick inspection your main issue is in

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.

So about this buffers: A VBO is a custom buffer on the GPU generally used and optimised to store the vertex data directly to the GPU. The performance you gain by doing so is that the vertex data do not need to be copied to the GPU on every draw call.

这些缓冲区仍然是自定义的,生成它们时,您只需设置它们的大小即可.我看到您在顶点计数上使用因子* 4,假设浮点值的大小为4个字节,但这不是最好的主意,因为这可能并不总是正确的.如果可能,请始终尝试使用某种形式的"sizeOf".无论如何,您的缓冲区都是正确创建的,并且数据已发送到该缓冲区.

These buffers are still custom and on generating them all you need to set is their size. I see you are using factor *4 on the vertex count assuming a float value has a size of 4 bytes, this is not the best idea since that might not always be true. If possible always try to use some form of "sizeOf". Anyway your buffer is created correctly and data are sent to it.

将数据发送到VBO之后,应将其保留在那里,直到需要它们为止.这意味着您通常会为每个唯一对象(例如正方形)创建一个VBO,然后仅保留其ID.每当您希望绘制它时,您只需绑定缓冲区并像您一样绘制即可.换句话说,永远不要在draw方法中创建缓冲区.您所做的操作也存在内存泄漏,因为一旦不再需要缓冲区,您就要通过调用delete来释放缓冲区.

After the data are sent to the VBO you should keep them there until you need them. That means you generally create a single VBO per unique object (a square for instance) and then just hold its ID. Whenever you wish to draw it you just simply bind the buffer and draw as you did. In other words the buffer should never be created in the draw method. What you did there is a memory leak as well since you are responsible for releasing the buffer by calling delete once the buffer is no longer needed.

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

So about your pointer issue on glVertexAttribPointer: There are 2 ways to use this method. Without the VBO the last parameter is the pointer to the data on your CPU. With the VBO you need to set that as a relative pointer inside the VBO. That means when VBO is bound the beginning of the buffer would be NULL (0), you might even need to typecast that value. For other positions in the buffer you need to manually calculate them.

以及您专门发布的代码:

And the code you posted specifically:

    // 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);,此调用的作用是 unbind 缓冲区.这不是您需要执行的操作,但是最好这样做,这样您就不会混淆绑定了什么缓冲区(如果有的话).

This all goes into some load time and have a reference to the buffer[] beside that you should add GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); what this call does is unbind the buffer. This is not something you NEED to do but it is best that you do so you have no confusion what buffer is bound if any.

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

Before the glVertexAttribPointer is called you need to bind your buffer. Then set the last parameter as described above.

使用完此缓冲区(完成绘制)后,您(同样不是必需的)应该解除绑定缓冲区.

After you are done using this buffer (done drawing) you should (again not necessary) unbind the buffer.

这篇关于Android上的OpenGL ES 2:如何使用VBO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆