使用正弦或余弦函数在C / C ++中进行3D烟花效果

时间:2014-07-25 16:05:01

标签: c++ c animation sine cosine

我正在尝试用C实现烟花效果。我有一个尺寸为10x10x10的立方体。火箭从地面开始,当它到达8楼时,它会爆炸。这是我不能做的 - 爆炸。如何使用正弦或余弦函数实现此功能?enter image description here

a busy cat

所以在点(5,0,7)//(x,y,z)//火箭飞向空中

for (j=0; j<9; j++) {
    setpoint(x, y, j);
    delay(100);
    clean();  //clears everything
}

爆炸发生了这一点。如何实现这一目标?它也可以在随机位置闪烁。提前谢谢。

2 个答案:

答案 0 :(得分:5)

嘿,我确实找到了一些时间(在1.5 hod完成)并将为这个有趣的东西:)

首先确定LED_cube类中的一些更新以支持体素点输出,其余的调暗与另一个问题中的球体相同...

//---------------------------------------------------------------------------
//--- LED cube class ver: 1.01 ----------------------------------------------
//---------------------------------------------------------------------------
#ifndef _LED_cube_h
#define _LED_cube_h
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
const int _LED_cube_size=32;
//---------------------------------------------------------------------------
class LED_cube
    {
public:
    int n,map[_LED_cube_size][_LED_cube_size][_LED_cube_size];

    LED_cube()              { n=_LED_cube_size; }
    LED_cube(LED_cube& a)   { *this=a; }
    ~LED_cube()             { }
    LED_cube* operator = (const LED_cube *a) { *this=*a; return this; }
    //LED_cube* operator = (const LED_cube &a) { /*...copy...*/ return this; }
    void cls(int col);                                  // clear cube with col 0x00BBGGRR
    void mul(int mul);                                  // mull all channels by mul and then shr by 8
    void point(int x,int y,int z,int col);              // draws voxel with col 0x00BBGGRR
    void sphere(int x0,int y0,int z0,int r,int col);    // draws sphere surface with col 0x00BBGGRR
    void glDraw();                                      // render cube by OpenGL as 1x1x1 cube at 0,0,0
    };
//---------------------------------------------------------------------------
void LED_cube::cls(int col)
    {
    int x,y,z;
    for (x=0;x<n;x++)
     for (y=0;y<n;y++)
      for (z=0;z<n;z++)
       map[x][y][z]=col;
    }
//---------------------------------------------------------------------------
void LED_cube::mul(int mul)
    {
    union { BYTE db[4]; int dd; } c;
    int x,y,z,i;
    for (x=0;x<n;x++)
     for (y=0;y<n;y++)
      for (z=0;z<n;z++)
        {
        c.dd=map[x][y][z];
        i=c.db[0]; i=(i*mul)>>8; c.db[0]=i;
        i=c.db[1]; i=(i*mul)>>8; c.db[1]=i;
        i=c.db[2]; i=(i*mul)>>8; c.db[2]=i;
        map[x][y][z]=c.dd;
        }
    }
//---------------------------------------------------------------------------
void LED_cube::point(int x,int y,int z,int col)
    {
    if ((x>=0)&&(x<n))
     if ((y>=0)&&(y<n))
      if ((z>=0)&&(z<n))
       map[x][y][z]=col;
    }
//---------------------------------------------------------------------------
void LED_cube::sphere(int x0,int y0,int z0,int r,int col)
    {
    int x,y,z,xa,ya,za,xb,yb,zb,xr,yr,zr,xx,yy,zz,rr=r*r;
    // bounding box
    xa=x0-r; if (xa<0) xa=0; xb=x0+r; if (xb>n) xb=n;
    ya=y0-r; if (ya<0) ya=0; yb=y0+r; if (yb>n) yb=n;
    za=z0-r; if (za<0) za=0; zb=z0+r; if (zb>n) zb=n;
    // project xy plane
    for (x=xa,xr=x-x0,xx=xr*xr;x<xb;x++,xr++,xx=xr*xr)
     for (y=ya,yr=y-y0,yy=yr*yr;y<yb;y++,yr++,yy=yr*yr)
        {
        zz=rr-xx-yy; if (zz<0) continue; zr=sqrt(zz);
        z=z0-zr; if ((z>0)&&(z<n)) map[x][y][z]=col;
        z=z0+zr; if ((z>0)&&(z<n)) map[x][y][z]=col;
        }
    // project xz plane
    for (x=xa,xr=x-x0,xx=xr*xr;x<xb;x++,xr++,xx=xr*xr)
     for (z=za,zr=z-z0,zz=zr*zr;z<zb;z++,zr++,zz=zr*zr)
        {
        yy=rr-xx-zz; if (yy<0) continue; yr=sqrt(yy);
        y=y0-yr; if ((y>0)&&(y<n)) map[x][y][z]=col;
        y=y0+yr; if ((y>0)&&(y<n)) map[x][y][z]=col;
        }
    // project yz plane
    for (y=ya,yr=y-y0,yy=yr*yr;y<yb;y++,yr++,yy=yr*yr)
     for (z=za,zr=z-z0,zz=zr*zr;z<zb;z++,zr++,zz=zr*zr)
        {
        xx=rr-zz-yy; if (xx<0) continue; xr=sqrt(xx);
        x=x0-xr; if ((x>0)&&(x<n)) map[x][y][z]=col;
        x=x0+xr; if ((x>0)&&(x<n)) map[x][y][z]=col;
        }
    }
//---------------------------------------------------------------------------
void LED_cube::glDraw()
    {
    #ifdef __gl_h_
    int x,y,z;
    float p[3],dp=1.0/float(n-1);
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE,GL_ONE);

    glPointSize(2.0);

    glBegin(GL_POINTS);

    for (p[0]=-0.5,x=0;x<n;x++,p[0]+=dp)
     for (p[1]=-0.5,y=0;y<n;y++,p[1]+=dp)
      for (p[2]=-0.5,z=0;z<n;z++,p[2]+=dp)
        {
        glColor4ubv((BYTE*)(&map[x][y][z]));
        glVertex3fv(p);
        }
    glEnd();
    glDisable(GL_BLEND);
    glPointSize(1.0);
    #endif
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
//--------------------------------------------------------------------------
  • 重要的东西是:
  • void mul(int mul); - 用于调整整个体素图
  • void point(int x,int y,int z,int col); - 用于设置单个体素的collor

现在是粒子

//---------------------------------------------------------------------------
class particle
    {
public:
    double  x, y, z;    // position
    double vx,vy,vz;    // velocity
    double ax,ay,az;    // acceleration driving force/m after update is reseted
    double i;           // intensity
    particle()
        {
         x=0.0;  y=0.0;  z=0.0;
        vx=0.0; vy=0.0; vz=0.0;
        ax=0.0; ay=0.0; az=0.0;
        i=0.0;
        };
    particle(particle& a){ *this=a; };
    ~particle(){};
    particle* operator = (const particle *a) { *this=*a; return this; };
//  particle* operator = (const particle &a) { ...copy... return this; };

    void update(double dt)
        {
        double c0,c;
        // gravity
        ay-=9.81;
        // friction in gass
        c=0.001;
        if (vx>0.0) c0=-c; else c0=+c; ax+=vx*vx*c0;
        if (vy>0.0) c0=-c; else c0=+c; ay+=vy*vy*c0;
        if (vz>0.0) c0=-c; else c0=+c; az+=vz*vz*c0;
        // friction in liquid
        c=0.0;
        ax-=vx*vx*vx*c;
        ay-=vy*vy*vy*c;
        az-=vz*vz*vz*c;
        // D'ALembert
        vx+=ax*dt;
        vy+=ay*dt;
        vz+=az*dt;
         x+=vx*dt;
         y+=vy*dt;
         z+=vz*dt;
        // reset acceleration
        ax=0.0; ay=0.0; az=0.0;
        }
    };
//---------------------------------------------------------------------------
List<particle> particles; // use any list/array you have at your disposal you need just function add and delete item
//---------------------------------------------------------------------------

这是绘制场景的方法:

cube.mul(200);          // dimm the voxel map insted of clearing it  (intensity*=200/256)
for (int i=0;i<particles.num;i++)
    {
    particle *p=&particles[i];
    int j=double(255.0*p->i);
    if (j<0) j=0;
    if (j>255) j=255;
    cube.point(p->x,p->y,p->z,0x00010101*j);
    }
cube.glDraw();

这是如何在某个计时器中更新模拟(双dt =计时器间隔,以秒为单位!!!)

double i0=1.0; // intensity at shoot start
double i1=0.9*i0; // intensity after explosion
double v0=0.6*double(_LED_cube_size); // shoot start speed
double v1=0.5*v0,v1h=0.5*v1; // explosion speed
if (particles.num==0) // shoot new particle if none in list
    {
    particle p;
    p.x=_LED_cube_size>>1;
    p.y=0.0;
    p.z=_LED_cube_size>>1;
    p.vy=v0;
    p.i=i0;
    particles.add(p);
    }
for (int i=0;i<particles.num;i++) // update all particles in list
    {
    particle *p=&particles[i];
    p->update(dt);
    if (fabs(p->i-i0)<1e-6)     // intensity detect state before explosion
        {
        if (p->vy<=0.0)         // explode near/after peak reached
            {
            particle q;
            q.x=p->x;               // copy position
            q.y=p->y;
            q.z=p->z;
            q.i=i1;                 // new intensity
            particles.del(i);       // remove old particle
            i--;
            for (int j=0;j<50;j++)  // add new random particles
                {
                q.vx=v1*Random()-v1h;
                q.vy=v1*Random()-v1h;
                q.vz=v1*Random()-v1h;
                particles.add(q)-v1h;
                }
            continue;               // avoid usage of p pointer after delete
            }
        }
    else{                       // after explosion
        p->i*=0.95;             // dimm intensity
        }
    if ((p->y<0.0)||(p->i<0.01))// remove particles below the ground or too dimmed out
        {
        particles.del(i);
        i--;
        continue;               // avoid usage of p pointer after delete
        }
    }

这就是它的外观

particles

对不起横幅,但我没有任何可靠的gif转换,这个网站不接受wmv ...你必须使用常量来匹配你的LED立方体大小常量所需的输出:

  1. 整个立方体贴图dimm rate(cube.mul(200))当前(200/256)每帧
  2. 速度,强度v0,v1,i0,i1
  3. 目前爆炸后新颗粒的数量50
  4. 爆炸后的颗粒强度dimm率目前为0.95
  5. <强> [注释]

    List<>只是动态数组的模板,可以使用std::或自己的数组中的任何内容......

    不要忘记将dt常量设置为更新之间经过的时间。希望我没有忘记复制一些东西。希望它有所帮助

答案 1 :(得分:2)

使用倒置抛物线代替sin / cos更好。在爆炸点处给每个粒子一个随机的水平速度。这个速度是恒定的,直到粒子撞击地面。您还需要为每个粒子提供随机垂直速度。但是,这一次,你将这个速度加到与-0.5*g*dt^2成比例的位置(严格来说,这在数字上是错误的,但除非你进行科学分析,否则你不会注意到) 。这里,g是由于引力引起的加速度,dt是时间步长。这就是全部。