OpenGL ES Android:没有使用VBO工作纹理,没有VBO的相同代码工作正常

时间:2014-10-26 04:50:24

标签: android opengl-es vbo

当我不使用VBO时,我有一段显示正确大小和纹理矩形(来自两个三角形)的代码。当我使用VBO时,它在三星平板电脑上没有显示任何内容,并且正确的尺寸矩形但完全有纹理,颜色取自HTC Evo 4G纹理的一个角落像素。

我不知道发生了什么,因为它适用于非VBO的事实某些证明我正确设置了顶点和纹理坐标,我的绘图代码也没问题。我找不到我支持VBO的一小段代码与我在互联网上找到的所有教程和文章有何不同。在我周六花了8个小时后,我决定向比我更聪明的人寻求帮助:)

感谢。

public class TextureShaderProgram extends ShaderProgram {
    private final int uMatrixLocation;
    private final int uTextureUnitLocation;
    // public for performance reasons
    public final int aPositionLocation;
    public final int aTextureCoordinatesLocation;

    public TextureShaderProgram(Resources resources) {
        super(resources, R.raw.texture_vertex_shader, R.raw.texture_fragment_shader);

        uMatrixLocation = glGetUniformLocation(program, U_MATRIX);
        uTextureUnitLocation = glGetUniformLocation(program, U_TEXTURE_UNIT);
        aPositionLocation = glGetAttribLocation(program, A_POSITION);
        aTextureCoordinatesLocation = glGetAttribLocation(program,
            A_TEXTURE_COORDINATES);
    }

    public void setUniforms(float[] matrix, int textureId) {
        glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textureId);
        glUniform1i(uTextureUnitLocation, 0);
    }

}

public class VertexArray {
    private final FloatBuffer floatBuffer;
    public int vboIdx;

    public VertexArray(float[] vertexData) {
        floatBuffer = ByteBuffer.allocateDirect(
            vertexData.length * Constants.BYTES_PER_FLOAT).order(
            ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);
    }

    public void setVertexAttribPointer(int dataOffset, int attributeLocation,
            int componentCount, int stride) {
        floatBuffer.position(dataOffset);
        glVertexAttribPointer(attributeLocation, componentCount,
            GL_FLOAT, false, stride, floatBuffer);
        glEnableVertexAttribArray(attributeLocation);
        floatBuffer.position(0);
    }

    public void generateVBO() {
        int buffers [] = new int [1];
        glGenBuffers(1, buffers, 0);
        if (buffers[0] == 0 ) {
            throw new RuntimeException("error during VBO generation");
        }
        vboIdx = buffers[0];
    }

    public void loadDataToVBO() {
        floatBuffer.position(0);
        glBindBuffer(GL_ARRAY_BUFFER, vboIdx);
        glBufferData(GL_ARRAY_BUFFER, floatBuffer.capacity() * 
            Constants.BYTES_PER_FLOAT, floatBuffer, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

    public void setVertexAttribPointerWithVBO(int dataOffset, int attributeLocation,
            int componentCount, int stride) {
        glBindBuffer(GL_ARRAY_BUFFER, vboIdx);
        glVertexAttribPointer(attributeLocation, componentCount, GL_FLOAT,
        false, stride, dataOffset);
        glEnableVertexAttribArray(attributeLocation);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

    public void clearAndPut(float [] vertexData) {
        floatBuffer.clear();
        floatBuffer.put(vertexData);
    }

}

public class Rect {
    public static final int VERTEXES_SIZE = 24;
    public static final int POSITION_COMPONENT_COUNT = 2;
    public static final int TEXTURE_COORDINATES_COMPONENT_COUNT = 2;
    public static final int STRIDE = (POSITION_COMPONENT_COUNT +         
        TEXTURE_COORDINATES_COMPONENT_COUNT) * Constants.BYTES_PER_FLOAT;

    private boolean reloadVBOs = true;

    private TextureShaderProgram textureProgram = …;

    private float width, height, x1, y1, x2, y2, x3, y3, x4, y4;

    // either VERTEXES_SIZE or VERTEXES_SIZE * number of rects in TextureAtlasRects.
    private float [] vertexes;
    /* This rect part starts at texAtlasOffset if it is a part of TextureAtlasRect.
     * If not this is just always 0 and the rest of the logc is the same
    */
    private int texAtlasOffset; 

    public void initVertexes(TextRectCoords texRectCoords) {
        // upper left triangle
        vertexes[0 + texAtlasOffset] = x1;
        vertexes[1 + texAtlasOffset] = y1;
        vertexes[2 + texAtlasOffset] = texRectCoords.lowerLeftTexX;
        vertexes[3 + texAtlasOffset] = texRectCoords.lowerLeftTexY;
        vertexes[4 + texAtlasOffset] = x3;
        vertexes[5 + texAtlasOffset] = y3;
        vertexes[6 + texAtlasOffset] = texRectCoords.upperRightTexX;
        vertexes[7 + texAtlasOffset] = texRectCoords.upperRightTexY;
        vertexes[8 + texAtlasOffset] = x4;
        vertexes[9 + texAtlasOffset] = y4;
        vertexes[10 + texAtlasOffset] = texRectCoords.upperLeftTexX;
        vertexes[11 + texAtlasOffset] = texRectCoords.upperLeftTexY;
        // lower right triangle
        vertexes[12 + texAtlasOffset] = x1;
        vertexes[13 + texAtlasOffset] = y1;
        vertexes[14 + texAtlasOffset] = texRectCoords.lowerLeftTexX;
        vertexes[15 + texAtlasOffset] = texRectCoords.lowerLeftTexY;
        vertexes[16 + texAtlasOffset] = x2;
        vertexes[17 + texAtlasOffset] = y2;
        vertexes[18 + texAtlasOffset] = texRectCoords.lowerRightTexX;
        vertexes[19 + texAtlasOffset] = texRectCoords.lowerRightTexY;
        vertexes[20 + texAtlasOffset] = x3;
        vertexes[21 + texAtlasOffset] = y3;
        vertexes[22 + texAtlasOffset] = texRectCoords.upperRightTexX;
        vertexes[23 + texAtlasOffset] = texRectCoords.upperRightTexY;
    }

    private void initVertexArray(TextRectCoords texRectCoords) {
        initAndReturnVertexes(texRectCoords);

        if (vertexArray != null) {
            vertexArray.clearAndPut(vertexes);
        } else {
            vertexArray = new VertexArray(vertexes);
        }
    }

    private void bindData(TextureShaderProgram textureProgram, boolean useVBO) {
        if (! useVBO) {
            vertexArray.setVertexAttribPointer(0, textureProgram.aPositionLocation,
                POSITION_COMPONENT_COUNT, STRIDE);
            vertexArray.setVertexAttribPointer(POSITION_COMPONENT_COUNT,
                textureProgram.aTextureCoordinatesLocation,
                TEXTURE_COORDINATES_COMPONENT_COUNT, STRIDE);
            } else {
                if (reloadVBOs) {
                    vertexArray.generateVBO();
                    vertexArray.loadDataToVBO();
                    reloadVBOs = false;
                }
                vertexArray.setVertexAttribPointerWithVBO(0, 
                    textureProgram.aPositionLocation, 
                    POSITION_COMPONENT_COUNT, STRIDE);
                vertexArray.setVertexAttribPointerWithVBO(POSITION_COMPONENT_COUNT,
                    textureProgram.aTextureCoordinatesLocation, 
                    TEXTURE_COORDINATES_COMPONENT_COUNT, STRIDE);           
            }
        }
    }

    private void draw(TextureAndSize texture, TextRectCoords texRectCoords,
        boolean willEverChange) {

        textureProgram.setUniforms(projectionMatrix, texture.getTextureId());

        if (vertexArray == null || willEverChange) {
            initVertexArray(texRectCoords);
        }

        /* if the second argument below if false, then I do not use VBO and
         * everything works. If true then I use VBO and I get no rect at all
         * on Samsung Galaxy Tab S and the correct dimension rect but textured with
         * a single color, taken from one of the one pixels in the corners of the
         * texture, on HTC Evo 4G.
         */
        bindData(textureProgram, false);

        glDrawArrays(GL_TRIANGLES, 0, 6);
    }
}

1 个答案:

答案 0 :(得分:1)

代码中存在一个问题,其偏移作为glVertexAttribPointer()的最后一个参数传递。电话来自这个方法:

public void setVertexAttribPointerWithVBO(int dataOffset, int attributeLocation,
        int componentCount, int stride) {
    ...
    glVertexAttribPointer(attributeLocation, componentCount, GL_FLOAT,
                          false, stride, dataOffset);
    ...
}

这就是这样称呼的:

public static final int POSITION_COMPONENT_COUNT = 2;
...
vertexArray.setVertexAttribPointerWithVBO(POSITION_COMPONENT_COUNT,
        textureProgram.aTextureCoordinatesLocation, 
        TEXTURE_COORDINATES_COMPONENT_COUNT, STRIDE);           

基于此,为glVertexAttribPointer()的最后一个参数传递值2。此参数需要偏移以字节为单位,而传入的值是浮点数。所以它需要乘以浮点数。

使用其余代码,最简单的添加方法是在方法中:

public void setVertexAttribPointerWithVBO(int dataOffset, int attributeLocation,
        int componentCount, int stride) {
    ...
    glVertexAttribPointer(attributeLocation, componentCount, GL_FLOAT,
                          false, stride, dataOffset * Constants.BYTES_PER_FLOAT);
    ...
}