当我不使用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);
}
}
答案 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);
...
}