user9114500
user9114500

Reputation:

OpenGL: Cannot not render a triangle

After writing the code and running it, nothing worked. I managed to fill the background but nothing else.

Here's my code:

#include <iostream>
#include <glad\glad.h>
#include <GLFW\glfw3.h>

const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;

const char *vertexShaderSource = "#version 450 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";

const char *fragmentShaderSource = "#version 450 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
    "FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\0";

void framebuffer_size_callback(GLFWwindow* window, int width, int height);

int main()
{
    // Initializes GLFW and passes window hints 
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Creates GLFWwindow called window
    GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "LearningOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    // Check if GLAD is initialized
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    float vertices[] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f,  0.5f, 0.0f
    };

    int success;
    char infoLog[512];


    // Creating Vertex Shader Object
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    // Creating Fragment Shader Object
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    // Shader program
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();

    // Attatching both shaders to the program and then linking them
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // Interpreting vertex data 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // Generating a Vertex Array Object
    unsigned int VAO;
    unsigned int VBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // Size of rendering window 
    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 

    // While window is open
    while (!glfwWindowShouldClose(window))
    {
        // Finally
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        glBindVertexArray(VAO);
        glUseProgram(shaderProgram);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    // If loop is exited, terminate all allocated resources and close the program
    glfwTerminate();
    return 0;
}

// Frame buffer function that resizes the viewport when the window gets resized
void framebuffer_size_callback(GLFWwindow * window, int width, int height)
{
    glViewport(0, 0, width, height);
}

Upvotes: 1

Views: 1013

Answers (2)

Francis Cugler
Francis Cugler

Reputation: 7895

I noticed a few errors or problems with your code: The first apparent error is that after your call to:

glfwMakeContextCurrent(window);

You should be calling:

glfwSetFramebufferSizeCallback( window, framebuffer_size_callback );

This should be done after making the window the current context and before all of your OpenGL stuff.


The second problem that I see is within the setup of your VAO & VBO after reading in the information from your shaders and that is you have some things in an improper order and you are even missing a call or two from this section of your code:

// Interpreting vertex data 
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

// Generating a Vertex Array Object
unsigned int VAO;
unsigned int VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// Size of rendering window 
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 
  • First, you should be creating and initializing your VBO & VAO before calling glVertexAttribPointer() & glEnableVertexAtrribArray(). Think of this from the perspective of the API - Library. How can I enable a pointer to something that doesn't yet exist in memory?

  • Second, you are missing a call to glBindVertexArray(VAO); This should be after you generate your VAO & VBO.

  • Third, the last two lines of code I already explained about the function glfwSetFramebufferSizeCallback() and where it should be placed; but for this part I'll explain why. This is the function that sets up your viewport as it is a call back type of function. After you set the window to being the current context; this is where you want to tell OpenGL the size of your viewport or window so that it knows the Screen Size to work with in translating all of the vertex data into screen space coordinates. By fixing this you won't have to make the call to glViewport() independently; as this is what the call back function does for you.

This section of code should look like this:

unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);

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

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0); 

// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0); 

The last thing that I see is in your while loop for rending and after the loop as you have:

// While window is open
while (!glfwWindowShouldClose(window))
{
   // Finally
   glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
   glClear(GL_COLOR_BUFFER_BIT);
   glBindVertexArray(VAO);
   glUseProgram(shaderProgram);
   glDrawArrays(GL_TRIANGLES, 0, 3);

   glfwSwapBuffers(window);
   glfwPollEvents();
}
// If loop is exited, terminate all allocated resources and close the program
glfwTerminate();
return 0;

I am seeing two concerns here:

First, the order of using the program and binding the vertex arrays are backwards, they should be:

glUseProgram(shaderProgram);
glBindVertexArray(VAO);

Second after your while loop and before the glfwTerimate() call you should be deleting your vertex array and buffers

glDeleteVertexArrays( 1, &VAO );
glDeleteBuffers( 1, &VBO );

If these simple corrections do not fix your problem there is one other thing that you might be able to try. You can try changing the version of OpenGL from 4.5 to 3.3 since the versions of their GLSL Shader languages are slightly different.

If this doesn't work, then it could be something within how you setup the external libraries that you are using.


Summary

You first have to set the view port before trying to setup any of the vertex data. Next, you have to set up your VAO & VBO information before you can make a call to glVertexAtrribPointer() & glEnableVertexAttribArray() and don't forget to make a call to glBindVertexArray(VAO) after the calls to generate them. After all of the initialization is in proper order then when using it in the render loop you should make a call to glUseProgram before glBindVertexArray. Finally after your render loop you should make the appropriate calls to delete your vertex arrays and buffers. If these fail, then you can try changing the version of OpenGl - GLSL and check the setup of all external libraries that are being used.

Upvotes: 4

genpfault
genpfault

Reputation: 52084

Don't try to enable or set vertex attribute pointers before you have a VAO bound. Won't do anything useful in a Core context.

Bind a VAO then enable/set attributes:

unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// Generating a Vertex Array Object
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray( VAO );

// Interpreting vertex data 
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

Upvotes: 4

Related Questions