<p>You only need to create the VBOs and VAO once and then you can reuse them every frame.</p>

<pre><code>void init(){

    glGenVertexArrays(1, &amp;VAO1);
    glBindVertexArray(VAO1);

    glGenBuffers(1, &amp;VBO1);
    glBindBuffer(GL_ARRAY_BUFFER, VBO1);
    glBufferData(GL_ARRAY_BUFFER, sizeof(data1), data1, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, VBO1);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenBuffers(1, &amp;VBO2);
    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(data2), data2, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);

    uniformLoc_centerX = glGetUniformLocation(program, "centerX");
    uniformLoc_centerY = glGetUniformLocation(program, "centerY");
    uniformLoc_sizeX = glGetUniformLocation(program, "sizeX");
    uniformLoc_sizeY = glGetUniformLocation(program, "sizeY");
    uniformLoc_size= glGetUniformLocation(program, "size");
}

void draw(){
    glUseProgram(program);
    glBindVertexArray(VAO1);

    glUniform1f(uniformLoc_centerX, centerX);
    glUniform1f(uniformLoc_centerY, centerY);
    glUniform1f(uniformLoc_sizeX, scrwidth);
    glUniform1f(uniformLoc_sizeY, scrheight);
    glUniform1f(uniformLoc_size, dotSize);

    glDrawArrays(GL_POINTS, 0, dot count);
}
</code></pre>

<p>If the data ever changes then all you need to do is:</p>

<pre><code>glGenBuffers(1, &amp;VBO1);
glBufferData(GL_ARRAY_BUFFER, sizeof(data1), data1, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBO2);
glBufferData(GL_ARRAY_BUFFER, sizeof(data2), data2, GL_STATIC_DRAW);
</code></pre>

CC BY-SA 3.0
2017-08-18T08:29:59.387Z
2017-08-18T08:29:59.387Z
ratchet freak
<p>To start with, you should (almost) never have a glGen*() call in your render loop. Do that during initialization only. </p>

<p>It looks like your vertex data isn't changing. Don't re-set the buffer data, just send it once during initialization. </p>

<p>For the application you've described, about the only thing that should be in your render loop is bindBuffer, setting your uniforms, clear, draw and present. </p>

<p>Fixing those issues will likely have a significant perf impact. If that still isn't enough, look at spatial partitioning and frustum culling - in 2D, your frustum is just going to be a box - to more intelligently clip your data CPU-side. Google "quad trees" to get started. </p>

<p>Also, depending on the use case, you MIGHT be better off just doing this in Unity or another off-the-shelf engine. They already provide much of this functionality.  (However, I'm all for roll-your-own  for the fun factor, and a full engine may be overkill for this.)</p>

<p>And never forget: the profiler is your friend. Without it, everything else is just professional guessing. </p>

CC BY-SA 3.0
2017-08-20T16:24:38.197Z
2017-08-20T16:24:38.197Z
3Dave
<p>I have a very basic grasp of computer graphics however I threw it all away when I wrote this simple application that I am using for scientific purposes. I didn't have a lot of time to write it correctly because my "bosses" didn't see the promise of it but now that it is done they have found it quite useful.</p>

<p>The problem is I built it stupidly.</p>

<p>Basically it takes a TON of points stored in a big array and draws them to the screen. The screen can be moved and zoomed.</p>

<p>Instead of using a matrix to accomplish this I am simply passing in the width, height and center of the screen making my average vertex shader look like so</p>

<pre><code>#version 330 core
layout (location = 0) in float ex;
layout (location = 1) in float ey;

uniform float sizeX;
uniform float sizeY;
uniform float centerX;
uniform float centerY;
uniform float size;

out vec4 color;
out float passsize;
void main()
{
    gl_PointSize = size;
    passsize = size;
    float x = (ex - centerX) / (sizeX / 2.0);
    float y = (ey - centerY) / (sizeY / 2.0);
    gl_Position = vec4(x, y, 0.0, 1.0);

    color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
</code></pre>

<p>and an average draw call look about like this</p>

<pre><code>glUseProgram(program);
glGenVertexArrays(1, &amp;VAO1);
glBindVertexArray(VAO1);

glGenBuffers(1, &amp;VBO1);
glBindBuffer(GL_ARRAY_BUFFER, VBO1);
glBufferData(GL_ARRAY_BUFFER, sizeof(data1), data1, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBO1);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, 0);

glGenBuffers(1, &amp;VBO2);
glBindBuffer(GL_ARRAY_BUFFER, VBO2);
glBufferData(GL_ARRAY_BUFFER, sizeof(data2), data2, GL_STATIC_DRAW);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);

glUniform1f(glGetUniformLocation(program, "centerX"), centerX);
glUniform1f(glGetUniformLocation(program, "centerY"), centerY);
glUniform1f(glGetUniformLocation(program, "sizeX"), scrwidth);
glUniform1f(glGetUniformLocation(program, "sizeY"), scrheight);
glUniform1f(glGetUniformLocation(program, "size"), dotSize);

glDrawArrays(GL_POINTS, 0, dot count);
glfwSwapBuffers(window);
glfwPollEvents();
</code></pre>

<p>This works very well but I would love to get rid of the low frame rate this causes when I am drawing a ton of points (generally over 10,000 on my small laptop that doesn't actually have a GPU).</p>

<p>Is there any way I can get the GPU to more intelligently clip points that are going to be off screen?</p>

<p>I don't have a lot of time to change things around so it would be great if it were something simple to achieve.</p>

CC BY-SA 3.0
2017-08-18T04:33:08.273Z
What kind of laptop does not have a GPU?
joojaa
CC BY-SA 3.0
2017-08-18T05:15:08.030Z
You need to profile your code to see where the problem is. Drawing 10,000 points should be no problem for even a low-end GPU. Are you actually uploading the data on every draw call? If so, don't do that. You're using `GL_STATIC_DRAW`, so it looks like your data is not changing. If that's the case, upload it once and draw it on every frame.
user1118321
CC BY-SA 3.0
2017-08-18T07:49:07.503Z
Are you creating a new vertex buffer each frame? If so it would be more efficient to create it only once, then update its content when it changes. Nowadays, even a low end laptop with an integrated chipset can draw hundreds of thousands of points at a good framerate.
Julien Guertault
CC BY-SA 3.0
2017-08-18T08:27:09.030Z
@joojaa I assume he means it has an Intel integrated GPU instead of a beefier off-chip one.
Dan Hulme
CC BY-SA 3.0
2017-08-18T09:56:26.003Z
@DanHulme Thats my point its still a GPU! You will have hard timefinding laptops with really no GPU.
joojaa
CC BY-SA 3.0
2017-08-25T17:28:24.590Z
@joojaa "GPU" is very common colloquial nomenclature for a dedicated graphics card, excluding integrated graphics processors. Don't be pedantic. :P
Dan
CC BY-SA 3.0
2017-08-25T18:01:34.797Z
@Dan well, most GPUs on laptops tend to be integrated to the motherboard. So does that mean laptops do not have them?
joojaa
CC BY-SA 3.0
2017-08-25T18:17:31.340Z
@joojaa It's vague, depends on the model of the GPU whether or not I would consider it worthy of being called a "GPU" in such a colloquial way as to imply that it e.g. has drivers which support OpenGL > 1.1.
Dan
<opengl>
Is there a way I can make this easier for openGL to draw?
CalebK
# Is there a way I can make this easier for openGL to draw?

(Asked by: username_0 on 2017-08-18)

I have a very basic grasp of computer graphics however I threw it all away when I wrote this simple application that I am using for scientific purposes. I didn't have a lot of time to write it correctly because my "bosses" didn't see the promise of it but now that it is done they have found it quite useful.

The problem is I built it stupidly.

Basically it takes a TON of points stored in a big array and draws them to the screen. The screen can be moved and zoomed.

Instead of using a matrix to accomplish this I am simply passing in the width, height and center of the screen making my average vertex shader look like so

```
#version 330 core
layout (location = 0) in float ex;
layout (location = 1) in float ey;

uniform float sizeX;
uniform float sizeY;
uniform float centerX;
uniform float centerY;
uniform float size;

out vec4 color;
out float passsize;
void main()
{
    gl_PointSize = size;
    passsize = size;
    float x = (ex - centerX) / (sizeX / 2.0);
    float y = (ey - centerY) / (sizeY / 2.0);
    gl_Position = vec4(x, y, 0.0, 1.0);

    color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

```

and an average draw call look about like this

```
glUseProgram(program);
glGenVertexArrays(1, &VAO1);
glBindVertexArray(VAO1);

glGenBuffers(1, &VBO1);
glBindBuffer(GL_ARRAY_BUFFER, VBO1);
glBufferData(GL_ARRAY_BUFFER, sizeof(data1), data1, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBO1);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, 0);

glGenBuffers(1, &VBO2);
glBindBuffer(GL_ARRAY_BUFFER, VBO2);
glBufferData(GL_ARRAY_BUFFER, sizeof(data2), data2, GL_STATIC_DRAW);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);

glUniform1f(glGetUniformLocation(program, "centerX"), centerX);
glUniform1f(glGetUniformLocation(program, "centerY"), centerY);
glUniform1f(glGetUniformLocation(program, "sizeX"), scrwidth);
glUniform1f(glGetUniformLocation(program, "sizeY"), scrheight);
glUniform1f(glGetUniformLocation(program, "size"), dotSize);

glDrawArrays(GL_POINTS, 0, dot count);
glfwSwapBuffers(window);
glfwPollEvents();

```

This works very well but I would love to get rid of the low frame rate this causes when I am drawing a ton of points (generally over 10,000 on my small laptop that doesn't actually have a GPU).

Is there any way I can get the GPU to more intelligently clip points that are going to be off screen?

I don't have a lot of time to change things around so it would be great if it were something simple to achieve.

**Tags:** opengl

> **Comments:**
> **username_1**: What kind of laptop does not have a GPU?  
> **username_2**: You need to profile your code to see where the problem is. Drawing 10,000 points should be no problem for even a low-end GPU. Are you actually uploading the data on every draw call? If so, don't do that. You're using `GL_STATIC_DRAW`, so it looks like your data is not changing. If that's the case, upload it once and draw it on every frame.  
> **username_3**: Are you creating a new vertex buffer each frame? If so it would be more efficient to create it only once, then update its content when it changes. Nowadays, even a low end laptop with an integrated chipset can draw hundreds of thousands of points at a good framerate.  
> **username_4**: @username_1 I assume he means it has an Intel integrated GPU instead of a beefier off-chip one.  
> **username_1**: @username_4 Thats my point its still a GPU! You will have hard timefinding laptops with really no GPU.  
> **username_5**: @username_1 "GPU" is very common colloquial nomenclature for a dedicated graphics card, excluding integrated graphics processors. Don't be pedantic. :P  
> **username_1**: @username_5 well, most GPUs on laptops tend to be integrated to the motherboard. So does that mean laptops do not have them?  
> **username_5**: @username_1 It's vague, depends on the model of the GPU whether or not I would consider it worthy of being called a "GPU" in such a colloquial way as to imply that it e.g. has drivers which support OpenGL > 1.1.  

---

## 2 answers

### Answer by username_6 on 2017-08-18. Score: 8

You only need to create the VBOs and VAO once and then you can reuse them every frame.

```
void init(){

    glGenVertexArrays(1, &VAO1);
    glBindVertexArray(VAO1);

    glGenBuffers(1, &VBO1);
    glBindBuffer(GL_ARRAY_BUFFER, VBO1);
    glBufferData(GL_ARRAY_BUFFER, sizeof(data1), data1, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, VBO1);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenBuffers(1, &VBO2);
    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(data2), data2, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);

    uniformLoc_centerX = glGetUniformLocation(program, "centerX");
    uniformLoc_centerY = glGetUniformLocation(program, "centerY");
    uniformLoc_sizeX = glGetUniformLocation(program, "sizeX");
    uniformLoc_sizeY = glGetUniformLocation(program, "sizeY");
    uniformLoc_size= glGetUniformLocation(program, "size");
}

void draw(){
    glUseProgram(program);
    glBindVertexArray(VAO1);

    glUniform1f(uniformLoc_centerX, centerX);
    glUniform1f(uniformLoc_centerY, centerY);
    glUniform1f(uniformLoc_sizeX, scrwidth);
    glUniform1f(uniformLoc_sizeY, scrheight);
    glUniform1f(uniformLoc_size, dotSize);

    glDrawArrays(GL_POINTS, 0, dot count);
}

```

If the data ever changes then all you need to do is:

```
glGenBuffers(1, &VBO1);
glBufferData(GL_ARRAY_BUFFER, sizeof(data1), data1, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBO2);
glBufferData(GL_ARRAY_BUFFER, sizeof(data2), data2, GL_STATIC_DRAW);

```


---

### Answer by username_7 on 2017-08-20. Score: 2

To start with, you should (almost) never have a glGen\*() call in your render loop. Do that during initialization only.

It looks like your vertex data isn't changing. Don't re-set the buffer data, just send it once during initialization.

For the application you've described, about the only thing that should be in your render loop is bindBuffer, setting your uniforms, clear, draw and present.

Fixing those issues will likely have a significant perf impact. If that still isn't enough, look at spatial partitioning and frustum culling - in 2D, your frustum is just going to be a box - to more intelligently clip your data CPU-side. Google "quad trees" to get started.

Also, depending on the use case, you MIGHT be better off just doing this in Unity or another off-the-shelf engine. They already provide much of this functionality. (However, I'm all for roll-your-own for the fun factor, and a full engine may be overkill for this.)

And never forget: the profiler is your friend. Without it, everything else is just professional guessing.


---

