# GLSL Sphere from Vertex

I am working on a particle simulation where we have a lot of spheres which can have different radii. Using this tutorial http://mmmovania.blogspot.de/2011/01/point-sprites-as-spheres-in-opengl33.html (see also code below) I was able to create a sphere from a point, but they all have the size from glPointSize(). Is it possible to extend this with a radius?

#version 330
out vec4 vFragColor;

uniform vec3 Color;
uniform vec3 lightDir;

void main(void)
{
// calculate normal from texture coordinates
vec3 N;
N.xy = gl_PointCoord* 2.0 - vec2(1.0);
float mag = dot(N.xy, N.xy);
if (mag > 1.0) discard;   // kill pixels outside circle
N.z = sqrt(1.0-mag);

// calculate lighting
float diffuse = max(0.0, dot(lightDir, N));

vFragColor = vec4(Color,1) * diffuse;
}


Maybe of interest: I am using #version 120 for my shaders. Or, is there a better way to do this?

So, combining the two answers I now have:

void
Draw::setGeometry(float* geometry, float* velocity, float* radius, GLuint size){
this->_size = size;

glGenBuffers(1, &_vertexData);
glBindBuffer(GL_ARRAY_BUFFER, _vertexData);
glBufferData(GL_ARRAY_BUFFER, _size * 3 * sizeof(float), geometry, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

glGenBuffers(1, &_velocityData);
glBindBuffer(GL_ARRAY_BUFFER, _velocityData);
glBufferData(GL_ARRAY_BUFFER, size * 3 * sizeof(float), velocity, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), radius, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

}


And the drawing method:

void
Draw::paint(GLenum mode){
glBindBuffer(GL_ARRAY_BUFFER, _vertexData);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 0, 0);

glDrawArrays(mode, 0, _size * 3 * sizeof(float));
glDisableVertexAttribArray(0);
}


#version 130

attribute vec3 position;
attribute vec3 velocity;
attribute float size;

uniform mat4 MVP;
uniform mat4 MV;

void main(){
gl_PointSize = size;

gl_Position = MVP * vec4(position, 1.0);
}


The problem is that when gl_PointSize = 15 is set, they are drawn well. When I make it equal with size, then it looks like this: http://picpaste.com/Big_particles-daIBnJCG.png

Works better now. Particles still getting bigger as they move along.

• Geometry shaders are no option? – Mario Jun 25 '14 at 9:15
• They might be, if I find a good enough solution. The particles also have to be colored depending on the radius, but I also don't know how to start on that one. – Daniel Jun 25 '14 at 9:25
• Coloring based on radius... You can do that in the vertex shader or in your particle engine code. My answer already has a particle color property. In my particle engine I pass the color and opacity of the particle to the fragment shader. But I do my sizing using 2 tris and calculate it in the engine code and not in the shader. – badweasel Jun 25 '14 at 9:43
• Is it working now? Maybe you just needed to scale the size as you set it or better yet scale it when you set the attribute. It was likely then just a unit scale issue. Don't forget to either post your own answer or checkmark an answer below. Stack Exchange is a points based system and people do the work of answering in hopes of winning those points. – badweasel Jun 26 '14 at 22:04

Yes.

I would send the radius as an attribute. Which means you'll have to add it in your vertex shader, then pass it to the fragment shader as a varying.

I don't know how you're storing your attributes for the particles. But I usually do this in an array of structs. That way the data is interleaved per particle. So let's say you have something like:

typedef struct {
vec3 vertex;
vec2 texture;
vec4 color;
} TexturedColoredVertex;


You'd add to it at the end:

    float radius;


Then when you're setting up the attribute data you're going to have something like:

glVertexAttribPointer(a_vertexPosition, 3, GL_FLOAT, GL_FALSE, sizeof(TexturedColoredVertex), 0);
glVertexAttribPointer(a_vertexColor, 4, GL_FLOAT, GL_FALSE, sizeof(TexturedColoredVertex), (GLvoid*) offsetof(TexturedColoredVertex, color));
glVertexAttribPointer(a_vertexTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedColoredVertex), (GLvoid*) offsetof(TexturedColoredVertex, texture));


glVertexAttribPointer(a_vertexRadius, 1, GL_FLOAT, GL_FALSE, sizeof(TexturedColoredVertex), (GLvoid*) offsetof(TexturedColoredVertex, radius));


There are of course other things like getting the location of that attribute along with all your others. But hopefully you get the idea.

Then in your particle emitter code just set the radius of each particle and it can even change over time or whatever happens with your particles.

attribute vec3 a_vertexPosition;
attribute lowp vec2 a_vertexTexCoord0;
attribute lowp vec3 a_vertexColor;


Set up a varying and copy the radius to it. This gets it to the fragment shader. Just like you do with the vertex position.

I'm still on OpenGL 2.0, so I'm not using in/out yet. But it's all the same. Maybe in your version instead of claiming a varying float v_radius in both shaders you do out float v_radius in one and in float v_radius in the other.

• I'm quite sure you wouldn't declare a_vertexRadius as a vec3, would you? – Mario Jun 25 '14 at 9:35
• Fixed. That was a typo. Everywhere else I had it as a float. – badweasel Jun 25 '14 at 9:40
• It looks good. I'm trying it out right now – Daniel Jun 25 '14 at 9:56
• I edited my question with the current status, having built on your answer. Still not working, maybe because I am not using the struct and my structures are a bit different. Could you take a look, maybe you can spot something wrong. – Daniel Jun 25 '14 at 12:30

Call glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); You can then write to the built in variable gl_PointSize in your vertex shader. This affects the size of the quad that will be created for the point. If you have a vertex attribute to specify the size of each point you can simply set gl_PointSize from that. The point size is specified in device pixels.

• I've tried this and just added in my shader a static gl_PointSize=15.0 and I am getting this: link ; any ideas? – Daniel Jun 25 '14 at 10:19
• Ignore that, it was an artifact – Daniel Jun 25 '14 at 10:20

After some 12 hours spent on the problem, the solution is a combination of the two before-mentioned solutions:

Thanks to GuyRT's answer, I added the gl_PointSize to the Vertex Shader, which sets the size of the points. Look at his answer for more details.

uniform mat4 MVP;
uniform mat4 MV;

attribute vec3 position;
attribute float velocity;

varying float speed;

void main(){
speed = velocity;

gl_Position = MVP * vec4(position, 1.0);
}


As pointed by badweasel in his answer, transferring from one kernel to another is fairly simple, no matter what version of GLSL you use. I did not color my particles by size in the end, but by velocity, but moving the data from one shader to another should be similar.

#version 130

varying float speed;

void main(){
gl_FragColor = vec4(speed, speed, speed, 1.0);
}


All the fancy sprite stuff from above can be then copied here.

Moving and updating the particles

This was the actual problem where I got stuck in the end. After looking at https://code.google.com/p/opengl-tutorial-org/source/browse/tutorial04_colored_cube/tutorial04.cpp I came up with the following:

    //Somewhere in the class
GLuint vboHandles[3];


Init Method

    //Declaring the buffers
glBindAttribLocation(this->getProgram(), 0, "position");
glBindAttribLocation(this->getProgram(), 1, "velocity");

glGenBuffers(3, vboHandles);

glBindBuffer(GL_ARRAY_BUFFER, vboHandles[0]);
glBufferData(GL_ARRAY_BUFFER, _memSize, geometry, GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, vboHandles[1]);
glBufferData(GL_ARRAY_BUFFER, _memSize / 3, velocity, GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, vboHandles[2]);
glBufferData(GL_ARRAY_BUFFER, _memSize / 3, radius, GL_STATIC_DRAW);


Update method

    //Updating positions
glBindBuffer(GL_ARRAY_BUFFER, vboHandles[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte*) NULL);
glBufferData(GL_ARRAY_BUFFER, _memSize, geometry, GL_STATIC_DRAW);


Paint method

    glBindBuffer(GL_ARRAY_BUFFER, vboHandles[0]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboHandles[1]);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboHandles[2]);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 0, 0);

glDrawArrays(mode, 0, _size);  //Mode is GL_POINTS
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);


So again, the answer is based on the two good given answers. For this specific problem, it was a bit harder to implement and combine. Improvements to the code are welcome.

• When are you calling glBindAttribLocation? Unless you call it before linking the program it will have no effect (it might just be working by chance now, but will likely not work with a different GPU) – GuyRT Jun 26 '14 at 11:38