PDA

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



maven
07-07-2011, 04:18 AM
Hi.

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.

Regards,

Andrew

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.EnableClientState(gl.VERTEX_ARRAY);
gl.VertexPointer(4, gl.FLOAT, 0, 0);

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

// Shader program
gl.Enable(gl.POINT_SPRITE_ARB);
gl.TexEnvi(gl.POINT_SPRITE_ARB, gl.COORD_REPLACE_ARB, gl.TRUE);
gl.Enable(gl.VERTEX_PROGRAM_POINT_SIZE_NV);
gl.DepthMask(true);
gl.Enable(gl.DEPTH_TEST);

// 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.UseProgram(m_program);

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

// End shader program
gl.UseProgram(0);
gl.Disable(gl.POINT_SPRITE_ARB);

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

kRogue
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.

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

I have changed
attribute vec2 pointRadius;
to
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?
gl.EnableVertexAttribArrayARB(radiusLocation);


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.

Andrew

kRogue
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]);