monolith
monolith

Reputation: 1706

OpenGL shader problem (not displaying anything)

I am fairly new to OpenGL and i was following this tutorial on Shaders https://learnopengl.com/Getting-started/Textures. I can't get mine to work, as the screen ends up just being entirely black. This code uses glew and glut instead of glfw like in the tutorial.

What is going on?

Considerations:

This is myDisplay callback:

void myDisplay(void)
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glEnable(GL_TEXTURE_2D);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 
glTranslatef(0, 0, -10);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

glUseProgram(ourShader);
glBindVertexArray(VAO); 
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

glutSwapBuffers();
}

Main setup

int main(){
//glut initialization stuff...left this out



float 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 
    };
    float texCoords[] = {
    0.0f, 0.0f,  // lower-left corner  
    1.0f, 0.0f,  // lower-right corner
    0.5f, 1.0f   // top-center corner
    };

    unsigned int indices[] = {
       0, 1, 3, // first triangle
       1, 2, 3  // second triangle
    };

    //frameBuffer
    glGenBuffers(1, &FBO);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR: Framebuffer not bound" << std::endl;

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    //glDeleteFramebuffers(1, &fbo);


    //VAO
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

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

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

    // Vertex Attributes 
    glEnableVertexAttribArray(0); //pozicija
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(0));
    glEnableVertexAttribArray(1); //boja
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2); //boja
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));

    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &texture);
    glActiveTexture(GL_TEXTURE0); 
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    std::string path = "C:\\Projects\\Myproj\\container.jpg";
    bool success = loadTexture(path,texture_data,&tex_width, &tex_height, &nchannels);
    if (success) 
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else 
    {
        std::cout << "ERROR::STBI::FAILED TO LOAD TEXTURE" << std::endl;
    }

    stbi_image_free(texture_data);

    int success_f;
    char infoLog[512];

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    getShaderStatus(vertexShader, &success_f, infoLog);

    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    getShaderStatus(fragmentShader, &success_f, infoLog);


    ourShader = glCreateProgram();
    glAttachShader(ourShader, vertexShader);
    glAttachShader(ourShader, fragmentShader);
    glLinkProgram(ourShader);
    getShaderStatus(ourShader, &success_f, infoLog);

    glUseProgram(ourShader);
    glUniform1i(glGetUniformLocation(ourShader, "ourTexture"), 0);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    glutMainLoop();
}

Vertex Shader

const char* vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 aPos;\n"
"layout(location = 1) in vec3 aColor;\n"
"layout(location = 2) in vec2 aTexCoord;\n"
"out vec3 ourColor;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos, 1.0);\n"
"ourColor = aColor;\n"
"TexCoord = aTexCoord;\n"
"}\n";

Fragment Shader

const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
"FragColor = texture(ourTexture, TexCoord);\n"
"}\n";

UPDATE LOG - SOLVED

glutInitContextVersion(3, 3); glutInitContextProfile(GLUT_CORE_PROFILE);

Final code is here : [ https://pastebin.com/D8DgPqaT ]

Psychedelic Shaders: [ https://pastebin.com/vtJ3Cr6i ]

Upvotes: 2

Views: 2898

Answers (1)

Rabbid76
Rabbid76

Reputation: 210878

glEnable(GL_TEXTURE_2D) is unnecessary when you use a shader, because weather the texture is used or not is implemented in the (fragment) shader.
Your shader code defines if the texture is applied or not. glEnable(GL_TEXTURE_2D) is for use of the deprecated Fixed Function Pipeline, without a shader only.

Also using the fixed function matrix stack (glMatrixMode, glLoadIdentity, gluPerspective, ...) is useless. You have to use Uniform variables (of type mat4). This functions change the matrices on the fixed function matrix stack. This matrices are applied to the fixed function vertex coordinates which are set by glVertex or glVertexPointer, but only if there is no shader code.
If there is a shader you have to do the matrix transformations by yourself.
In GLSL there exist the built-in uniforms like gl_ModelViewMatrix, gl_ProjectionMatrix or gl_ModelViewProjectionMatrix which allow you to access the matrices on the fixed function matrix stack. But this uniforms are deprecated, too and not any more accessible in GLSL #version 330 core.

Write a shader with 2 uniforms mat4 u_proj and mat4 u_view. Transform the vertex coordinate by the shader code.

#version 330 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;

out vec3 ourColor;
out vec2 TexCoord;

uniform mat4 u_proj;
uniform mat4 u_view;

void main()
{
    gl_Position = u_proj * u_view * vec4(aPos, 1.0);
    ourColor = aColor;
    TexCoord = aTexCoord;
}

Get The uniform locations after the program is linked:

GLint proj_loc = glGetUniformLocation(ourShader, "u_proj");
GLint view_loc = glGetUniformLocation(ourShader, "u_view");

Calculate the projection matrix an view matrix. I recommend to use the OpenGL Mathematics (GLM) library which is designed to do OpenGL and GLSL relate calculations and based on the OpenGL Shading Language (GLSL). See also glm::perspective and glm::lookAt:

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

</>

glm::mat4 proj = glm::perspective(glm::radians(fov_degrees)), aspect, near, far);
glm::mat4 view = glm::lookAt(eye, target, up);

Set the uniforms after the program is installed (glUseProgram) by glUniformMatrix4fv:

glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(proj));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, glm::value_ptr(view));

Review of code [https://pastebin.com/KWDxcEen] and shaders [https://pastebin.com/yq3rQEga]

If a shader has been successfully compiled has to be checked by glGetShaderiv

glGetShaderiv(shader_ID, GL_COMPILE_STATUS, &status);

in compare to check if a program has been successfully linked, which has to be checked by glGetProgramiv

glGetProgramiv(program_ID, GL_LINK_STATUS, success_f);

The array texture coordinates consist of tuples with a size of 2 (u, v):

glVertexAttribPointer(2,
    2,                 // <---- 2 instead of 3 
    GL_FLOAT,
    GL_FALSE,
    8 * sizeof(GLfloat),
    (void*)(6 * sizeof(GLfloat))
); 

The 3rd parameter of glDrawArrays is the number of vertces, but not the number of primitives:

glDrawArrays(GL_TRIANGLES, 0, 6); // <---- 6 instead of 2

the 2nd parameter of loadTexture has to be an output parameter. It has to be a reference (unsigned char *& buff):

bool loadTexture(
   const std::string &filename,
   unsigned char*& buff,           // < ---- unsigned char*&
   int* w, int* h, int* nc);

The sate if a vertex attribute is enabled or disabled is stored in the Vertex Array Object. There is not need of doing this again in the display function:

void myDisplay(void) 
{

    // ....

    glBindVertexArray(VAO);

    // unecessary:
    //glEnableVertexAttribArray(0);
    //glEnableVertexAttribArray(1); 
    //glEnableVertexAttribArray(2); 

Finally I recommend to add a glutPostRedisplay() call to the display function (myDisplay), for a continuously update of the scene.

Upvotes: 2

Related Questions