Points do not get rendered properly using std::vector. C style array works however

Hi! I’m trying to render a graph using glDrawArrays() with GL_LINE_STRIP following the tutorial on wikibooks about scientific opengl.

If I use a C-style array, I get the desired render. The main issue I run into is that while using a vector to store the the points, only half the graph gets rendered. This doesn’t happen when I use a C style array.

Here are some of the graphs for reference:

main.cpp

#include ...

unsigned const int WIN_WIDTH = 800;
unsigned const int WIN_HEIGHT = 600; 

//! FIND OUT WHY GRAPH DOESN'T RENDER PROPERLY WHEN USING STD VECTOR

struct Point {
  float m_x;
  float m_y;
  Point(float x, float y) : m_x{x}, m_y{y}{}
};

int main(){

    std::vector<Point> graph;
    graph.reserve(2000);
    for(int i = 0; i < 2000; i++) {
        float x = (i - 1000.0f) / 100.0f;
        graph.push_back(Point(x,(sin(x * 10.0f) / (1.0f + x * x))));
        std::cout << graph[i - 0].m_x << " , " << graph[i - 0].m_y<< "\n";
    }

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
    
    GLFWwindow* window = glfwCreateWindow(WIN_WIDTH,WIN_HEIGHT,"Learning OpenGL",NULL, NULL);
    if(window == NULL){
        std::cout << "Failed to create OpenGL window\n";
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
        std::cout << "Failed to initialze GLAD\n";
        return -1;
    }

    Shader myShader("./shaders/vertexShader1.vert","./shaders/fragmentShader1.frag");

    unsigned int VAO; 
    unsigned int VBO_Vertex;
    //unsigned int EBO;
    
    glGenVertexArrays(1,&VAO);
    glGenBuffers(1, &VBO_Vertex);
    //glGenBuffers(1, &EBO);

    glBindVertexArray(VAO); //<--- Start of VAO Bind
    
    glBindBuffer(GL_ARRAY_BUFFER, VBO_Vertex); 
    glBufferData(GL_ARRAY_BUFFER, graph.size() * sizeof(float), &graph[0], GL_STATIC_DRAW);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindVertexArray(0); //<--- End of VAO Bind

    myShader.use();

    bool button_r_pressed = false; //For hot shader reloading


    while(!glfwWindowShouldClose(window)){        
        // inputA
        processInput(window);
        if((glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS) && !button_r_pressed){
            reloadShader(window, &myShader);
            myShader.use();
            button_r_pressed = true;
        }
        if(glfwGetKey(window,GLFW_KEY_R) == GLFW_RELEASE){
            button_r_pressed = false;
        }
        //rendering commands
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        
        
        myShader.use();        
        glBindVertexArray(VAO);

        glDrawArrays(GL_LINE_STRIP, 0, graph.size());
        //check and call events and swap buffers

        glBindVertexArray(0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwTerminate();
    return 0; 
}

vertex shader

#version 330 core
layout (location = 0) in vec2 coord2d;
layout (location = 1) in vec3 vecCol;

out vec3 out_vecCol;

void main(){
    out_vecCol = vecCol;
    gl_Position = vec4(coord2d.x, coord2d.y, 0.0f, 1.0f);
}

fragment shader

#version 330 core
out vec4 FragColour;

in vec3 out_vecCol;

void main(){
    FragColour = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}

The code above gives me the graph shown in (1)

However I noticed that when I changed this portion of my code in main() to the following:

    std::vector<Point> graph;
    graph.reserve(2000);
    for(int i = 500; i < 2000; i++) {
        float x = (i - 1000.0f) / 100.0f;
        graph.push_back(Point(x,(sin(x * 10.0f) / (1.0f + x * x))));
        std::cout << graph[i - 500].m_x << " , " << graph[i - 500].m_y<< "\n";
    }

The result is the full graph but with a weird line coming from the origin connecting to something offscreen to the right as shown in (2)

When I lower the starting i to 100 like so:

    std::vector<Point> graph;
    graph.reserve(2000);
    for(int i = 100; i < 2000; i++) {
        float x = (i - 1000.0f) / 100.0f;
        graph.push_back(Point(x,(sin(x * 10.0f) / (1.0f + x * x))));
        std::cout << graph[i - 100].m_x << " , " << graph[i - 100].m_y<< "\n";
    }

The graph is now not fully drawn, the line from the origin connects to the point where the graph stops as seen in (3)

As the value is lowered to 0, the graph shrinks until it stops at the origin, with a weird line always connecting to the origin.

Initially I thought the issue may have been that the std::vector elements aren’t contiguous, but that doesn’t seem to be the case after some googling. I tried creating another vector using the graph vector as a constructor and verified that the issue wasn’t caused by using push_back.

Does anyone have any idea what is going on here?

Thank you for reading!

That’s the wrong buffer size, your per-vertex data has size sizeof(Point) i.e. 2 * sizeof(float).

1 Like