copenglglslglfwstb-image

Multiple models not rendering together but rendering seperately


I am building a simple test to see if I can render multiple separate objects using multiple EBOs, VAOs, and VBOs. I've gotten this to work in the past with just quads, but now that I am using a cube and a quad, only the quad will be drawn to the screen, no matter the order in which I draw them. I am using the stb_image, cglm, glad, glfw, and OpenGL libraries along with pure C, no C++.

#define _CRT_SECURE_NO_WARNINGS
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include "stb/stb_image.h"
#include <cglm/cglm.h>

typedef struct WindowData {
    GLFWwindow* window;
    int status;
} WindowData;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
unsigned int setUpShader(const char* vertSource, const char* fragSource);
WindowData buildWindow();
unsigned int setUpTexture();

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// shader sources
const char* vertexShaderSource3 = "#version 330 core\n" // vert // projection shader
                                  "layout(location = 0) in vec3 aPos;\n"
                                  "layout (location = 1) in vec3 aColor;\n"
                                  "layout(location = 2) in vec2 aTexCoord;\n"
                                  "out vec3 vertexColor;\n"
                                  "out vec2 TexCoord;\n"
                                  "out vec3 vertexPos;\n"
                                  "uniform mat4 model;\n"
                                  "uniform mat4 view;\n"
                                  "uniform mat4 projection;\n"
                                  "void main()\n"
                                  "{\n"
                                  "   vertexColor = aColor; \n"
                                  "   vertexPos = aPos;\n"
                                  "   gl_Position = projection * view * model * vec4(aPos, 1.0);\n"
                                  "   TexCoord = aTexCoord;\n"
                                  "}\n";

const char* fragmentShaderSource4 = "#version 330 core\n" //frag // texture RGB shader
                                    "out vec4 FragColor;\n"
                                    "in vec3 vertexColor;\n"
                                    "in vec2 TexCoord;\n"
                                    "uniform sampler2D ourTexture;\n"
                                    "void main()\n"
                                    "{\n"
                                    "   FragColor = texture(ourTexture, TexCoord) * vec4(vertexColor, 1.0);\n"
                                    "}\n\0";

int main(int argc, char* argv[])
{
    // SETUP WINDOW
    WindowData windowBuildResult = buildWindow();

    if(windowBuildResult.status == -1) {
        return -1;
    }

    GLFWwindow* window = windowBuildResult.window;

    // GLAD: LOAD ALL OpenGL FUNCTION POINTERS
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        printf("Failed to initialize GLAD\n");
        return -1;
    }

    // SET UP SHADERS AND TEXTURES
    unsigned int modelShader = setUpShader(vertexShaderSource3, fragmentShaderSource4);

    // SET UP VERTEX DATA AND VBOs/VAOs/EBO

    float plane1verts[] = {
        //---position--------/----color--------/texture coordinates
        //X------Y------Z----/R-----G-----B----/X-----Y----/
       -0.75f, -1.0f, -0.75f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 0
        0.75f, -1.0f, -0.75f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // 1
        0.75f, -1.0f,  0.75f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // 2
       -0.75f, -1.0f,  0.75f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 3
    };

    float planeIndices[] = {
        0, 1, 3, // 1st triangle
        1, 2, 3, // 2nd triangle
    };

    float cube1verts[] = {
      //---position--------/----color--------/texture coordinates
      //X------Y------Z----/R-----G-----B----/X-----Y----/
      
        // back face
        0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 0 // RED // top right
        0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 1 // YELLOW // bottom right
       -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 2 // GREEN // bottom left
       -0.5f,  0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 3 // BLUE // top left

        // front face
       -0.5f, -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 4
        0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 5
        0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 6
       -0.5f,  0.5f,  0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 7

        // left face
       -0.5f,  0.5f,  0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // 8
       -0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // 9
       -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 10
       -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 11

        // right face // working on color correction
        0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 12
        0.5f,  0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 13
        0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 14
        0.5f, -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 15

        // bottom face
       -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 16
        0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // 17
        0.5f, -0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // 18
       -0.5f, -0.5f,  0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 19

        // top face
       -0.5f,  0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 20
        0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 21
        0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 22
       -0.5f,  0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 23
    };

    unsigned int cubeIndices[] = {
        //back face
         0,  1,  3, // 1st triangle
         1,  2,  3, // 2nd triangle

        //front face
         4,  5,  6, // 3rd triangle
         6,  7,  4, // 4th triangle

        //left face
         8,  9, 11, // 5th triangle
         9, 10, 11, // 6th triangle

        //right face
        12, 13, 15, // 7th triangle
        13, 14, 15, // 8th triangle

        //bottom face
        16, 17, 19, // 9th triangle
        17, 18, 19, // 10th triangle

        //top face
        20, 21, 23, // 11th triangle
        21, 22, 23, // 12th triangle
    };

    vec3 cubePositions[] = {
        { 0.0f,  0.0f,  0.0f },
        { 2.0f,  5.0f, -15.0f },
        { -1.5f, -2.2f, -2.5f },
        { -3.8f, -2.0f, -12.3f },
        { 2.4f, -0.4f, -3.5f },
        { -1.7f,  3.0f, -7.5f },
        { 1.3f, -2.0f, -2.5f },
        { 1.5f,  2.0f, -2.5f },
        { 1.5f,  0.2f, -1.5f },
        { -1.3f,  1.0f, -1.5f }
    };

    unsigned int VBOs[2], VAOs[2], EBOs[2];
    glGenVertexArrays(2, VAOs);
    glGenBuffers(2, VBOs);
    glGenBuffers(2, EBOs);

    // SETUP TEXTURES
    unsigned int texture = setUpTexture();
    

    // SETUP RENDERING
    
    // CUBE
    glBindVertexArray(VAOs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cube1verts), cube1verts, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // PLANE
    glBindVertexArray(VAOs[1]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(plane1verts), plane1verts, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);


    // To draw in triangle as a wireframe:
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glLineWidth(2.0f);
    glEnable(GL_DEPTH_TEST);

    // RENDER LOOP
    while (!glfwWindowShouldClose(window))
    {
        processInput(window);

        glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        /*--------------------------------------------------------------------------------------*/

        // SETUP CAMERA/FOV

        // initialize view and projection matrices
        mat4 view = GLM_MAT4_IDENTITY_INIT; // camera
        mat4 projection = GLM_MAT4_IDENTITY_INIT; // FOV

        // do view and projection transforms
        float viewSinMovement = (float)sin(glfwGetTime());
        glm_rotate(view, glm_rad(0.0f), (vec3) { 0.0f, 1.0f, 0.0f });
        glm_translate(view, (vec3) { viewSinMovement, -0.25f, -3.0f });
        glm_perspective(glm_rad(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f, projection); // FOV, aspect ratio, near Z, far Z, projection matrix

        /*--------------------------------------------------------------------------------------*/

        // DRAW TEXTURED CUBE IN PERSPECTIVE

        // setup cube textures, shaders, and EBO
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[0]);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);
        glUseProgram(modelShader);
        
        // assign view and projection matrices to shader
        unsigned int viewLoc1 = glGetUniformLocation(modelShader, "view");
        unsigned int projectionLoc1 = glGetUniformLocation(modelShader, "projection");
        glUniformMatrix4fv(viewLoc1, 1, GL_FALSE, (const GLfloat*) view);
        glUniformMatrix4fv(projectionLoc1, 1, GL_FALSE, (const GLfloat*) projection);
        
        // bind VAO
        glBindVertexArray(VAOs[0]);

        for (int i = 0; i < (sizeof(cubePositions)/sizeof(vec3)); i++) {

            // initialize model matrix
            mat4 model1 = GLM_MAT4_IDENTITY_INIT;

            // do model matrix transforms
            glm_translate(model1, cubePositions[i]);
            glm_rotate(model1, glm_rad((float)glfwGetTime() * 10.0f * i), (vec3) { 1.0f, 0.5f, 0.0f });

            // assign model matrix to shader
            unsigned int modelLoc2 = glGetUniformLocation(modelShader, "model");
            glUniformMatrix4fv(modelLoc2, 1, GL_FALSE, (const GLfloat*)model1);

            // draw cube
            glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
        }

        /*--------------------------------------------------------------------------------------*/

        // DRAW PLANE IN PERSPECTIVE

        // setup plane textures, shaders, and EBO
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[1]);
        glBindTexture(GL_TEXTURE_2D, texture);
        glUseProgram(modelShader);

        // initialize model matrix
        mat4 model2 = GLM_MAT4_IDENTITY_INIT;

        // do model matrix transforms
        glm_translate(model2, (vec3) { 0.0f, 0.0f, 0.0f });
        glm_rotate(model2, 0.0f, (vec3) { 0.0f, 0.0f, 0.0f });
        glm_scale(model2, (vec3) { 1.0f, 1.0f, 1.0f });

        // assign model matrix to shader
        unsigned int modelLoc1 = glGetUniformLocation(modelShader, "model");
        glUniformMatrix4fv(modelLoc1, 1, GL_FALSE, (const GLfloat*)model2);

        // assign view and projection matrices to shader
        unsigned int viewLoc2 = glGetUniformLocation(modelShader, "view");
        unsigned int projectionLoc2 = glGetUniformLocation(modelShader, "projection");
        glUniformMatrix4fv(viewLoc2, 1, GL_FALSE, (const GLfloat*)view);
        glUniformMatrix4fv(projectionLoc2, 1, GL_FALSE, (const GLfloat*)projection);

        // draw plane
        glBindVertexArray(VAOs[1]);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        // SWAP BUFFERS AND CHECK FOR USER INPUTS
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // DE-ALLOCATE RESOURCES
    glDeleteVertexArrays(2, VAOs);
    glDeleteBuffers(2, VBOs);
    glDeleteBuffers(2, EBOs);
    glDeleteProgram(modelShader);

    // CLEAR ALL RESOURCES AND STOP OpenGL
    glfwTerminate();
    return 0;
}

// CHANGE WINDOW SIZE AND VIEWPORT
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow* window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, 1);
    }
}

unsigned int setUpShader(const char* vertSource, const char* fragSource) {
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertSource, NULL);
    glCompileShader(vertexShader);

    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
    }

    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragSource, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
    }

    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return shaderProgram;
}

WindowData buildWindow() {

    // INIT GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // CHANGE SETTINGS BASED ON OS
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    // BUILD WINDOW
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    WindowData windowData = { window, 0 };
    if (window == NULL)
    {
        printf("Failed to create GLFW window\n");
        glfwTerminate();
        windowData.status = -1;
        return windowData;
    }

    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    return windowData;
}

unsigned int setUpTexture(){
    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

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

    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(1);
    unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
    if (data) {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else {
        printf("ERROR::TEXTURE::LOAD::FAILED\n");
    }
    stbi_image_free(data);
    return texture;
}

What I have verified is correct:

The only thing that is incorrect, is when I set the render mode to wireframe, the cube(s) only have a single line being drawn, while the entire quad is being drawn properly (all of its lines show up)


Solution

  • Index arrays (such as planeIndices[] and cubeIndices[]) need to be unsigned int and not float

    On line 171 I declared planeIndices[] as a float and not an unsigned int array, hence why OpenGL did not properly render the plane.

    This does not actively break the render cycle, which is why it took so long to find it.

    Double check the types used for all your object data as well as the vertex data and indices if you are having trouble getting an object to render.

    PS: Also make sure you are binding a texture to your object if the shader utilizes one. (modelShader uses a texture and the plane object did not have the any texture bound to it)