3D Fireworks Effect in C/C++ using sine or cosine function

前端 未结 2 2028
天命终不由人
天命终不由人 2021-01-25 05:49

I am trying to implement fireworks effect in C. I have a cube with dimensions 10x10x10. A rocket starts from the ground, and when it reaches 8th floor it explodes. Here\'s the p

相关标签:
2条回答
  • 2021-01-25 06:14

    Heh I did find some time (done in 1.5 hod) and will for this funny stuff :)

    OK first some updates in the LED_cube class to support voxel point output and dimming the rest is the same as for the sphere from your another question ...

    //---------------------------------------------------------------------------
    //--- 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
    //---------------------------------------------------------------------------
    //--------------------------------------------------------------------------
    
    • the important stuff are:
    • void mul(int mul); - used for dimming out the whole voxel map
    • void point(int x,int y,int z,int col); - used to set collor of single voxel

    Now the particles

    //---------------------------------------------------------------------------
    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
    //---------------------------------------------------------------------------
    

    this is how to draw the scene:

    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();
    

    This is how to update simulation in some timer (double dt=timer interval in seconds !!!)

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

    This is how it looks

    particles

    Sorry for the banner but I do not have anything solid for gif conversion and this site will not accept wmv ... You have to play with constants to match desired output on your LED cube size constants to play with:

    1. whole cube map dimm rate (cube.mul(200)) currently (200/256) per frame
    2. speeds,intensities v0,v1,i0,i1
    3. number of new particles after explosion currently 50
    4. particle intensity dimm rate after explosion currently 0.95

    [Notes]

    List<> is just template for dynamic array can use anything from std:: or own array ...

    Do not forget to set dt constant to time elapsed between updates. Hope I did not forget to copy something. Hope it helps

    0 讨论(0)
  • 2021-01-25 06:20

    It's better to do this using an upside down parabola instead of sin/cos. At the point of explosion give each particle a random horizontal speed. This speed is constant till the particle hits the ground. You also need to give each particle a random vertical speed. this time, however, you'll add to this speed an amount proportional to -0.5*g*dt^2 (strictly speaking, this is numerically wrong, but you won't notice unless you're doing scientific analysis). Here, g is the acceleration due to gravitation and dt is the time step. That's all.

    0 讨论(0)
提交回复
热议问题