OpenGL中的雪花模拟?

时间:2011-08-01 13:32:04

标签: objective-c opengl

我想使用OpenGL制作雪花动画。任何人都可以建议我一些教程或示例代码吗?

3 个答案:

答案 0 :(得分:2)

一种可能的解决方案是使用particle system。我曾经从中做过一些爆炸效果,我认为这非常接近你想要的。

这是one of the tutorials I used,我认为这可能会有所帮助(顺便说一下,该网站上有很多很好的教程,你可以查看它们。)

另外,对于雪花一代,你可以使用相同的薄片,但如果你想要更漂亮的东西(不太花哨,但相对容易),你可以使用三角形条纹(教程使用)来实现更好因为雪花是对称的。

答案 1 :(得分:2)

如果要使用3D雪花,可以使用transform feedback计算顶点着色器中的粒子物理和instancingPoint sprites应该使广告牌更快,并使用更少的内存来存储顶点。 (每个雪花只需要一个。)

在顶点着色器中运行粒子系统会使它快几倍,而数学基本保持不变。

您还可以使用3D纹理来抵消阻尼计算,以便可以产生明显的湍流 如果您使用高度贴图作为地面,则可以使用该数据重置不再可见的雪花。

转换反馈和实例化在第12章的OpenGL SuperBible (Fifth Edition)中进行了解释,精神点在第7章中。The source code for all examples is available online. Mac OS X的示例代码仅进入第7章but it should be possible to make most of it work.

我找不到任何好的在线教程,但代码评论很好。变换反馈示例称为“植绒”。对于雪花模拟,一个顶点着色器应该足以在一次通过中更新和重新排列粒子。

如果你想要大量快速移动的雪,water particles from Nvidia's Cascades Demo(从第114页开始)显示了一种伪造大量粒子的有趣方法。

答案 2 :(得分:0)

#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;
}