Search code examples
androidkotlinshaderglslesopengl-es-3.0

OpenGL ES 3.0 / GLSL not rendering data (Kotlin)


I am trying to implement a basic shading program with OpenGL ES 3.0, and have pieced together this code from various tutorials. Everything looks correct to me, and it compiles fine, but nothing appears on my screen.

It rendered fine until I added Normal and Light Position data, then it broke and I haven't been able to find a way to fix it.

Can anyone see what's wrong here?

import android.opengl.GLES30.*
import android.opengl.GLSurfaceView.Renderer
import android.opengl.Matrix.*
import java.nio.*
import java.nio.ByteBuffer.allocateDirect
import java.nio.ByteOrder.nativeOrder
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class GLRenderer:Renderer{
    lateinit var vBuf: FloatBuffer
    lateinit var nBuf: FloatBuffer
    var glProgram = -1
    var uMV       = -1
    var uMVP      = -1
    var uLightPos = -1
    val aPosition =  0
    val aNormal   =  1
    val aColor    =  2
    val modelM = FloatArray(16)
    val viewM  = FloatArray(16)
    val projM  = FloatArray(16)
    val mvM    = FloatArray(16)
    val mvpM   = FloatArray(16)
    val lPos   = FloatArray(4)
    val lightPos = floatArrayOf(0f,10f,0f,1f)

    override fun onSurfaceCreated(g:GL10,c:EGLConfig) {
        glClearColor(0f,0f,0f,1f)
        setLookAtM(viewM,0,0f,0f,5f,0f,0f,0f,0f,1f,0f)

        val vShader = glCreateShader(GL_VERTEX_SHADER)
        val fShader = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(vShader,"#version 300 es\n" +
            " uniform mat4 u_mvpM;                              " +
            " uniform mat4 u_mvM;                               " +
            " layout(location=0) in vec4 aPos;                  " +
            " layout(location=1) in vec4 aCol;                  " +
            " layout(location=2) in vec3 aNorm;                 " +
            " out vec3 vPos;                                    " +
            " out vec4 vCol;                                    " +
            " out vec3 vNorm;                                   " +
            " void main(){                                      " +
            "   vPos        = vec3(u_mvM * aPos);               " +
            "   vCol        = aCol;                             " +
            "   vNorm       = vec3(u_mvM * vec4(aNorm,0.0));    " +
            "   gl_Position = u_mvpM * aPos;}                   " )
        glShaderSource(fShader,"#version 300 es\n" +
            " precision mediump float;                          " +
            " uniform vec3 u_LightPos;                          " +
            " in  vec3 vPos;                                    " +
            " in  vec4 vCol;                                    " +
            " in  vec3 vNorm;                                   " +
            " out vec4 fColor;                                  " +
            " void main(){                                      " +
            "   float distance = length(u_LightPos - vPos);     " +
            "   vec3  lightPos = normalize(u_LightPos - vPos);  " +
            "   float diffuse  = max(dot(vNorm,lightPos),0.1)/  " +
            "                    (distance*distance/4.0 + 1.0); " +
            "   fColor         = vCol * diffuse;}               " )
        glCompileShader(vShader)
        glCompileShader(fShader)
        glProgram = glCreateProgram()
        glAttachShader(glProgram,vShader)
        glAttachShader(glProgram,fShader)
        glLinkProgram(glProgram)
        glUseProgram(glProgram)
        uMV       = glGetUniformLocation(glProgram,"u_mvM")
        uMVP      = glGetUniformLocation(glProgram,"u_mvpM")
        uLightPos = glGetUniformLocation(glProgram,"u_LightPos")

        vBuf = allocateDirect(9*4).order(nativeOrder()).asFloatBuffer().put(floatArrayOf(
               0f,1f,0f, -1f,0f,0f, 1f,0f,0f))
        nBuf = allocateDirect(9*4).order(nativeOrder()).asFloatBuffer().put(floatArrayOf(
               0f,0f,-1f, 0f,0f,-1f, 0f,0f,-1f))
        vBuf.position(0)
        nBuf.position(0)
    }
    override fun onSurfaceChanged(g:GL10,w:Int,h:Int) {
        glViewport(0,0,w,h)
        val ratio = (w/h).toFloat()
        frustumM(projM,0,-ratio,ratio,1f,-1f,1f,10f)
    }
    override fun onDrawFrame(g:GL10){
        glClear(GL_COLOR_BUFFER_BIT)
        setIdentityM(modelM,0)
        multiplyMM(mvM, 0,viewM,0,modelM,0)
        multiplyMM(mvpM,0,projM,0,mvM,0)
        multiplyMV(lPos,0,mvpM,0,lightPos,0)

        glUniformMatrix4fv(uMV, 1,false,mvM, 0)
        glUniformMatrix4fv(uMVP,1,false,mvpM,0)
        glUniform3f(uLightPos,lPos[0],lPos[1],lPos[2])
        glVertexAttribPointer(aPosition,3,GL_FLOAT,false,0,vBuf)
        glVertexAttribPointer(aNormal,  3,GL_FLOAT,false,0,nBuf)
        glVertexAttrib4f(aColor,1f,1f,1f,1f)
        glEnableVertexAttribArray(aPosition)
        glEnableVertexAttribArray(aNormal)
        glDrawArrays(GL_TRIANGLES,0,vBuf.capacity()/4)
    }
}

Solution

  • There is a mismatch between the layout qualifiers in the shader program and the resource indices in the application:

    The layout locations for aPos, aCol and aNorm are 0, 1, 2

    layout(location=0) in vec4 aPos;
    layout(location=1) in vec4 aCol;
    layout(location=2) in vec3 aNorm;
    

    But the corresponding variables in the application (aPosition, aColor, aNormal) are initialized by 0, 2, 1:

    val aPosition =  0
    val aNormal   =  1
    val aColor    =  2