在 Android OpenGL ES 上只能看到 glClear 颜色,没有几何图形

use*_*681 2 android opengl-es kotlin

我正在尝试编写一个非常简单的 Android 应用程序,它使用 OpenGL 显示绿色背景并在其上渲染单个青色三角形,以验证我的代码是否正确显示某些几何图形。我遇到了一个问题,即对glClearColor/glClear设置背景的调用可见并使视图按预期变为绿色,但glDrawArrays在将第 0 个属性数组指向包含FloatBuffer顶点坐标后的调用没有看到明显的变化。我的顶点着色器所做的就是将位置作为 avec4传递给片段着色器,片段着色器总是将输出颜色设置为青色,因此我希望看到带有一个青色三角形的绿色视图,但我只看到绿色背景,并且我不确定为什么。

主要活动文件(省略导入):

setupDefaultProgram()
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        GLES30.glViewport(0, 0, width, height)
    }

    override fun onDrawFrame(gl: GL10?) {
        glRenderer.renderFunc()
    }

}
Run Code Online (Sandbox Code Playgroud)

渲染器代码:

class GlRenderer {

    companion object {
        // Pass through position and UV values
        val vertexSource = """
            #version 300 es
            
            in vec2 position;
            
            void main() {
                gl_Position = vec4(position, -0.5, 1.0);
            }
        """.trimIndent()

        // Eventually get the texture value, for now, just make it cyan so I can see it
        val fragmentSource = """
            #version 300 es
            precision mediump float;
            
            out vec4 fragColor;
            
            void main() {
                fragColor = vec4(0.0, 1.0, 1.0, 1.0);
            }
        """.trimIndent()
    }

    private var vertexBuffer: FloatBuffer

    private var defaultProgram: Int = -1
    private var vertexLocation: Int = -1

    private fun checkGlError(msg: String) {
        val errCodeEgl = EGL14.eglGetError()
        val errCodeGl = GLES30.glGetError()
        if (errCodeEgl != EGL14.EGL_SUCCESS || errCodeGl != GLES30.GL_NO_ERROR) {
            throw RuntimeException(
                "$msg - $errCodeEgl(${GLU.gluErrorString(errCodeEgl)}) : $errCodeGl(${
                    GLU.gluErrorString(
                        errCodeGl
                    )
                })"
            )
        }
    }

    init {
        // Flat square
        // Am I allocating and writing to these correctly?
        val vertices = floatArrayOf(-1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f)
        vertexBuffer = ByteBuffer.allocateDirect(vertices.size * 4).asFloatBuffer().also {
            it.put(vertices)
            it.position(0)
        }
    }

    fun setupDefaultProgram() {
        defaultProgram = makeProgram(
        mapOf(
            GLES30.GL_VERTEX_SHADER to vertexSource,
            GLES30.GL_FRAGMENT_SHADER to fragmentSource
            )
        )
        vertexLocation = GLES30.glGetAttribLocation(defaultProgram, "position")
        checkGlError("Getting uniform")
    }

    private fun compileShader(source: String, shaderType: Int): Int {
        val shaderId = GLES30.glCreateShader(shaderType)
        checkGlError("Create shader")
        if (shaderId == 0) {
            Log.e("Native", "Could not create shader for some reason")
            checkGlError("Could not create shader")
        }
        GLES30.glShaderSource(shaderId, source)
        checkGlError("Setting shader source")
        GLES30.glCompileShader(shaderId)
        val statusBuffer = IntArray(1)
        GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, statusBuffer, 0)
        val shaderLog = GLES30.glGetShaderInfoLog(shaderId)
        Log.d("Native", "Compiling shader #$shaderId : $shaderLog")

        if (statusBuffer[0] == 0) {
            GLES30.glDeleteShader(shaderId)
            checkGlError("Failed to compile shader $shaderId")
        }
        return shaderId
    }

    private fun makeProgram(sources: Map<Int, String>): Int {
        val program = GLES30.glCreateProgram()
        checkGlError("Create program")
        sources.forEach {
            val shader = compileShader(it.value, it.key)
            GLES30.glAttachShader(program, shader)
        }
        val linkBuffer = IntArray(1)
        GLES30.glLinkProgram(program)
        GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkBuffer, 0)
        if (linkBuffer[0] == 0) {
            GLES30.glDeleteProgram(program)
            checkGlError("Failed to link program $program")
        }
        return program
    }

    // Called to actually draw to the surface. When fully implemented it should draw whatever is
    // on the associated texture, but for now, to debug, I just want to verify I can draw vertices,
    // but it seems I cannot?
    fun renderFunc() {
        GLES30.glClearColor(0f, 1f, 0.5f, 1f)
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
        checkGlError("Clearing")

        GLES30.glUseProgram(defaultProgram)
        checkGlError("Use program")

        GLES30.glEnableVertexAttribArray(vertexLocation)
        vertexBuffer.position(0)
        FloatArray(2 * 4).apply {
            vertexBuffer.get(this)
            vertexBuffer.position(0)
            Log.d("Native", "Vertex buffer ${contentToString()}")
        }
        GLES30.glVertexAttribPointer(vertexLocation, 2, GLES30.GL_FLOAT, false, 0, vertexBuffer)
        checkGlError("Attribute 0")

        // Just render a triangle
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3)

        GLES30.glFinish()
        checkGlError("Finished GL")
    }

}
Run Code Online (Sandbox Code Playgroud)

我的调试输出记录了我所期望的内容:

D/Native: Compiling shader #2 : 
D/Native: Compiling shader #3 : 
D/Native: Vertex buffer [-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0]
Run Code Online (Sandbox Code Playgroud)

我将其包含<uses-feature android:glEsVersion="0x00020000" android:required="true" />在我的清单中。我哪里出错了,三角形的几何形状要么没有渲染到屏幕上,要么不可见?

小智 5

当您Buffer为 GL 创建时,您需要指定native byte-order.

val vertices = floatArrayOf(-1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f)
vertexBuffer = ByteBuffer.allocateDirect(vertices.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().also {
    it.put(vertices)
    it.position(0)
}
Run Code Online (Sandbox Code Playgroud)