安卓 OpenGL ES 2.0 VBO
Posted
技术标签:
【中文标题】安卓 OpenGL ES 2.0 VBO【英文标题】:Android OpenGL ES 2.0 VBO 【发布时间】:2014-08-18 13:42:15 【问题描述】:我花了几天时间试图让 VBO 使用 OpenGL ES 2.0 在 android 上工作,但我似乎无法让它工作。
这是我正在使用的代码:
/* The Android shader code */
private static final String[] androidVertexShaderCode = new String[]
"attribute vec4 vertexPosition;",
"void main() ",
" gl_Position = vertexPosition;",
"" ;
private static final String[] androidFragmentShaderCode = new String[]
"precision mediump float;",
"uniform vec4 colour;",
"void main() ",
" gl_FragColor = colour;",
"" ;
/* The Android shader */
public Shader androidShader;
/* The constructor with the render mode and the
* number of vertex values given */
public AndroidRenderer(int renderMode, int vertexValuesCount)
super(renderMode, vertexValuesCount);
//Add this renderer to the list
allRenderers.add(this);
usage = GLES20.GL_STATIC_DRAW;
//Setup the Android shader
this.androidShader = new AndroidShader();
this.androidShader.vertexShader = ShaderUtils.createShader(ArrayUtils.toStringList(androidVertexShaderCode), Shader.VERTEX_SHADER);
this.androidShader.fragmentShader = ShaderUtils.createShader(ArrayUtils.toStringList(androidFragmentShaderCode), Shader.FRAGMENT_SHADER);
this.androidShader.create();
/* The method used to setup the buffers,
* assumes the vertices have already been set */
public void setupBuffers()
//Create the vertices buffer
this.verticesBuffer = BufferUtils.createFlippedBuffer(this.verticesData);
int[] vh = new int[1];
GLES20.glGenBuffers(1, vh, 0);
//Setup the vertices handle
this.verticesHandle = vh[0];
//Bind the vertices buffer and give OpenGL the data
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.verticesHandle);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Float.BYTES * verticesData.length, this.verticesBuffer, this.usage);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
//Check to see whether the normals have been set
if (this.normalsData != null)
//Create the normals buffer
this.normalsBuffer = BufferUtils.createFlippedBuffer(this.normalsData);
int[] nh = new int[1];
GLES20.glGenBuffers(1, nh, 0);
//Setup the normals handle
this.normalsHandle = nh[0];
//Bind the normals buffer and give OpenGL the data
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.normalsHandle);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Float.BYTES * verticesData.length, this.normalsBuffer, this.usage);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
//Check to see whether the colours have been set
if (this.colourData!= null)
//Create the colours buffer
this.coloursBuffer = BufferUtils.createFlippedBuffer(this.colourData);
int[] ch = new int[1];
GLES20.glGenBuffers(1, ch, 0);
//Setup the colours handle
this.coloursHandle = ch[0];
//Bind the colours buffer and give OpenGL the data
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.coloursHandle);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Float.BYTES * colourData.length, this.coloursBuffer, this.usage);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
//Check to see whether the texture coordinates have been set
if (this.textureData != null)
//Create the texture coordinates buffer
this.texturesBuffer = BufferUtils.createFlippedBuffer(this.textureData);
int[] th = new int[1];
GLES20.glGenBuffers(1, th, 0);
//Setup the texture coordinates handle
this.texturesHandle = th[0];
//Bind the texture coordinates buffer and give OpenGL the data
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.texturesHandle);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Float.BYTES * textureData.length, this.texturesBuffer, this.usage);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
/* The method used to draw the object */
public void render()
this.androidShader.use();
short[] indices = new short[this.verticesData.length];
for (short a = 0; a < indices.length; a++)
indices[a] = a;
ShortBuffer indicesBuffer = BufferUtils.createFlippedBuffer(indices);
//Enable the arrays as needed
int vertexPositionAttribute = GLES20.glGetAttribLocation(this.androidShader.program, "vertexPosition");
int normalAttribute = 0;
int colourAttribute = 0;
int texturesAttribute = 0;
GLES20.glEnableVertexAttribArray(vertexPositionAttribute);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.verticesHandle);
GLES20.glVertexAttribPointer(vertexPositionAttribute, this.vertexValuesCount, GLES20.GL_FLOAT, false, 0, 0);
if (this.normalsData != null)
GLES20.glEnableVertexAttribArray(normalAttribute);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.normalsHandle);
GLES20.glVertexAttribPointer(normalAttribute, 2, GLES20.GL_FLOAT, false, 0, 0);
if (this.colourData != null)
colourAttribute = GLES20.glGetAttribLocation(this.androidShader.program, "colour");
Log.d("HELLO", "" + colourAttribute);
GLES20.glEnableVertexAttribArray(colourAttribute);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.coloursHandle);
GLES20.glVertexAttribPointer(colourAttribute, this.colourValuesCount, GLES20.GL_FLOAT, false, 0, 0);
if (this.textureData != null)
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.texturesHandle);
GLES20.glEnableVertexAttribArray(texturesAttribute);
GLES20.glVertexAttribPointer(texturesAttribute, this.textureValuesCount, GLES20.GL_FLOAT, false, 0, 0);
//Draw the arrays
GLES20.glDrawElements(this.renderMode, indices.length, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);
//Disable the arrays as needed
if (this.normalsData != null)
GLES20.glDisableVertexAttribArray(normalAttribute);
if (this.textureData != null)
GLES20.glDisableVertexAttribArray(texturesAttribute);
if (this.colourData != null)
GLES20.glDisableVertexAttribArray(colourAttribute);
GLES20.glDisableVertexAttribArray(vertexPositionAttribute);
this.androidShader.stopUsing();
目前我还没有实现法线或纹理的使用,因为我只是想绘制一个三角形,其中每个顶点都是不同的颜色。我知道着色器应该工作,因为我得到这个工作,使用相同的着色器和顶点/颜色数据只渲染一种颜色。
当我查看 LogCat 时,消息: : GL_INVALID_VALUE 正在被打印出来。然后我决定打印出使用 glGetAttribLocation 找到的 colourAttribute 的值,结果是 -1。经过进一步研究,我发现了这个:https://www.opengl.org/sdk/docs/man/html/glGetAttribLocation.xhtml,它指出返回 -1 的值“如果命名的属性变量不是指定程序对象中的活动属性”。
在谷歌搜索后,我没有找到解决三角形不渲染问题的方法,所以不胜感激。
谢谢。
【问题讨论】:
您确定着色器是否正确编译,并且 colorData 是具有 4 个元素的浮点数组。 是的,colorData 是从 4 个值 (rgba) 生成的,并且着色器之前正在工作,当我使用此处显示的类似方法时:developer.android.com/training/graphics/opengl/draw.html 在 draw 方法中,实际上我复制了来自同一组教程的着色器代码。 【参考方案1】:vertexAttributePointer 方法的步幅始终为 0。这意味着您可以使用颜色值覆盖顶点缓冲区中的顶点位置。
GLES20.glVertexAttribPointer(colourAttribute, this.colourValuesCount, GLES20.GL_FLOAT, false, **0**, 0);
您必须将 stride 增加先前顶点属性大小总和的偏移量。在您的情况 4 中,因为 vertexPosition 向量的 vec4 。 这同样适用于纹理和法线。
看看这里glVertexAttribPointer的定义:http://androidbook.com/akc/display?url=displaynoteimpurl&ownerUserId=android&reportId=4229
此外,您可以尝试为片段着色器添加固定颜色,例如:
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
这样你就避免了 colorHandle 对渲染过程有任何影响。
另外尽量避免一开始使用IndexBuffer而不使用
glDrawElements(.. , ..)
方法只是直接使用带有一个
的vertexBufferObjectglDrawArrays(.., .., )
方法。
如果可行,您当然可以切换回 IndexBuffer 方法。
由于评论而更新
我现在看到另一个问题。您错过了链接着色器并使用 glLinkProgram 和 glUseProgram 启用它。看看这里:Shader for Android OpenGL ES
这篇文章还向您展示了如何输出着色器程序的编译错误。
【讨论】:
我做了你建议的一切,唯一有效的是添加一个固定的颜色,问题是 glGetAttribLocation 返回-1,这是不对的,所以我不认为着色器甚至从程序本身获取颜色。 哇,我刚刚再次检查了 LogCat,现在还有另一个问题 "<1545>1545>以上是关于安卓 OpenGL ES 2.0 VBO的主要内容,如果未能解决你的问题,请参考以下文章
OPENGL ES 3.1是否比OPENGL ES 2.0慢?