View Full Version : Pass/use additional data VBO in shader

07-07-2011, 04:18 AM

I am using a vertex shader and a pixel shader to draw an array of points to appear as spheres. Each point should have a different color and a different radius. Right now I have this working but have to set the radius of each sphere with the following call

int prloc = gl.GetAttribLocationARB((int)m_program, "pointRadius");
gl.VertexAttrib2fARB(prloc, (float)0.5f, 0.0f);

I am now trying to get this to work using Vertex Buffer Objects (VBO). I am able to pass the vertex locations of each point and the color of each point with VBOs but have not been able to figure out how to pass a unique radius for each point. I tried passing the radius as the w coordinate of the vertex but this causes a run time error. Is there another buffer that could be passed to the shader that I could populate a radius in? Any other suggestions or references on how to do this would be appreciated.



The code for the shaders I am using are as follows:

// vertex shader
string vertexShader =
@"attribute vec2 pointRadius; // point size in world space
uniform float pointScale; // scale to calculate size in pixels
uniform float densityScale;
uniform float densityOffset;
void main()
// calculate window-space point size
vec3 posEye = vec3(gl_ModelViewMatrix * vec4(gl_Vertex.xyz, 1.0));
float dist = length(posEye);
gl_PointSize = pointRadius.x * (pointScale / dist);
// gl_PointSize = gl_Vertex.w * (pointScale / dist); // This did not work
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);

gl_FrontColor = gl_Color;

// pixel shader for rendering points as shaded spheres
string spherePixelShader =
@"void main()
const vec3 lightDir = vec3(0.577, 0.577, 0.577);

// calculate normal from texture coordinates
vec3 N;
N.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 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));

gl_FragColor = gl_Color * diffuse;

and the code to draw the points/spheres using VBO´s

// Bind the arry for the vertices
gl.BindBufferARB(gl.ARRAY_BUFFER_ARB, buffers[0]);
gl.VertexPointer(4, gl.FLOAT, 0, 0);

// Bind the array for the colors
gl.BindBufferARB(gl.ARRAY_BUFFER_ARB, buffers[1]);
gl.ColorPointer(4, gl.FLOAT, 0, 0);

// Shader program

// set particle radius // This is what I would like to move into the shader so each point has its own radius!
int prloc = gl.GetAttribLocationARB((int)m_program, "pointRadius");
gl.VertexAttrib2fARB(prloc, (float)0.5f, 0.0f);


gl.DrawArrays(gl.POINTS, 0, numpoints);

// End shader program

// Release the VBO
gl.BindBufferARB(gl.ARRAY_BUFFER_ARB, 0);

07-07-2011, 07:08 AM
There are two way: look into gl_MultiTexCoord[] or do the right thing: stop using the built in (i.e. fixed function pipeline) attributes and make your own.

07-07-2011, 03:13 PM
Made some progress.

I have changed
attribute vec2 pointRadius;
attirbute float pointRadius;

in the shader and added the following code before the gl.DrawArrays()

// Bind the array for the radius
int radiusLocation = gl.GetAttribLocationARB((int)m_program, "pointRadius");
gl.BindBufferARB(radiusLocation, buffers[2]);
gl.VertexAttribPointerARB(radiusLocation, 1, gl.FLOAT, false, 0, (IntPtr)0); // the last 0 is an offset?

This sorta/kinda works. It compiles, runs, but draws points of all kinds of intersting sizes. I think the last argument, (IntPtr)0, in the call to VertexAttribPointerARB is incorrect.

When using VBO arrays what pointer do I use here and how do I get it?

Would you also stop using the Color built in attribute?

Appreciate any help.


07-08-2011, 12:30 AM
The guilty call is this:

gl.BindBufferARB(radiusLocation, buffers[2]);

it should be:

gl.BindBufferARB(GL_ARRAY_BUFFER, buffers[2]);