Thursday, July 22, 2010

Rendering of particles with random radius

The base program used here is the NVIDIA's oclParticles example provided in the NVIDIA_GPU_Computing_SDK package.

The aim here is to render each particle with a random radius. The interactions and collisions are computed with a constant radius. So, our approach is to create a VBO for the radius and used to render the particles.

First, we created the instance variables for the VBO, CPU and GPU data in the inc/particlesSystem_class.h.

uint m_radiusVBO;
float *m_hRad;
memHandle_t m_dRad;

Then, we edited the src/particleSystem_class.cpp. I'm going to show the changes made per method.

  • allocate memory for the CPU and GPU data, and create the VBO
m_radiusVBO = createVBO(m_numParticles * sizeof(float);

Note that createVBO() is a method previously defined in this class.

  • delete the CPU and GPU data, and the VBO as is did it for the other instance variables
  • First we have to add RADIUS to the enumeration ParticleArray in the inc/particleSystem_class.h.
  • Then, we implement the case RADIUS. Since the radius data is smaller than the positions and velocities data, we need to do the copyArrayFromDevice on each case.
case RADIUS:
hdata = m_hRad;
ddata = m_dRad;
vbo = m_radiusVBO;
copyArrayFromDevice(hdata, ddata, vbo, m_numParticles * sizeof(float));

  • implement the case RADIUS
case RADIUS:
glBindBuffer(GL_ARRAY_BUFFER, m_radiusVBO);
glBufferSubData(GL_ARRAY_BUFFER, start * sizeof(float), count * sizeof(float), data);
glBindBuffer(GL_ARRAY_BUFFER, 0);

  • here is where we fill the data with random values, so inside the loop we initialize the CPU data
m_hRad[i] = frand();

  • we do the same thing than in initGrid(), we initialize again the data with new random numbers
  • at the end of the method we set the array with the new data
setArray(RADIUS, m_hRad, 0, m_numParticles);

  • we assign random radius for the particles that are going to be added to the system when we add the big sphere
m_hRad[index] = frand();
  • then we set the array again
setArray(RADIUS, m_hRad, start, index);

Now, we have to edit the src/shaders.cpp because we need to change the vertex shader, pointRadius now is going to be an attribute instead of an uniform variable. This is because the radius is going to be different for each particle, so every time a particle is going to be render a new value is need to be read.

Since we need to get the info of the positions and the radius from the main.cpp we have to add setRadiusBuffer() to inc/render_particles.cpp to initialize the VBO in the render_particles class with the info obtained from the main.cpp. We set the radius VBO in the main program as did it with the position VBO.

It's time to star rendering the particles, so lets edit the src/render_particles.cpp. So, it can be able to read and render the particles with random radius.

Then, we edit the _drawPoints() method. Basically, we add the following inside the else statement:

GLint r;
if(m_radiusVBO) {

glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_radiusVBO);
r = glGetAttribLocation(m_radiusVBO, "pointRadius");
glVertexAttribPointer(r, 1, GL_FLOAT, GL_FALSE, 0, (void*) 0);

At the end we disable the vertex array.

And finally, we have to comment out the line that gives the uniform values to the shader, if you not comment this line then you still going to be rendering the particles with the same radius.

//glUniform1f( glGetAttribLocation(m_program, "pointRadius"), m_particleRadius );

Now, you are done and you can render particles with different radius using VBO's and shaders.

No comments:

Post a Comment