Sample OpenGL shader code for the particle simulation (Pixel shader with GPU textures)

From SurfLab

Jump to: navigation, search

Contents

Download files

download files

Sample GLSL code for the particle simulation

Particle Simulation with GLSL
Particle Simulation with GLSL

Introduction

This program is based on the project1 of Interactive 3D Graphics and Physics, 08fall taught by Dr. Peters.

Five textures are used: 2 textures for positions, 2 textures for velocities, and 1 texture for initial velocities.

Each pixel shader updates the position and velocity of the corresponding particle based on time stamp.

Requirements:

  • GLEW: The OpenGL Extension Wrangler Library
  • NVIDIA GeForce FX (ATI compatible codes can be found from the GPGPU tutorial below)

CPU side

main.cpp

Initialize Shader

 /******************************************************************************
   Initialization of shaders from file inputs (vert.h & frag.h)
  ******************************************************************************/
 bool initialize_shaders(void)
 {
   char * tmp, * tmp2;
   ifstream fin, fin2;
   //! vertex shaer
   fin.open("vert.h");
   if(!fin.is_open()) {
       cout<<"Vertex shader File Error"<<endl;
       return 0;
   }
   long begin=fin.tellg();
   fin.seekg(0, ios::end);
   long end=fin.tellg();
   int size=end-begin;
   tmp=new char[size+1];
   fin.seekg(0, ios::beg);
   int ii=0; 
   while(fin.good()) {
       tmp[ii]=fin.get();
       if(!fin.eof())ii++;
   }
   tmp[ii]=0;
   vShader=(const GLchar*)tmp;
   fin.close();
   //! fragment shaer
   fin2.open("frag.h");
   if(!fin2.is_open()) {
       cout<<"Fragment shader File Error"<<endl;
       return 0;
   }
   fin2.seekg(0, ios::beg);
   begin=fin2.tellg();
   fin2.seekg(0, ios::end);
   end=fin2.tellg();
   size=end-begin;
   tmp2=new char[size+1];
   fin2.seekg(0, ios::beg);
   ii=0; 
   while(fin2.good()) {
       tmp2[ii]=fin2.get();
       if(!fin2.eof())ii++;
   }
   tmp2[ii]=0;
   fShader=(const GLchar*)tmp2;
   fin2.close();
   const GLchar* source[2] = {vShader, fShader};
   // Check for shader support first
   float version = atof((const char *)glGetString(GL_VERSION));
   cout << "OpenGL v" << version;
   if (version < 2) {
       cout << " <-- ERROR: Need at least OpenGL v2.0. Does your graphics card support shaders?\n";
       exit(-1);
   }
   else {
       cout << " <-- OKAY!\n";
   }
   shader.h_vert = glCreateShader(GL_VERTEX_SHADER);
   printf("handle for vertex shader=%d\n", shader.h_vert);
   glShaderSource(shader.h_vert, 1, (const GLchar**)&source[0], NULL);
   glCompileShader(shader.h_vert);
   if(!printInfoLog(shader.h_vert))        return false;
   shader.h_frag = glCreateShader(GL_FRAGMENT_SHADER);
   printf("handle for fragment shader=%d\n", shader.h_frag);
   glShaderSource(shader.h_frag, 1, (const GLchar**)&source[1], NULL);
   glCompileShader(shader.h_frag);
   if(!printInfoLog(shader.h_frag))        return false;
   shader.h_program = glCreateProgram();
   printf("handle for shader program=%d\n", shader.h_program);
   glAttachShader(shader.h_program, shader.h_vert);
   glAttachShader(shader.h_program, shader.h_frag);
   glLinkProgram(shader.h_program);
   if(!printInfoLog(shader.h_program))     return false;
   printf("shaders initialized\n");
   return true;
 }

Initialize IVP

 /******************************************************************************
   Initialize positions & velocities
  ******************************************************************************/
 void initIVP()
 {
   srand((unsigned)time(0)); 
   for(int i=0; i<texSize*texSize; ++i) {
       float tStamp=-(float)(rand()%100);
       fPosition[i][0]=0.0f; 
       fPosition[i][1]=0.0f; 
       fPosition[i][2]=0.0f; 
       fPosition[i][3]=tStamp; 
       fVelocity[i][0]=(GLfloat)((rand()%80)-40.0); 
       fVelocity[i][1]=(GLfloat)(100.0 + (rand()%100)); 
       fVelocity[i][2]=(GLfloat)((rand()%80)-40.0); 
       fVelocity[i][3]=0.0f; 
   }
 }

Initialize FBO

void initFBO(void) 
{
   // create FBO (off-screen framebuffer)
   glGenFramebuffersEXT(1, &fb); 
   // bind offscreen framebuffer (that is, skip the window-specific render target)
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
   // viewport transform for 1:1 pixel=texel=data mapping
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluOrtho2D(0.0,1,0.0,1);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glViewport(0,0,texSize,texSize);
}

Initialize Texture

GLenum texture_target=GL_TEXTURE_RECTANGLE_ARB;
GLenum internal_format=GL_RGBA32F_ARB;
GLenum texture_format=GL_RGBA;
void setupTexture (const GLuint texID, int width, int height) {
   // make active and bind
   glBindTexture(texture_target,texID);
   // turn off filtering and wrap modes
   glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
   // define texture with floating point format
   glTexImage2D(texture_target,0,internal_format,width,height,0,texture_format,GL_FLOAT,0);
}

glTexImage2D

void transferToTexture (float* data, GLuint texID, int width, int height) {
   glBindTexture(texture_target, texID);
   glTexSubImage2D(texture_target,0,0,0,width,height,texture_format,GL_FLOAT,data);
}

glTexSubImage2D

void createTexture()
{
   glGenTextures(2, texturePosition);
   glGenTextures(3, textureVelocity);
   setupTexture(texturePosition[0], texSize, texSize);
   transferToTexture(fPosition[0],texturePosition[0], texSize, texSize);
   setupTexture(textureVelocity[0], texSize, texSize);
   transferToTexture(fVelocity[0],textureVelocity[0], texSize, texSize);
   setupTexture(texturePosition[1], texSize, texSize);
   setupTexture(textureVelocity[1], texSize, texSize);
   setupTexture(textureVelocity[2], texSize, texSize);
   transferToTexture(fVelocity[0],textureVelocity[2], texSize, texSize);
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_REPLACE); 
   // check if something went completely wrong
   checkGLErrors ("createFBOandTextures()");
};

Simulate Particles

/******************************************************************************
  particle system simulation 
 ******************************************************************************/
void simulation()
{
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
   // attach texture
   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texture_target, texturePosition[writeTex],0);
   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, texture_target, textureVelocity[writeTex],0);
   // viewport transform for 1:1 pixel=texel=data mapping
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluOrtho2D(0.0,1,0.0,1);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glViewport(0,0,texSize,texSize);
   // Position update
   tmode=1;
   glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
   glUseProgram(shader.h_program);
   glActiveTexture(GL_TEXTURE0);
   glBindTexture(texture_target, texturePosition[readTex]);
   glUniform1i(::glGetUniformLocationARB(shader.h_program, "texturePosition"),0);
   glUniform1i(::glGetUniformLocation(shader.h_program, "mode"), tmode);
   glActiveTexture(GL_TEXTURE1);
   glBindTexture(texture_target, textureVelocity[readTex]);
   glUniform1i(::glGetUniformLocationARB(shader.h_program, "textureVelocity"), 1);
   glActiveTexture(GL_TEXTURE2);
   glBindTexture(texture_target, textureVelocity[2]);
   glUniform1i(::glGetUniformLocationARB(shader.h_program, "textureVelStart"), 2);
   glPolygonMode(GL_FRONT,GL_FILL);
   glBegin(GL_QUADS);
   glTexCoord2f(0.0, 0.0);	        glVertex2f(0.0, 0.0);
   glTexCoord2f(texSize, 0.0);	        glVertex2f(1.0, 0.0);
   glTexCoord2f(texSize, texSize);	glVertex2f(1.0, 1.0);
   glTexCoord2f(0.0, texSize);	        glVertex2f(0.0, 1.0);
   glEnd();
   // Velocity update
   tmode=2;
   glDrawBuffer (GL_COLOR_ATTACHMENT1_EXT);
   glUniform1i(::glGetUniformLocation(shader.h_program, "mode"), tmode);
   glBegin(GL_QUADS);
   glTexCoord2f(0.0, 0.0);	        glVertex2f(0.0, 0.0);
   glTexCoord2f(texSize, 0.0);	        glVertex2f(1.0, 0.0);
   glTexCoord2f(texSize, texSize);	glVertex2f(1.0, 1.0);
   glTexCoord2f(0.0, texSize);	        glVertex2f(0.0, 1.0);
   glEnd();
   checkFramebufferStatus();
   checkGLErrors("simulation()");
   glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
   glReadPixels(0, 0, texSize, texSize,texture_format,GL_FLOAT,fPosition);
   glUseProgram(0);
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
   glActiveTexture(GL_TEXTURE0);
   // swap textures
   writeTex=(writeTex+1)%2;
   readTex=(readTex+1)%2;
}

Render Particles

/******************************************************************************
  Rendering particles
 ******************************************************************************/
void drawParticles()
{
   glPointSize(4.0);
   glBegin(GL_POINTS);
   for(int i=0; i<texSize*texSize; ++i)
       glVertex3f(fPosition[i][0], fPosition[i][1], fPosition[i][2]);
   glEnd();
   glPointSize(1.0);
}

GPU side

frag.h

   #extension GL_ARB_texture_rectangle : enable
   uniform sampler2DRect texturePosition; 
   uniform sampler2DRect textureVelocity; 
   uniform sampler2DRect textureVelStart; 
   varying vec2 vTexCoord;
   uniform int mode;
   void main()
   {
       // Update position
       if(mode==1) {
           vec4 tmpColor = vec4(texture2DRect(texturePosition,vTexCoord).rgba);
           float tStamp = tmpColor.a;
           if(tStamp>0.00 && tStamp<50.0) {
               vec3 vel = texture2DRect(textureVelocity,vTexCoord).xyz;
               gl_FragColor.r=tmpColor.r+vel.x*0.0005;
               gl_FragColor.g=tmpColor.g+vel.y*0.0005;
               gl_FragColor.b=tmpColor.b+vel.z*0.0005;
               gl_FragColor.a=tStamp+1.0;
           }
           // initialize position
           else if(tStamp>=50.0) {
               gl_FragColor.r=0.0;
               gl_FragColor.g=0.0;
               gl_FragColor.b=0.0;
               gl_FragColor.a=0.0;
           }
           else {
               gl_FragColor.a=tStamp+1.0;
           }
       }
       // Update velocity
       else {
           gl_FragColor = vec4(texture2DRect(textureVelocity,vTexCoord).rgba);
           float tStamp = texture2DRect(texturePosition,vTexCoord).a;
           if(tStamp>0.00 && tStamp<50.0) {
               gl_FragColor.g-=9.8;
           }
           // initialize velocity
           else if(tStamp>=50.0) {
               gl_FragColor = vec4(texture2DRect(textureVelStart,vTexCoord).rgba);
           }
       }
   }

References

Personal tools