代码之家  ›  专栏  ›  技术社区  ›  user2649681

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

  •  0
  • user2649681  · 技术社区  · 4 年前

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

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

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

    渲染器代码:

    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")
        }
    
    }
    

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

    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]
    

    我包括 <uses-feature android:glEsVersion="0x00020000" android:required="true" /> 在我的清单上。三角形的几何体要么没有呈现在屏幕上,要么不可见,我哪里错了?

    0 回复  |  直到 4 年前
        1
  •  5
  •   ardget    4 年前

    当您创建 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)
    }
    
        2
  •  2
  •   new Q Open Wid    4 年前

    扩展@ardget的答案:字节顺序是ByteBuffer数据的内部顺序,它基本上决定了数据在内存中的存储方式。

    可能有两种“字节顺序”: 小endian 和 大端序 。我在这里不谈太多细节,但big-endian存储从最高有效值到最低有效值的数据,little-endian存储从最低有效值到最高有效值的信息。您的机器有 原生秩序 ,可以是小端序,也可以是大端序。

    当你打电话 ByteBuffer.allocateDirect ,Java自动将字节顺序设置为big-endian。但是当你使用 glBufferData ,(如果我没有弄错的话)OpenGL希望字节顺序是机器的本机顺序。如果本机顺序不是大端序,而是小端序(如在您的机器中),那么问题就会出现。

    您可以通过使用直接将字节顺序指定为本机字节顺序来解决此问题 .order(ByteOrder.nativeOrder()) 。