Snow flake simulation in OpenGL?
I want to do an animation fo开发者_如何学Pythonr snow flakes using OpenGL. Can anyone suggest me some tutorial or sample code?
You can use transform feedback to calculate the particle physics in the vertex shader and instancing if you want to use 3D snowflakes. Point sprites should make billboards faster and use less memory for storing vertices. (You only need one per snowflake.)
Running the particle system in the vertex shader will make it a few times faster while the math essentially stays the same.
You could also use a 3D texture to offset the damping calculation so you can have visible turbulences.
If you use a heightmap for the ground, you can use that data to reset snowflakes that aren't visible anymore.
Transform feedback and instancing are explained in OpenGL SuperBible (Fifth Edition) in chapter 12, point sprites are in chapter 7. The source code for all examples is available online. The example code for Mac OS X only goes up to chapter 7, but it should be possible to make most of it work.
I couldn't find any good online tutorials, but the code well commented. The transform feedback example is called "flocking". For a snowflake simulation, one vertex shader should be enough for both updating and redering the particles in one pass.
If you want lots of fast moving snow, the water particles from Nvidia's Cascades Demo (starting at page 114) show an interesting approach to faking a large amount of particles.
One possible solution is use a particle system. I once made some explosion effects from it, and I think that is pretty close to what you want.
Here's one of the tutorials I used, and I think this might be helpful (BTW, there are many good tutorials on that site, you could check them out).
Also, for the snow flake generation, you could just use identical flakes, but if you want fancier things (not too fancy, but relatively easy), you could use triangle stripes (which is used by the tutorial) to achieve better effects, since snow flakes are symmetric.
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glut.h>
#define PEATALS_NUMBER 100
#define X 0
#define Y 1
#define ORG_X 2
#define ORG_Y 3
#define SIZE 4
#define GROWING 5
#define SPEED 5
struct timeval start;
unsigned long int last_idle_time;
GLdouble size=5;
GLboolean growing=true;
GLdouble tab[PEATALS_NUMBER][7];
unsigned int get_ticks(){
struct timeval now;
gettimeofday(&now, NULL);
return (now.tv_sec - start.tv_sec) * 1000 +
(now.tv_usec - start.tv_usec) / 1000;
}
void init(){
for(int i=0;i<PEATALS_NUMBER;i++){
tab[i][X]=-300+rand()%600;
tab[i][Y]=200+rand()%500;
tab[i][ORG_X]=tab[i][X];
tab[i][ORG_Y]=tab[i][Y];
tab[i][SIZE]=1+rand()%9;
tab[i][GROWING]=rand()%1;
tab[i][SPEED]=rand()%10;
}
}
void Idle(){
unsigned long int time_now = get_ticks();
for(int i=0;i<PEATALS_NUMBER;i++){
tab[i][Y] -= (tab[i][SPEED]+40.0) * (time_now - last_idle_time) / 1000.0;
if(tab[i][Y]<-200.0)tab[i][Y]=tab[i][ORG_Y];
if(tab[i][SIZE]>5){
tab[i][GROWING]=0;
}
if(tab[i][SIZE]<1){
tab[i][GROWING]=1;
}
if(tab[i][GROWING]==1.0){
tab[i][SIZE]+=8.0 * (time_now - last_idle_time) / 1000.0;
tab[i][X] -= (tab[i][SPEED]+1.0) * (time_now - last_idle_time) / 1000.0;
}
else{
tab[i][SIZE]-=8.0 * (time_now - last_idle_time) / 1000.0;
tab[i][X] += (tab[i][SPEED]+2.0) * (time_now - last_idle_time) / 1000.0;
}
}
last_idle_time = time_now;
glutPostRedisplay();
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(600, 400);
gettimeofday(&start, NULL);
init();
// size of window
glutCreateWindow(argv[0]);
glutIdleFunc(Idle);
glEnable(GL_POINT_SMOOTH);
glutMainLoop();
return 0;
}
精彩评论