0
$\begingroup$

I'm trying to learn OpenGL in c++ (I used it in Java) but I have a problem, I make a triangle, but it doesn't draw on GL_FILL and in GL_LINE it just draw a line, I can't find my mistake, I guess my bug is in vertex buffers, but I can't detect it, can anyone help me please?

CglApp.cpp:

    CglApp::CglApp() {

    glm::vec3 vertices[] = {
            {0.5f,  0.5f, 0.0f} ,  // top right
            {0.5f, -0.5f, 0.0f},  // bottom right
            {-0.5f, -0.5f, 0.0f},  // bottom left
            {-0.5f,  0.5f, 0.0f}   // top left
    };
    unsigned int indices[] = {  // note that we start from 0!
            0, 1, 3,  // first Triangle
            //1, 2, 3   // second Triangle
    };

    glm::vec3 vertices2[] = {
            //{0.5f,  0.5f, 0.0f} ,  // top right
            {0.5f, -0.5f, 0.0f},  // bottom right
            {-0.5f, -0.5f, 0.0f},  // bottom left
            {-0.5f,  0.5f, 0.0f}   // top left
    };

    unsigned int indices2[] = {  // note that we start from 0!
            //0, 1, 3,  // first Triangle
            1, 2, 3   // second Triangle
    };


    cglSolidModel.loadModels(vertices,indices);
    cglSolidModel1.loadModels(vertices2,indices2);

}

CglApp::~CglApp() {

}

void CglApp::run() {

    while (!cglWindow.shouldClose()){

        // input
        // -----
        inputManager.processInput(cglWindow.getWindow());

        // render
        // ------
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        cglSolidModel.bind(cglShaders.getDefaultShader());
        cglSolidModel1.bind(cglShaders.getDefaultShader());

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(cglWindow.getWindow());
        glfwPollEvents();

    }

}

CglShaders.cpp

CglShaders::CglShaders() {
    createDefaultShader();
}

CglShaders::~CglShaders() {

}

void CglShaders::createDefaultShader() {

    const char *vertexShaderSource = "#version 330 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 330 core\n"
                                       "out vec4 FragColor;\n"
                                       "void main()\n"
                                       "{\n"
                                       "   FragColor = vec4(1.0f, 0.9f, 0.2f, 1.0f);\n"
                                       "}\n\0";

    createShader(vertexShaderSource,fragmentShaderSource);

}

void CglShaders::createShader(const char *vertexShaderSource, const char *fragmentShaderSource) {

    // build and compile our shader program
    // ------------------------------------
    // vertex shader
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // check for shader compile errors
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // fragment shader
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    // check for shader compile errors
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // link shaders
    unsigned int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    // check for linking errors
    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);

    shaderPrograms.push_back(shaderProgram);

}

CglSolidModel.cpp

CglSolidModel::CglSolidModel() {

}

CglSolidModel::~CglSolidModel() {

}

void CglSolidModel::loadModels(glm::vec3 vertices[], unsigned int indices[]) {

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    // 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);

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

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)nullptr);
    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);

    // remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound.
    //glBindBuffer(GL_ELEMENT_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(1);


    // uncomment this call to draw in wireframe polygons.
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

}

void CglSolidModel::bind(unsigned int shaderProgram) {

    // draw our first triangle
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
    //glDrawArrays(GL_TRIANGLES, 0, 6);
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
    // glBindVertexArray(0); // no need to unbind it every time

}

Im creating the VBO, EBO and VBA inside each SolidModel.

Only two lines for two different triangles with GL_LINE

$\endgroup$
0

1 Answer 1

3
$\begingroup$

A problem I see in your code is that you take the sizeof() an unsized array, which yields the size of the pointer to that array and not the size of array itself.

void CglSolidModel::loadModels(glm::vec3 vertices[], unsigned int indices[]) {
{
    ...
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    ...
}

Here is a small test case that demonstrates the issue.

void func(int array[]) {
    printf("sizeof(array) = %d\n", sizeof(array));
}

int myArray[10];
func(myArray);

Output when compiled for x64:

sizeof(array) = 8  

This is the size of the 64bit pointer to the array. You would expect 10*sizeof(int) = 40. In your code (assuming x64) it only sends 8 bytes of the vertice array to the VBO, which is enough to fill the XY coordinates for the first vertex. That goes some way to explaining why you only see 1 partial triangle.

It's not possible for C++ to determine the size of an unsized array. In C++ int array[]; is equivalent to const int *array; and so sizeof(array) is the same in both cases. This isn't the case for sized arrays, int array[10]; would give you 40 bytes as you would expect.

I would recommend you pass another parameter which contains the size of the array or use a container like std::vector which stores the size along with the array. Be aware that std::vector returns the number of elements and not the number of bytes which glBufferData expects.

$\endgroup$
2
  • $\begingroup$ Oh I understand, thanks so much, I'm gonna use sizeof(vertices[0])*vertexCount in this case. $\endgroup$ Mar 12, 2021 at 20:18
  • $\begingroup$ Happy to help. One small thing I noticed in your code was glBindVertexArray(1) after your VAO/VBO is loaded - What is object #1? Usually glBindVertexArray(0) is used to unbind VAO to openGL. Infact the call glBindBuffer(GL_ARRAY_BUFFER, 0); looks risky as you still have your VAO bound, I would suggest a call to glBindVertexArray(0) is all that is needed after initialisation, this will leave your VAO in its setup state $\endgroup$
    – PaulHK
    Mar 13, 2021 at 5:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.