OpenGL ES 2.0 vbo 白屏

Posted

技术标签:

【中文标题】OpenGL ES 2.0 vbo 白屏【英文标题】:OpenGL ES 2.0 vbo white screen 【发布时间】:2013-04-22 19:23:28 【问题描述】:

我一直在尝试让我的游戏引擎在 android 上运行,但我遇到了顶点缓冲区数组。它使用 FloatBuffer 工作,但是当我尝试使用 VBO 进行渲染时,我只得到一个白屏。所以我想知道我的代码是否有问题。

这就是我创建 VBO 的方式:

private int[] vbo = new int[1];
private int[] ibo = new int[1];

private void setUpVBO()

    short drawOrder[] =  0, 1, 2, 0, 2, 3 ; // order to draw vertices
    float TextureCoords[] = 
     
    0.0f, 0.0f,   // bottom left
    0.0f, 1.0f,   // top left
    1.0f, 1.0f, // top right
    1.0f, 0.0f,   // bottom right
    ;
    float squareCoords[] =  
                -width / 2.f - 0.015f / 2.f,  height / 2.f + 0.015f / 2.f, 0.0f,   // top left
                -width / 2.f - 0.015f / 2.f, -height / 2.f - 0.015f / 2.f, 0.0f,   // bottom left
                 width / 2.f + 0.015f / 2.f, -height / 2.f - 0.015f / 2.f, 0.0f,   // bottom right
                 width / 2.f + 0.015f / 2.f,  height / 2.f + 0.015f / 2.f, 0.0f ; // top right
        ByteBuffer bb = ByteBuffer.allocateDirect(bb.order(ByteOrder.nativeOrder());
        bb.order(ByteOrder.nativeOrder());
        FloatBuffer vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(squareCoords);
        vertexBuffer.position(0);

        // initialize vertex byte buffer for shape coordinates
        ByteBuffer tc = ByteBuffer.allocateDirect(TextureCoords.length * 4);
        tc.order(ByteOrder.nativeOrder());
        FloatBuffer TextureCoordinateBuffer = tc.asFloatBuffer();
        TextureCoordinateBuffer.put(TextureCoords);
        TextureCoordinateBuffer.position(0);


        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        ShortBuffer drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);


        GLES20.glGenBuffers(1, vbo, 0);
        GLES20.glGenBuffers(1, ibo, 0);

        if (vbo[0] > 0 && ibo[0] > 0) 
        
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
            GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4,
                    vertexBuffer, GLES20.GL_STATIC_DRAW);

            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
            GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, TextureCoordinateBuffer.capacity() * 4,
                    TextureCoordinateBuffer, GLES20.GL_DYNAMIC_DRAW);


            GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
            GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, drawListBuffer.capacity()
                    * 2, drawListBuffer, GLES20.GL_STATIC_DRAW);

            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
            GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
    

这就是我的渲染方式:

public void render(float[] mMVPMatrix) 
       
    if (vbo[0] > 0 && ibo[0] > 0) 
    
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);

        GLES20.glEnableVertexAttribArray(Values.mPositionHandle);
        GLES20.glVertexAttribPointer(Values.mPositionHandle, Values.COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                Values.fullStride, 0);


        GLES20.glEnableVertexAttribArray(Values.mTextureCoordinateHandle);
        GLES20.glVertexAttribPointer(Values.mTextureCoordinateHandle, Values.COORDS_PER_VERTEX_TEXTURE, 
                GLES20.GL_FLOAT, false,
                Values.fullStride, 0);


        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureOfBody); 
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
        GLES20.glUniform1i(Values.mTheActualTexture, 0);


    GLES20.glUniform4fv(Values.mColorHandle, 1, colorOfBody, 0);


        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(Values.mMVPMatrixHandle, 1, false, mMVPMatrix, 0);

        // Draw the square
        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
        GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, 0);

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(Values.mTextureCoordinateHandle);
        GLES20.glDisableVertexAttribArray(Values.mPositionHandle);


        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
    

着色器已正确加载。这是我的着色器:

顶点:

    uniform mat4 uMVPMatrix;
    attribute vec4 vPosition;
    attribute vec2 TexCoordinate;
    varying vec2 TexCoordinateGLFS;

    void main()
    
        TexCoordinateGLFS = TexCoordinate;

        gl_Position = uMVPMatrix * newPosition ;
    

片段:

    precision mediump float;
    uniform sampler2D theActualTexture;
    uniform vec4 vColor;
    varying vec2 TexCoordinateGLFS;

    void main() 
    
        gl_FragColor = texture2D(theActualTexture, TexCoordinateGLFS) * vColor;
    

一些变量:

public static final int COORDS_PER_VERTEX = 3;
public static final int COORDS_PER_VERTEX_TEXTURE = 2;

public static final int vertexStride = COORDS_PER_VERTEX * 4;
public static final int textureStride = COORDS_PER_VERTEX_TEXTURE * 4;
public static final int fullStride = (COORDS_PER_VERTEX + COORDS_PER_VERTEX_TEXTURE) * 4;

编辑: 这是新的 VBO 结构:

    ByteBuffer bb = ByteBuffer.allocateDirect((squareCoords.length + TextureCoords.length) * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(squareCoords);
        vertexBuffer.put(TextureCoords);
        vertexBuffer.position(0);


GLES20.glGenBuffers(1, vbo, 0);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexBuffer.capacity() * BYTES_PER_FLOAT,
                    vertexBuffer, GLES20.GL_DYNAMIC_DRAW);

我在这里画:

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

        GLES20.glVertexAttribPointer(Values.mTextureCoordinateHandle, Values.COORDS_PER_VERTEX_TEXTURE, 
                GLES20.GL_FLOAT, false,
                Values.textureStride, squareCoords.length);

squareCoords.length == 12; (每个顶点 3 个坐标 (x, y, z) -> 4 * 3 = 12)

【问题讨论】:

这看起来很讨厌ByteBuffer.allocateDirect(bb.order(ByteOrder.nativeOrder()),你应该改用字节大小吗? 好吧...在添加 vbo 之前它工作正常,所以我认为问题不存在。我唯一改变的是:添加 vbo,并在渲染类中:bindBuffer。一切都变了。 哦,我并不完全期望这能解决问题,但更惊讶的是它完全可以编译 :) 【参考方案1】:

从您发布的代码看来,您似乎用纹理坐标覆盖了您的位置坐标。通常,您需要与数组一样多的缓冲区,因此在您的情况下,您需要一个单独的纹理坐标缓冲区。一个更优雅的解决方案是将提到的 2 个数组合并为 1 个交错数组,将其推送到单个 VBO,并在设置顶点和纹理坐标指针时使用步幅。

这是绝对不行的:

GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);

GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, TextureCoordinateBuffer.capacity() * 4, TextureCoordinateBuffer, GLES20.GL_DYNAMIC_DRAW);

当您绑定相同的缓冲区两次并将数据推送到 GPU 时,最后剩下的就是纹理坐标(实际上,代码可能会根据您的矩阵在屏幕上的某处生成单个像素图像)

【讨论】:

我知道这会更优雅,但我真的不知道如何在 java 中做到这一点。在我用 C++ 编写的桌面版本中,我刚刚创建了一个包含所有信息的结构,之后我只调用“4 * sizeof(dataBuffer)”。也许如果你能给出一些提示。顺便说一句,我尝试使用 2 个缓冲区,它就像一个魅力,只是看到三角形而不是正方形。我更改的是:glGenBuffers(2, vbo, 0) 和:glBindBuffer(gl_array_buffer, vbo[0]) - 用于顶点,vbo[1] 用于纹理坐标,我在创建 vbo 和渲染时进行了更改 那么在您的情况下,您可以创建 1 个具有交错坐标的浮点数组并将其放入 1 个 VBO,设置步幅。或者您可以将两个数组放入 1 字节缓冲区,将其放入单个 VBO 并为第二个设置偏移量。您也可以创建一些顶点对象并使用它或多或少与 c++ 中的相同。至于三角形问题,您似乎有一个奇怪的索引和三角形条组合。您将 6 个索引与三角形带一起使用,从而形成 4 个三角形。不使用索引或设置三角形(无条) 我从三角形条带更改为三角形扇形,现在它适用于 2 个 vbo,但我仍在尝试将顶点和纹理坐标放在同一个 vbo 中,但我无法获得偏移量适合纹理坐标。对象被绘制在它们应该在的位置,但是纹理被打乱了,这让我觉得它没有得到正确的纹理坐标。我用新添加的代码进行了编辑。 顺便说一句,android opengl es 2.0中有顶点数组对象吗?我在网上搜索,发现只适用于 ios。如果有的话,你能给我指个教程吗? 好吧,偏移量可能必须以字节为单位,所以尝试 length*4 那里(如 4 = sizeof(float))。抱歉,我不知道如何在 android 上制作 VAO。

以上是关于OpenGL ES 2.0 vbo 白屏的主要内容,如果未能解决你的问题,请参考以下文章

安卓 OpenGL ES 2.0 VBO

OpenGL ES 2.0 VBO 问题

共享内存架构中的 OpenGL (ES 2.0) VBO 性能

OpenGL ES 2.0:似乎无法渲染第二个 VBO?

iOS OpenGL ES 2.0 VBO 混淆

在 Android 上的 OpenGL ES 2.0 中使用 VBO/IBO