Search code examples
opengl-esglslglslesvertex-array-object

How to Convert GLSL #version 330 core to GLSL ES #version 100?


I'm trying to make an app that draws an image in Android Studio with NDK and JNI to call C++ Code using OpenGL ES. I have went through the tutorial how to do this in OpenGL at : https://learnopengl.com/#!Getting-started/Textures, which use GLSL 330 core. However, OpenGL ES 3.0 isn't supported on the Android emulator (Note in this link :https://developer.android.com/ndk/guides/stable_apis.html).

Therefore, I have to use the GLSL ES #version 100 , which doesn't support "layout", "in" and "out" in the shaders below. How should I edit them so that they could run in #version 100 and is there any change in the source code if I edit them? Thanks for your attention and your help.

Update: After searching around, I found out that I could use glGetAttributeLocation to get the location of variable in vertex shader instead of using layout(location=0). However, there's no VAO in GLSL ES #version 100 so I still couldn't firgure out how it work without VAO.

My Vertex shader:

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;

out vec3 ourColor;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(position, 1.0f);
    ourColor = color;
    // We swap the y-axis by substracing our coordinates from 1. This is done because most images have the top y-axis inversed with OpenGL's top y-axis.
    // TexCoord = texCoord;
    TexCoord = vec2(texCoord.x, 1.0 - texCoord.y);
}

fragment Shader:

#version 330 core
in vec3 ourColor;
in vec2 TexCoord;

out vec4 color;

// Texture samplers
uniform sampler2D ourTexture1;
uniform sampler2D ourTexture2;

void main()
{
    // Linearly interpolate between both textures (second texture is only slightly combined)
    color = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2);
}

Initialize VAO,VBO,:

    // Set up vertex data (and buffer(s)) and attribute pointers
    GLfloat vertices[] = {
        // Positions          // Colors           // Texture Coords
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // Top Right
         0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // Bottom Right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // Bottom Left
        -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // Top Left 
    };
    GLuint indices[] = {  // Note that we start from 0!
        0, 1, 3, // First Triangle
        1, 2, 3  // Second Triangle
    };
    GLuint VBO, VAO, ;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, );
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // Position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // Color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // TexCoord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    glBindVertexArray(0); // Unbind VAO

Draw an image:

        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Activate shader
        ourShader.Use();     

        // Bind Textures using texture units
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture1);
        glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);
        glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1);  

        // Draw container
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

Solution

  • Finally, I manage to solve it. In GLSL ES 100, There is no in out and layout(location=0) as i mentioned above. Therefore, I have to replace them:

    in => attribute

    out => varying

    And completely remove layout(location=0) because there's no such thing does the same thing in GLSL ES 100 as far as I aware.

    Because of the removal of layout(location=0), we have to tell the program the location of our vertex data, which are position,color and textCoord in this case. With layout(location=0), we could simple put the location 0 in the

    glVertexAttribPointer(0,3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    

    Without it, we first need to get the location of the vertex attribute with:

    GLint mPosition= glGetAttributeLocation(ourProgram,"position")
    

    then replace the constant number 0,1 or 2 with my predefined mPosition :

    glVertexAttribPointer(mPosition,3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(mPosition);;
    

    The same on color and textCoord.

    below are my edited vertex shader, fragment shader and how to initialize VBO and pass in our data:

    Edited vertex shader for GLSL ES 100:

    auto gVertexShader =
    "attribute vec3 position;\n"
    "attribute vec3 color;\n"
    "attribute  vec2 texCoord;\n"
    
    "varying vec3 ourColor;\n"
    "varying vec2 TexCoord;\n"
    
    "void main()\n"
    "{\n"
        "gl_Position = vec4(position,1.0); // Add the xOffset to the x position of the vertex position\n"
        "ourColor = color;\n"
        "TexCoord= vec2(texCoord.x,1.0-texCoord.y);\n"
    "}\n";
    

    Edited fragment shader for GLSL ES 100:

    static const char FRAGMENT_SHADER[] =
        "#version 100\n"
        "precision mediump float;\n"
        "varying vec4 vColor;\n"
        "void main() {\n"
        "    gl_FragColor = vColor;\n"
        "}\n";
    

    my InitBuffer function:

    // Set up vertex data (and buffer(s)) and attribute pointers
        GLfloat vertices[] = {
            // Positions          // Colors           // Texture Coords
             0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // Top Right
             0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // Bottom Right
            -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // Bottom Left
            -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // Top Left 
        };
        GLuint indices[] = {  // Note that we start from 0!
            0, 1, 3, // First Triangle
            1, 2, 3  // Second Triangle
        };
    void initBuffers()
    {
        GLint mPosition,mCorlor,mTextCoord;
        GLuint VBOs[2]; // Initialize an buffer to store all the verticles and transfer them to the GPU
    
        glGenBuffers(2, VBOs); // Generate VBO
    
    
        glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);//Bind verticles array for OpenGL to use
        glBufferData(GL_ARRAY_BUFFER, sizeof(recVertices), recVertices, GL_STATIC_DRAW);
    
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBOs[1]);//Bind the indices for information about drawing sequence
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
        // 1. set the vertex attributes pointers
        // Position Attribute
        mPosition=glGetAttributeLocation(Program, "position");
        glVertexAttribPointer(mPosition, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(mPosition);
        // Color Attribute
    
        mColor=glGetAttributeLocation(Program, "color");
        glVertexAttribPointer(mColor, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
        glEnableVertexAttribArray(mColor);
        //Texture Coordinate Attribute
    
        mTextCoord=glGetAttributeLocation(Program, "textCoord")'
        glVertexAttribPointer(mTextCoord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
        glEnableVertexAttribArray(mTextCoord);
    
    
    }
    

    Then we replace VAO binding in our draw function with the call of initBuffer() function

        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    
        // Activate shader
        ourShader.Use();     
    
        // Bind Textures using texture units
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture1);
        glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);
        glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1);  
    
        // Draw container
        initBuffers();
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    

    Hope this will help who has the same problem with me. Please feel free to ask me if you have any question :).