I am kind of beginner with opengl.

I am using point sprites (currently without any texturing) for my particles. I seem to fail to get them uploaded to the GPU memory correctly. I have readed lots of tutorials on VBOs and VAOs and I can not locate the reason why the particles seems to be wrong.

The problem is, that some of the particles are behaving correctly, but others dont. They have random colors even if every one of them should be white and they are not in correct point in space. Also when a particle dies and the size of the array gets decreased, all particles warp in another location.

Here is my particle GPU data struct:

public struct GPUParticle
    public Vector4 Position;
    public Vector4 Color;

    public static int SizeInBytes = Vector4.SizeInBytes * 2;

Here is the VAO, VBO and EBO initialization:

GL.GenBuffers(1, out Vbo);
GL.GenBuffers(1, out Ebo);
GL.GenVertexArrays(1, out Vao);

// Bind the VAO as current

// Bind the VBO to the VAO
GL.BindBuffer(BufferTarget.ArrayBuffer, Vbo);

// Describe the VAO data

GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);

GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, 0, Vector4.SizeInBytes);

// Bind the EBO to the VAO
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Ebo);

// Unbind the VAO

And here is the uploading which I do on every frame:

// Bind the buffer and send the data to the GPU
GL.BindBuffer(BufferTarget.ArrayBuffer, Vbo);

// Invalidate old data
GL.BufferData (BufferTarget.ArrayBuffer, new IntPtr(Count * GPUParticle.SizeInBytes), IntPtr.Zero, BufferUsageHint.StreamDraw);

// Upload new data
GL.BufferData (BufferTarget.ArrayBuffer, new IntPtr(buffer.Length * GPUParticle.SizeInBytes), buffer, BufferUsageHint.StreamDraw);

// Unbind
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);

//Console.WriteLine ("Uploaded array buffer. Count: {0}", buffer.Length);

// Update index buffer only if there are more elements in the buffer than there has ever been
// Generate index buffer for EBO
indices = new uint[buffer.Length];

// This is really stupid. Perhaps we really do not need any indices?
for(ushort i=0; i < buffer.Length; i++)
    indices [i] = i;

// Bind the EBO for uploading
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Ebo);

// Invalidate old data
GL.BufferData (BufferTarget.ElementArrayBuffer, new IntPtr(Count * sizeof(uint)), IntPtr.Zero, BufferUsageHint.DynamicDraw);

// Upload new data
GL.BufferData (BufferTarget.ElementArrayBuffer, new IntPtr(buffer.Length * sizeof(uint)), indices, BufferUsageHint.DynamicDraw);

// Unbind EBO
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);

// Save the particle count for drawing and zeroing the buffer
Count = buffer.Length;

Here are the shaders:

#version 330 core
layout(location = 0) in vec4 vertex;
layout(location = 1) in vec4 color;

uniform mat4 mP;
uniform mat4 mV;

out vec4 fragColor;
out vec4 pos; // For debugging

void main(){
    fragColor = color;
    pos = vertex;
    gl_Position = mP * mV * vec4(vertex.xyz, 1.0);

#version 330 core
in vec4 fragColor;
in vec4 pos;

layout(location = 0) out vec4 color;

void main(){
    color = fragColor;
    //color = vec4(1,1,1,1);
    //color = pos;

I have simplified the code a bit, but this is basically what I do. I am unable to spot what I am doing wrong.

The most weird thing is, that when in vertex shader I swap the color to be used as vertex and vertex to be used as color, the motion of the particles gets corrected, but the colors are still going haywire.

Any suggestions? I am out of ideas myself. Is the VAO initialization / uploading code correct?

  • \$\begingroup\$ This is just a small suggestion. Why don't you store positions as Vector3? In the shader you are not using the fourth component anyway. The same for colour if you are not using alpha. This would save on memory and bandwidth. However, there may be other concerns like caching and alignment, so I don't want to say you should. But it may be an area of optimisation to think about. \$\endgroup\$
    – DaleyPaley
    Commented Jul 16, 2013 at 1:23
  • \$\begingroup\$ You are absolutely right. The position was actually a Vector3 before, but I was fiddling around and changed it to see if it would help the problem with possibly misaligned data. That's why the size value in the VertexAttribPointer function call was 3, but the problem was somewhere else at that time. But it got left as Vector4 as it is here now. \$\endgroup\$
    – Lasse
    Commented Jul 16, 2013 at 2:40
  • \$\begingroup\$ @DaleyPaley (forgot to add your name to the last comment) I also seem to fail to send correct vec3 + vec3 + vec2 data to the GPU. Here is my sphere: bit.ly/147bcPt and bit.ly/1biD1rb \$\endgroup\$
    – Lasse
    Commented Jul 16, 2013 at 3:08
  • \$\begingroup\$ Wow, cool images :-D The last parameter in the VertexAttribPointer is the offset to the start of the attrib stream. So for your uvs it should be Vector3.SizeInBytes+Vector3.SizeInBytes (assuming you have pos,col,uv). Did you do that? \$\endgroup\$
    – DaleyPaley
    Commented Jul 16, 2013 at 4:20
  • \$\begingroup\$ @DaleyPaley Yes, I do that. Here's what I do: GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0); GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 0, Vector3.SizeInBytes); GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 0, Vector3.SizeInBytes * 2); But that does not seem to do the trick. I think I know that the alignment of the data I send is wrong, because OpenGL draws some of those normals too. The sphere generator code is from here: bit.ly/12SU2zS and I think it should be correct if I did not miscalculate it myself. \$\endgroup\$
    – Lasse
    Commented Jul 16, 2013 at 15:32

1 Answer 1


To answer my own question, the problem was on this line:

GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);

While it should have been:

GL.VertexAttribPointer(0, 4, VertexAttribPointerType.Float, false, 0, 0);

Works like a charm now. And I can facepalm :)


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .