题目:给出鹊桥会时的烟花庆祝或闪闪星光或流星飞过,或祥云飘飘
效果:
一、粒子系统动画
动力学动画——粒子系统动画的算法思想:
将许多简单形状的微小粒子作为基本元素聚集起来形成一个不规则的模糊物体,每个粒子均经历出生、成长、衰老和死亡的过程,与粒子有关的每一参数均将受到一个随机过程的控制。
基本步骤:
- 生成新的粒子并加入系统中;
- 赋予每一新粒子以一定的属性;
- 删除那些已经超过其生命周期的粒子;
- 更新原粒子的动态属性并对粒子进行移动和变换;
- 绘制并显示由有生命的粒子组成的图形。
补:
每个粒子有形状、颜色、位置、运动速度、大小、透明度和生命值等属性。
形状是一些简单形状。
粒子不是静态的,可以随时间的改变而变。
虽然看似困难,但其实需要做的也不是那么难。
可以建立struct保存基本粒子的属性,建立class保存一些处理粒子的函数(设置位置、速度、颜色、加速度、生命等属性)
尤其是网络上有许多封装好的类可以直接拿来使用
这里贴出结构体和类定义
#pragma once
/** 粒子结构 */
struct Particle
{
float x, y, z; /**< 粒子的位置 */
unsigned int r, g, b; /**< 粒子的颜色 */
float vx, vy, vz; /**< 粒子的速度(x,y,z方向) */
float ax, ay, az; /**< 粒子在x,y,z上的加速度 */
float lifetime; /**< 粒子生命值 */
float sizeball; /**< 粒子尺寸 */
float dec; /**< 粒子消失的速度 */
};
/** 粒子类 */
class CParticle
{
private:
Particle* data; /**< 粒子指针 */
int numparticle; /**< 粒子数目 */
public:
CParticle(); /**< 构造函数 */
~CParticle(); /**< 析构函数 */
/** 创建粒子数组 */
int Create(long num);
/** 设置和获取颜色属性 */
int SetColor(int r, int g, int b);
int SetColor(int index, int r, int g, int b);
int GetColor(int index, int &r, int &g, int &b);
/** 设置和获取速度属性 */
int SetVelocity(float vx, float vy, float vz);
int SetVelocity(int index, float vx, float vy, float vz);
int GetVelocity(int index, float &vx, float &vy, float &vz);
/** 设置和获取位置属性 */
int SetPosition(float x, float y, float z);
int SetPosition(int index, float x, float y, float z);
int GetPosition(int index, float &x, float &y, float &z);
/** 设置和获取加速度属性 */
int SetAcceleration(float ax, float ay, float az);
int SetAcceleration(int index, float ax, float ay, float az);
int GetAcceletation(int index, float &ax, float &ay, float &az);
/** 设置和获取尺寸属性 */
int SetSize(float sizeball);
int SetSize(int index, float sizeball);
int GetSize(int index, float &sizeball);
/** 设置和获取消失速度属性 */
int SetDec(float dec);
int SetDec(int index, float dec);
int GetDec(int index, float &dec);
/** 设置和获取生命值属性 */
int SetLifeTime(float lifetime);
int SetLifeTime(int index, float lifetime);
int GetLifeTime(int index, float &lifetime);
/** 获取粒子数组地址 */
Particle *GetParticle() { return data; }
/** 获得粒子的数目 */
int GetNumOfParticle() { return numparticle; }
/** 获得粒子所有的属性 */
int GetAll(int index, /**< 索引 */
int &r, int &g, int &b, /**< 粒子的颜色 */
float &x, float &y, float &z, /**< 位置 */
float &vx, float &vy, float &vz, /**< 速度 */
float &ax, float &ay, float &az, /**< 加速度 */
float &sizeball, /**< 大小 */
float &lifetime, /**< 生命时间 */
float &dec /**< 消失速度 */
);
/** 设置粒子的所有属性 */
int SetAll(int index, /**< 索引 */
int r, int g, int b, /**< 粒子的颜色 */
float x, float y, float z, /**< 位置 */
float vx, float vy, float vz, /**< 速度 */
float ax, float ay, float az, /**< 加速度 */
float sizeball, /**< 大小 */
float lifetime, /**< 生命时间 */
float dec /**< 消失速度 */
);
};
详情见粒子系统
二、实现
但是因为刚刚贴出的教程使用glut,我们使用glfw,所以得有些改动。
我们可以在循环内的每一帧用for循环,建立数组,传入buffer,绑定并且绘制,之后更新粒子属性,end
之后便是先前掌握的知识,我们同样可以由简入繁。
- 绘制point
- 绘制triangles
- 绑定纹理
先从简单的点绘制,按照实验一或者是opengl课程按图索骥即可。
三角形同样如此,这样纹理也简单了起来。
三、困境
同样有一些值得探讨的问题,实验中载入图像时碰到了一些问题1.图像
根据实验推出,与图片的深度有关,原格式为24bpp,提高为32bpp则成功。由于原bmp格式原因,背景是黑色,用PS可以清除。
2.混合模式
补充了实验二应该学习的混合函数
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
若不开启,后绘制的像素点的颜色将覆盖先绘制的像素点。我们日常会用到的如上混合,即也是按照先后绘制的顺序覆盖,但多了透明度alpha通道后才能良好地显示。
3.陷阱
在使用完函数后要恢复默认。
例如:默认纹理单元为GL_TEXTURE0,激活GL_TEXTURE1后若不恢复默认,可能导致一些问题。
变量名选取不可重复,主函数外定义,也可以在内部定义,则会带来难寻找的问题。
4.深度(z轴)
之前的实验都是通过绘制顺序的更改来改变前后关系,之前的z轴坐标没有用。
现在学习到,我们需要进行深度测试。
此次实验仍是以二维的角度绘制尚未涉及三维。