zoukankan      html  css  js  c++  java
  • 烟花OpenGL初步实现demo

    在NeHe程序框架基础上初步实现了这个烟花的demo。

    烟花的弹片生存期由life和fade两个值决定。

    烟花的弹片速度由speed和a两个值决定。

    生命值和速度值变换在每次循环中加减运算实现,所以有必要添加一个参数来根据每台电脑的运算速度加以调整优化。

    实现代码如下。所需BMP图片在这里

    //vs2008 & windows7
    #include<windows.h>
    #include<tchar.h>
    #include <gl\gl.h>
    #include <gl\glu.h>
    #pragma comment(lib,"opengl32.lib")
    #pragma comment(lib,"glu32.lib")

    #define MAX_NUM_PARTICLES 20 //粒子数
    #define MAX_NUM_SHELLS 40 //弹片数

    HGLRC hRC=NULL; //OpenGL图形操作描述表
    HDC hDC=NULL; //设备描述表
    HWND hWnd=NULL; //窗口句柄
    HINSTANCE hInstance; //应用程序实例

    bool keys[256]; //键盘按键参数阵列
    bool active=TRUE; //窗口是否活动
    bool fullscreen=TRUE; //是否全屏

    bool rainbow=false; //彩虹模式,改变颜色
    bool sp; //空格键击键标志
    bool rp; //回车键击键标志

    float slowdown=1.0f; //粒子减速控制
    float zoom=-55.0f; //视野变焦

    GLuint loop,loop2,color,delay; //循环参数、当前颜色、延迟
    GLuint texture[1]; //粒子贴图

    float shell_life=5.0f; //弹片高度
    float shell_fade=0.05f;
    float shell_life1=4.0f; //弹片高度
    float shell_fade1=0.05f;
    float sxspeed=0.0f; //弹片速度
    float szspeed=0.0f;
    float syspeed=850.0f;
    float shell_yg=-4.8f;

    float particle_life=2.0f; //粒子高度
    float particle_fade;
    float xspeed; //粒子速度
    float yspeed;
    float zspeed;
    float particle_yg=-2.8f;

    float par_times=2.0f; //速度倍数
    float par_times1=10.0f;

    float x,y,z;
    float x1,y1,z1;

    typedef struct
    {
    bool active; //状态,生存or湮灭
    float life; //粒子生命
    float fade; //衰减速度
    float r,g,b; //颜色
    float x,y,z; //当前位置
    float xd,yd,zd; //速度
    float xg,yg,zg; //加速度 a=1-p[空气]/p[物质]
    }particle; //粒子结构

    typedef struct
    {
    bool active; //状态,生存or湮灭
    float life; //粒子生命
    float fade; //衰减速度
    unsigned int status; //阶段
    float x,y,z; //当前位置
    float xd,yd,zd; //速度
    float xg,yg,zg; //加速度 a=1-p[空气]/p[物质]
    particle particles[MAX_NUM_PARTICLES]; //颗粒
    }shell; //弹片

    shell shells[MAX_NUM_SHELLS]; //弹体

    static GLfloat colors[4][3]= // 颜色值
    {
    {1.0f,1.0f,1.0f},{1.0f,0.0f,0.0f},{1.0f,1.0f,0.0f},{1.0f,0.0f,1.0f}
    };
    //
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息处理函数
    bool NeHeLoadBitmap(LPTSTR szFileName, GLuint *texid); //贴图图像载入
    GLvoid ReSizeGLScene(GLsizei width, GLsizei height); //重新绘制窗口
    int InitGL(GLvoid); //初始化OpenGL
    int DrawGLScene(GLvoid); //画图
    GLvoid KillGLWindow(GLvoid) ; //关闭窗口
    //
    bool NeHeLoadBitmap(LPTSTR szFileName, GLuint *texid) //从一个bmp文件创建贴图
    {
    HBITMAP hBMP; //bmp文件句柄
    BITMAP BMP; // Bitmap数据结构
    glGenTextures(1, texid); // 创建贴图
    hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );
    if (!hBMP)
    return FALSE;
    GetObject(hBMP, sizeof(BMP), &BMP); //获得目标
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // Pixel Storage Mode (Word Alignment / 4 Bytes)
    //创建贴图
    glBindTexture(GL_TEXTURE_2D, *texid);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, BMP.bmWidth, BMP.bmHeight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
    DeleteObject(hBMP);
    return TRUE;
    }//end of NeHeLoadBitmap

    GLvoid ReSizeGLScene(GLsizei width, GLsizei height) //重画窗口
    {
    if (height==0) height=1;
    glViewport(0, 0, width, height); //重置当前窗口
    glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
    glLoadIdentity(); // Reset The Projection Matrix
    gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,200.0f); //视图
    glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
    glLoadIdentity(); // Reset The Modelview Matrix
    }//end of ReSizeGLScene

    int InitGL(GLvoid) //初始化gl
    {
    if (!NeHeLoadBitmap(_T("Data\\Particle.bmp"), &texture[0])) {return FALSE; }//载入贴图
    glShadeModel(GL_SMOOTH); // Enables Smooth Shading
    glClearColor(0.0f,0.0f,0.0f,0.0f); // Black Background
    glClearDepth(1.0f); // Depth Buffer Setup
    glDisable(GL_DEPTH_TEST); // Disables Depth Testing
    glEnable(GL_BLEND); // Enable Blending
    glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Type Of Blending To Perform
    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // Really Nice Perspective Calculations
    glHint(GL_POINT_SMOOTH_HINT,GL_NICEST); // Really Nice Point Smoothing
    glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
    glBindTexture(GL_TEXTURE_2D,texture[0]); // Select Our Texture

    for(loop2=0;loop2<MAX_NUM_SHELLS;loop2++)
    {
    shells[loop2].active=true;
    shells[loop2].status=0; //0-上升阶段
    shells[loop2].life=shell_life1;
    // shells[loop2].fade=float(rand()%100)/1000.0f+0.003f;
    shells[loop2].fade=shell_fade1;
    shells[loop2].xd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].yd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].zd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].xg=0.0f;
    shells[loop2].yg=shell_yg;
    shells[loop2].zg=0.0f;
    for (loop=0;loop<MAX_NUM_PARTICLES;loop++) // 初始化所有贴图
    {
    shells[loop2].particles[loop].active=true; // 使所有粒子为活动
    shells[loop2].particles[loop].life=particle_life; // 所有粒子生命值
    shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; // 随机生命递减速度
    shells[loop2].particles[loop].r=colors[color][0]; //颜色
    shells[loop2].particles[loop].g=colors[color][1];
    shells[loop2].particles[loop].b=colors[color][2];
    shells[loop2].particles[loop].xd=float((rand()%50)-25.0f)*par_times; //随机速度
    shells[loop2].particles[loop].yd=float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].zd=float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].xg=0.0f; //加速度
    shells[loop2].particles[loop].yg=particle_yg;
    shells[loop2].particles[loop].zg=0.0f;
    }
    }
    shells[0].life=shell_life;
    shells[0].fade=shell_fade;
    return TRUE;
    }//end of InitGL

    int DrawGLScene(GLvoid) //画图
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
    glLoadIdentity(); // Reset The Current Modelview Matrix

    switch(shells[0].status)
    {
    case 0: //上升阶段
    {
    if(shells[0].life==shell_life)
    {
    shells[0].x=0.0f;
    shells[0].y=-30.0f;
    shells[0].z=zoom;
    shells[0].xd=sxspeed; //获得初始速度
    shells[0].yd=syspeed;
    shells[0].zd=szspeed;
    //
    for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
    {
    shells[0].particles[loop].x=shells[0].x;
    shells[0].particles[loop].y=shells[0].y;
    shells[0].particles[loop].z=shells[0].z;
    }
    }//if life
    shells[0].x+=shells[0].xd/(slowdown*1000); //新位置
    shells[0].y+=shells[0].yd/(slowdown*1000);
    shells[0].z+=shells[0].zd/(slowdown*1000);
    shells[0].xd+=shells[0].xg; //速度增量
    shells[0].yd+=shells[0].yg;
    shells[0].zd+=shells[0].zg;
    shells[0].life-=shells[0].fade; //生命递减
    if(shells[0].life<0.0f)
    {
    shells[0].status=1; //转到下一个阶段
    shells[0].active=false;
    x1=shells[0].x;
    y1=shells[0].y;
    z1=shells[0].z;
    break;
    }

    for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
    {
    if(shells[0].particles[loop].active)
    {
    shells[0].particles[loop].x+=shells[0].particles[loop].xd/(slowdown*1000); //位置改变
    shells[0].particles[loop].y+=shells[0].particles[loop].yd/(slowdown*1000);
    shells[0].particles[loop].z+=shells[0].particles[loop].zd/(slowdown*1000);
    shells[0].particles[loop].xd+=shells[0].particles[loop].xg; //速度增量
    shells[0].particles[loop].yd+=shells[0].particles[loop].yg;
    shells[0].particles[loop].zd+=shells[0].particles[loop].zg;
    shells[0].particles[loop].life-=shells[0].particles[loop].fade; //生命减少

    x=shells[0].particles[loop].x; //获得位置坐标
    y=shells[0].particles[loop].y;
    z=shells[0].particles[loop].z+zoom;
    glColor4f(shells[0].particles[loop].r,shells[0].particles[loop].g,shells[0].particles[loop].b,shells[0].particles[loop].life); //颜色
    glBegin(GL_TRIANGLE_STRIP); //两个三角画一个矩形
    glTexCoord2d(1,1);glVertex3f(x+0.5f,y+0.5f,z);
    glTexCoord2d(0,1);glVertex3f(x-0.5f,y+0.5f,z);
    glTexCoord2d(1,0); glVertex3f(x+0.5f,y-0.5f,z);
    glTexCoord2d(0,0); glVertex3f(x-0.5f,y-0.5f,z);
    glEnd();

    if(shells[0].particles[loop].life<0.0f) //湮灭
    {
    shells[0].particles[loop].life=particle_life; //获得新生
    shells[0].particles[loop].fade=float(rand()%100)/100.0f+0.03f; //生命递减速度
    shells[0].particles[loop].x=shells[0].x; //新生粒子位置与弹片位置相同
    shells[0].particles[loop].y=shells[0].y;
    shells[0].particles[loop].z=shells[0].z;
    shells[0].particles[loop].xd=xspeed+float((rand()%50)-25.0f)*par_times; //初始速度
    shells[0].particles[loop].yd=yspeed+float((rand()%50)-25.0f)*par_times;
    shells[0].particles[loop].zd=zspeed+float((rand()%50)-25.0f)*par_times;
    shells[0].particles[loop].r=colors[color][0]; //粒子颜色,用参数color改变
    shells[0].particles[loop].g=colors[color][1];
    shells[0].particles[loop].b=colors[color][2];
    }//end of if life

    }//end of if active
    }//end of for loop
    break;
    }//end of case 0:
    case 1:
    {
    if(shells[0].active==false)
    {
    shells[0].active=true;
    for(loop2=1;loop2<MAX_NUM_SHELLS;loop2++)
    {
    shells[loop2].x=x1;
    shells[loop2].y=y1;
    shells[loop2].z=z1;
    }
    }//if !
    for(loop2=1;loop2<MAX_NUM_SHELLS;loop2++)
    {
    // if(shells[loop2].life>0.0f)
    // {
    for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
    {
    if(shells[loop2].life==shell_life1)
    {
    shells[loop2].particles[loop].x=shells[loop2].x;
    shells[loop2].particles[loop].y=shells[loop2].y;
    shells[loop2].particles[loop].z=shells[loop2].z;
    }
    shells[loop2].particles[loop].x+=shells[loop2].particles[loop].xd/(slowdown*1000); //位置改变
    shells[loop2].particles[loop].y+=shells[loop2].particles[loop].yd/(slowdown*1000);
    shells[loop2].particles[loop].z+=shells[loop2].particles[loop].zd/(slowdown*1000);
    shells[loop2].particles[loop].xd+=shells[loop2].particles[loop].xg; //速度增量
    shells[loop2].particles[loop].yd+=shells[loop2].particles[loop].yg;
    shells[loop2].particles[loop].zd+=shells[loop2].particles[loop].zg;
    shells[loop2].particles[loop].life-=shells[loop2].particles[loop].fade; //生命减少

    x=shells[loop2].particles[loop].x; //获得位置坐标
    y=shells[loop2].particles[loop].y;
    z=shells[loop2].particles[loop].z+zoom;
    glColor4f(shells[loop2].particles[loop].r,shells[loop2].particles[loop].g,shells[loop2].particles[loop].b,shells[loop2].particles[loop].life); //颜色
    glBegin(GL_TRIANGLE_STRIP); //两个三角画一个矩形
    glTexCoord2d(1,1);glVertex3f(x+0.5f,y+0.5f,z);
    glTexCoord2d(0,1);glVertex3f(x-0.5f,y+0.5f,z);
    glTexCoord2d(1,0); glVertex3f(x+0.5f,y-0.5f,z);
    glTexCoord2d(0,0); glVertex3f(x-0.5f,y-0.5f,z);
    glEnd();

    if(shells[loop2].particles[loop].life<0.0f) //湮灭
    {
    shells[loop2].particles[loop].life=particle_life; //获得新生
    shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; //生命递减速度
    shells[loop2].particles[loop].x=shells[loop2].x;
    shells[loop2].particles[loop].y=shells[loop2].y;
    shells[loop2].particles[loop].z=shells[loop2].z;
    shells[loop2].particles[loop].xd=xspeed+float((rand()%50)-25.0f)*par_times; //初始速度
    shells[loop2].particles[loop].yd=yspeed+float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].zd=zspeed+float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].r=colors[color][0]; //粒子颜色,用参数color改变
    shells[loop2].particles[loop].g=colors[color][1];
    shells[loop2].particles[loop].b=colors[color][2];
    }
    }//for loop
    // }//if life
    shells[loop2].x+=shells[loop2].xd/(slowdown*1000); //新位置
    shells[loop2].y+=shells[loop2].yd/(slowdown*1000);
    shells[loop2].z+=shells[loop2].zd/(slowdown*1000);
    shells[loop2].xd+=shells[loop2].xg; //速度增量
    shells[loop2].yd+=shells[loop2].yg;
    shells[loop2].zd+=shells[loop2].zg;
    shells[loop2].life-=shells[loop2].fade; //生命递减
    if(shells[1].life<0.0f){shells[1].status=1;}
    }//for loop2
    break;
    }//end of case 1:
    default:
    break;
    }//end of switch

    if (keys[VK_TAB]||shells[1].status==1) //TAB发射一颗新烟花弹
    {
    shells[0].life=shell_life;
    shells[0].status=0;
    for(loop2=0;loop2<MAX_NUM_SHELLS;loop2++)
    {
    shells[loop2].active=true;
    shells[loop2].status=0; //0-上升阶段
    shells[loop2].life=shell_life1;
    // shells[loop2].fade=float(rand()%100)/1000.0f+0.003f;
    shells[loop2].fade=shell_fade1;
    shells[loop2].xd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].yd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].zd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].xg=0.0f;
    shells[loop2].yg=shell_yg;
    shells[loop2].zg=0.0f;
    for (loop=0;loop<MAX_NUM_PARTICLES;loop++) // 初始化所有贴图
    {
    shells[loop2].particles[loop].active=true; // 使所有粒子为活动
    shells[loop2].particles[loop].life=particle_life; // 所有粒子生命值
    shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; // 随机生命递减速度
    shells[loop2].particles[loop].r=colors[color][0]; //颜色
    shells[loop2].particles[loop].g=colors[color][1];
    shells[loop2].particles[loop].b=colors[color][2];
    shells[loop2].particles[loop].xd=float((rand()%50)-25.0f)*par_times; //随机速度
    shells[loop2].particles[loop].yd=float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].zd=float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].xg=0.0f; //加速度
    shells[loop2].particles[loop].yg=particle_yg;
    shells[loop2].particles[loop].zg=0.0f;
    }
    }
    shells[0].life=shell_life;
    shells[0].fade=shell_fade;
    }//if

    return TRUE;
    }//end of DrawGLScene

    <完>

  • 相关阅读:
    每日日报2020.12.1
    每日日报2020.11.30
    981. Time Based Key-Value Store
    1146. Snapshot Array
    565. Array Nesting
    79. Word Search
    43. Multiply Strings
    Largest value of the expression
    1014. Best Sightseeing Pair
    562. Longest Line of Consecutive One in Matrix
  • 原文地址:https://www.cnblogs.com/afarmer/p/1611257.html
Copyright © 2011-2022 走看看