OpenGL ES Android:不使用VBOs处理纹理,在没有VBOs的情况下使用相同的代码可以很好地工作

OpenGL ES Android:不使用VBOs处理纹理,在没有VBOs的情况下使用相同的代码可以很好地工作,android,opengl-es,vbo,Android,Opengl Es,Vbo,我有一段代码,当我不使用VBO时,它会显示一个大小和纹理正确的矩形(来自两个三角形)。当我使用VBO时,它在三星平板电脑上不显示任何内容,并且是一个适当的尺寸矩形,但纹理完全采用了HTC Evo 4G上纹理的一个角像素的颜色 我不知道发生了什么,因为它对非VBO工作的事实某种程度上证明了我正确设置了顶点和纹理坐标,我的绘图代码也正常。我找不到我启用VBO的一小段代码与我在Internet上找到的所有教程和文章有什么不同。在周六花了8个小时的时间之后,我决定向比我聪明的人寻求帮助:) 谢谢 pub

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

我不知道发生了什么,因为它对非VBO工作的事实某种程度上证明了我正确设置了顶点和纹理坐标,我的绘图代码也正常。我找不到我启用VBO的一小段代码与我在Internet上找到的所有教程和文章有什么不同。在周六花了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);
    }
}

作为
glvertexattributepointer()
的最后一个参数传递的偏移量在代码中有问题。调用来自此方法:

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

你是对的。非常感谢,我应该在7小时前问你:)