我想在我的安卓设备上用 opengl es 3.0 渲染一个简单的立方体,但它没有渲染。这是我的 SurfaceView 设置:
public GLContextView(Context context){
super(context);
setEGLContextClientVersion(3);
setRenderer(renderer);
}
渲染代码:
public void onSurfaceCreated(javax.microedition.khronos.opengles.GL10 unused, javax.microedition.khronos.egl.EGLConfig p2){
GLES30.glEnable(GLES30.GL_DEPTH_TEST);
GLES30.glEnable(GLES30.GL_BLEND);
GLES30.glEnable(GLES30.GL_CULL_FACE);
GLES30.glDepthFunc(GLES30.GL_LEQUAL);
GLES30.glCullFace(GLES30.GL_BACK);
GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
cubeProgram = RenderHelper.createShaderProgram(Shader.CubeVertexShader, Shader.CubeFragmentShader);
int[] array = new int[2];
GLES30.glGenVertexArrays(1, array, 0);
vaId = array[0];
GLES30.glBindVertexArray(vaId);
GLES30.glGenBuffers(2, array, 0);
vbId = array[0];
ibId = array[1];
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbId);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, RenderCube.vertices.length * 4, RenderCube.vBuffer, GLES30.GL_STATIC_DRAW);
GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, 0);
GLES30.glEnableVertexAttribArray(positionHandle);
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, ibId);
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, RenderCube.indices.length * 4, RenderCube.iBuffer, GLES30.GL_STATIC_DRAW);
colorHandle = GLES30.glGetUniformLocation(cubeProgram, "in_color");
GLES30.glBindVertexArray(0);
}
public void onDrawFrame(GL10 p1){
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
GLES30.glUseProgram(cubeProgram);
GLES30.glBindVertexArray(vaId);
GLES30.glUniform4f(colorHandle, 1.0f, 1.0f, 1.0f, 1.0f);
GLES30.glDrawElements(GLES30.GL_TRIANGLES, RenderCube.indices.length, GLES30.GL_UNSIGNED_INT, 0);
}
public void onSurfaceChanged(GL10 p1, int p2, int p3){
GLES30.glViewport(0, 0, p2, p3);
}
带有顶点和索引数据的 RenderCube 类:
class RenderCube{
public static float[] vertices = {
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
};
public static int[] indices = {
0, 3, 1, 0, 2, 3, //Bottom
4, 7, 5, 4, 6, 7, //Top
0, 5, 1, 0, 4, 5, //Back
2, 7, 3, 2, 6, 7, //Front
0, 6, 2, 0, 4, 6, //Left
1, 7, 3, 1, 5, 7 //Right
};
public static FloatBuffer vBuffer = RenderHelper.createFloatBuffer(vertices.length * 4, vertices);
public static IntBuffer iBuffer = RenderHelper.createIntBuffer(indices.length * 4, indices);
};
着色器:
final class Shader{
public static final String CubeVertexShader =
"#version 300 es\n" +
"layout (location = 0) in vec3 pos;" +
"void main(){" +
" gl_Position = vec4(pos, 1.0f);" +
"}";
public static final String CubeFragmentShader =
"#version 300 es\n" +
"precision mediump float;" +
"uniform vec4 in_color;" +
"out vec4 color;" +
"void main(){" +
" color = in_color;" +
"}";
}
编译正常,没有打印 opengl 错误。我做错了什么?
最佳答案
我认为你根本没有可见的三角形。
底面、顶面、左面和右面的三角形是不可见的,因为它们与观察平面正交。所以你从边缘看它们,它们最终变成退化的三角形(即面积为零的三角形)。
按照你定义的方式,背面和正面的三角形都是顺时针方向的。展开这 4 个三角形的索引,并仅显示相应顶点的 x 和 y 坐标:
0, 5, 1 -> (0.0f, 0.0f), (1.0f, 1.0f), (1.0f, 0.0f)
0, 4, 5 -> (0.0f, 0.0f), (0.0f, 1.0f), (1.0f, 1.0f)
2, 7, 3 -> (0.0f, 0.0f), (1.0f, 1.0f), (1.0f, 0.0f)
2, 6, 7 -> (0.0f, 0.0f), (0.0f, 1.0f), (1.0f, 1.0f)
如您所见,这些三角形都是顺时针方向的。由于您选择启用背面剔除:
GLES30.glEnable(GLES30.GL_CULL_FACE);
GLES30.glCullFace(GLES30.GL_BACK);
并且正面的默认缠绕顺序是逆时针的,这意味着背面的缠绕是顺时针的,所有这些三角形都将被剔除。
此外,由于正面在 z = 1.0 处,它也恰好位于前裁剪平面上。按照我阅读规范的方式,恰好位于裁剪平面上的几何体应该仍然可见。但将它清楚地放在剪辑体积内可能更安全。
关于java - Android 上的 OpenGL ES 3.0 未绘制立方体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38532904/