Шейдеры компилируются и связываются без ошибок, но текстуры все еще не видны - PullRequest
1 голос
/ 01 июня 2019

Я хотел бы отобразить очень простую текстуру в GLSurfaceView, которая охватывает весь видовой экран.У меня отлично работает версия в WebGL, но по какой-то причине мой код Android не отображает мою текстуру (вообще).

Пытался жестко закодировать цвет во фрагментном шейдере, игнорировать текстуру, но ничегоизменилось ... может быть, шейдеры вообще не применяются?

    private fun loadShader(shaderType: Int, source: String): Int {
        var shader = GLES20.glCreateShader(shaderType)
        if (shader != 0) {
            GLES20.glShaderSource(shader, source)
            GLES20.glCompileShader(shader)
            val compiled = IntArray(1)
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0)
            if (compiled[0] == 0) {
                Log.e(TAG, "Could not compile shader $shaderType:")
                Log.e(TAG, GLES20.glGetShaderInfoLog(shader))
                GLES20.glDeleteShader(shader)
                shader = 0
            } else{
                Log.e(TAG, "Shader $shaderType compiled!")
                Log.e(TAG, GLES20.glGetShaderInfoLog(shader))
            }
        }
        return shader
    }

    private fun createProgram(vertexSource: String, fragmentSource: String): Int {
        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource)
        if (vertexShader == 0) {
            return 0
        }
        val pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource)
        if (pixelShader == 0) {
            return 0
        }

        var program = GLES20.glCreateProgram()
        if (program != 0) {
            GLES20.glAttachShader(program, vertexShader)
            checkGlError("glAttachShader")
            GLES20.glAttachShader(program, pixelShader)
            checkGlError("glAttachShader")
            GLES20.glLinkProgram(program)
            val linkStatus = IntArray(1)
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0)
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Log.e(TAG, "Could not link program: ")
                Log.e(TAG, GLES20.glGetProgramInfoLog(program))
                GLES20.glDeleteProgram(program)
                program = 0
            } else {
                Log.e(TAG, "Shader Program Linked!")
            }
        }
        return program
    }

    private fun checkGlError(op: String) {
        val error: Int = GLES20.glGetError()
        while (error  != GLES20.GL_NO_ERROR) {
            Log.e(TAG, "$op: glError $error")
            throw RuntimeException("$op: glError $error")
        }
    }

    private fun initGL (side:Int) {

        /*======== Defining and storing the geometry ===========*/

        val verticesData = floatArrayOf(
                -1.0f,1.0f,0.0f,
                -1.0f,-1.0f,0.0f,
                1.0f,-1.0f,0.0f,
                1.0f,1.0f,0.0f
        )

        val indicesData = shortArrayOf(0,1,2,0,3,2)

        val vertexBuffer : FloatBuffer = ByteBuffer.allocateDirect(verticesData.size * 4)
            .order(ByteOrder.nativeOrder()).asFloatBuffer()
        vertexBuffer.put(verticesData).position(0)

        val indexBuffer : ShortBuffer = ByteBuffer.allocateDirect(indicesData.size * 2).order(ByteOrder.nativeOrder())
            .asShortBuffer()
        indexBuffer.put(indicesData).position(0)

        val buffers = IntArray(2)
        GLES20.glGenBuffers(2, buffers, 0)
        val vbo = buffers[0]
        val ibo = buffers[1]

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo)
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
            vertexBuffer.capacity() * 4, // 4 = bytes per float
            vertexBuffer,
            GLES20.GL_STATIC_DRAW)
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0)

        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo)
        GLES20.glBufferData(
            GLES20.GL_ELEMENT_ARRAY_BUFFER,
            indexBuffer.capacity() * 2, // 2 = bytes per short
            indexBuffer,
            GLES20.GL_STATIC_DRAW)
        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0)

        /*================ Shaders ====================*/

        // Vertex shader source code
        val vertCode =
        """
        attribute vec3 coordinates;

        void main(void) {
            gl_Position = vec4(coordinates, 1.0);
        }
        """

        //fragment shader source code
        val fragCode =
        """
        precision mediump float;

        // The texture.
        uniform sampler2D u_tex;

        void main(void) {
            vec4 color = texture2D(u_tex, vec2(gl_FragCoord.x/$side.0, gl_FragCoord.y/$side.0));
            gl_FragColor = color;
        }
        """

        // Create a shader program object to store
        // the combined shader program
        val shaderProgram = createProgram(vertCode, fragCode)

        // Use the combined shader program object
        GLES20.glUseProgram(shaderProgram)

        /*======= Associating shaders to buffer objects =======*/

        // Bind vertex buffer object
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo)

        // Bind index buffer object
        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo)

        // Get the attribute location
        val coord = GLES20.glGetAttribLocation(shaderProgram, "coordinates")

        // Point an attribute to the currently bound VBO
        GLES20.glVertexAttribPointer(coord, 3, GLES20.GL_FLOAT, false, 0,0)

        // Enable the attribute
        GLES20.glEnableVertexAttribArray(coord)
    }

    private fun updateGLCanvas (matrix : ByteArray, side : Int) {
        val textureImage = floatArrayOf(
            0f,0f,0f,
            1f,0f,0f,
            0f,0f,1f,
            1f,1f,0f
        )
        val textureImageBuffer : FloatBuffer = ByteBuffer.allocateDirect(textureImage.size * 4)
            .order(ByteOrder.nativeOrder()).asFloatBuffer()
        textureImageBuffer.put(textureImage).position(0)

        val texArray = IntArray(1)
        GLES20.glGenTextures(1,texArray,0)
        val textureId = texArray[0]
        if (texArray[0]==0) Log.e(TAG, "Error with Texture!")
        else Log.e(TAG, "Texture id $textureId created!")

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST)

        //TODO: Flip Y axis!!!
        //gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
        GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT,1)

        //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, side, side, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array(matrix));
        //TODO: change 2 to parameter 'side'
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,GLES20.GL_RGB, 2, 2, 0, GLES20.GL_RGB, GLES20.GL_FLOAT, textureImageBuffer)

        // Clear the canvas
        GLES20.glClearColor(1f,0.5f,0.5f,0.9f)

        // Enable the depth test
        GLES20.glEnable(GLES20.GL_DEPTH_TEST)

        // Clear the color buffer bit
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)

        // Set the view port
        //TODO: set proper canvas dimensions
        GLES20.glViewport(0,0,500,500)

        // Draw the triangle
        GLES20.glDrawElements(GLES20.GL_TRIANGLES,6, GLES20.GL_UNSIGNED_SHORT,0)
    }

Шейдеры компилируются и связываются без ошибок.Код работает без проблем, но единственное, что показывает, это мой довольно розовый фон.Тестовый код должен отображать текстуру моего пикселя [2x2] ... но по какой-то причине он отказывается делать что-либо значимое.

1 Ответ

0 голосов
/ 04 июня 2019

Что ж, похоже, у этого кода было много недостатков ... по какой-то причине openGL ES2 не понравился мой буфер массива элементов, поэтому я отказался от него. Тогда

GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,GLES20.GL_RGB, 2, 2, 0, GLES20.GL_RGB, GLES20.GL_FLOAT, textureImageBuffer)

оказалось хорошо для эмулятора, но на реальном устройстве с использованием GLES20.GL_FLOAT вызвал изжогу ... изменение его на GL_UNSIGNED_BYTE решило проблему!

...