java - Android 上的 OpenGL ES 3.0 未绘制立方体

标签 java android opengl-es

我想在我的安卓设备上用 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/

相关文章:

java - 渲染 10x10 立方体 openGl 1.0 es

java - 如何将包含指针的 OpenCV-C++ 代码转换为 JAVA?

java - 应用程序中有大量数据

java - Keycloak 用户联盟

android - 使用 FAST 检测可以更快地进行 SURF 描述?

Android 使用键盘上的完成按钮单击按钮

java - Spring Boot中如何实现热插拔(不是自动重启)?

android - 如何将评级栏设置为最低一颗星?

ios - 如何在 iOS 上使用任何技术绘制此效果

iphone - OpenGL ES、OpenFrameworks、Cinder和IOS创意开发