Sample OpenGL shader code for the particle simulation (Pixel shader with GPU textures)
From SurfLab
Contents |
[edit]
Download files
[edit]
Sample GLSL code for the particle simulation
[edit]
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)
[edit]
CPU side
main.cpp
[edit]
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;
}
[edit]
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;
}
}
[edit]
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);
}
[edit]
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);
}
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);
}
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()");
};
[edit]
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;
}
[edit]
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);
}
[edit]
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);
}
}
}
[edit]

