没有使用transformfeedback的粒子系统
来源:互联网 发布:javascript事件委托 编辑:程序博客网 时间:2024/06/02 23:28
注意:这是一个十分基础的粒子系统,没有billboard没有几何着色器没有光照没有噪声处理,算是粒子系统的一个小基础
上周通过OpenGL编程指南用TransFormFeedback技术按照书上那不完全的代码补全了粒子碰撞效果,然后我本意是想做一个火球效果。。。。。结果我觉得我还是先一步步来做一个基础的粒子系统。
粒子系统的主要成分就是一个粒子发射器类,我们写好该类后,可以通过调整参数实现各种不同的效果。
首先是粒子结构体:
struct Particle { vec3 Position, Velocity;//定义粒子的位置和速度 vec4 Color;//定义粒子颜色 GLfloat Life;//定义粒子生命周期 Particle() : Position(0.0f), Velocity(0.0f), Color(1.0f), Life(0.0f) { }};
然后是粒子发射器类:
class ParticleGenerator{public: ParticleGenerator(Shader shader, GLuint texture, GLuint amount, vec3 gravity); void Update(GLfloat dt, vec3 position, vec3 velocity, GLuint newParticles, vec3 offset = vec3(0.0f, 0.0f, 0.0f));//更新粒子状态 void Draw(mat4 projection, mat4 view, mat4 model);//绘制粒子private: vector<Particle> particles;//粒子数组,保存每个粒子的信息 GLuint amount; Shader shader; GLuint texture; vec3 gravity; GLuint VAO; void init();//将粒子进行初始化 GLuint firstUnusedParticle();//查询死亡的粒子 void respawnParticle(Particle &particle, vec3 position,vec3 velocity, vec3 offset = vec3(0.0f, 0.0f, 0.0f));//将死亡的粒子重新初始化};
定义完后,我们接下来就开始写各个函数:
1、粒子发射器的构造函数
ParticleGenerator::ParticleGenerator(Shader shader, GLuint texture, GLuint amount, vec3 gravity): shader(shader), texture(texture), amount(amount),gravity(gravity){ this->init();}
2、init函数,该函数用于具体设置粒子的形状
GLuint VBO; GLfloat particle_quad[] = { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f };//小立方体的顶点数据 glGenVertexArrays(1, &this->VAO); glGenBuffers(1, &VBO); glBindVertexArray(this->VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(particle_quad), particle_quad, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); glBindVertexArray(0); for (GLuint i = 0; i < this->amount; ++i) { this->particles.push_back(Particle()); }
3、Update函数
void ParticleGenerator::Update(GLfloat dt, vec3 position, vec3 velocity, GLuint newParticles, vec3 offset){ //我当前想要生成newParticles个新粒子,我首先要查询是否有旧粒子死亡,为了防止生成大量数据 for (GLuint i = 0; i < newParticles; ++i) { int unusedParticle = this->firstUnusedParticle();//获取已经死亡的旧粒子的下标 if (unusedParticle != -1) { this->respawnParticle(this->particles[unusedParticle], position, velocity, offset);//重新生成该粒子 } } for (GLuint i = 0; i < this->amount; ++i)//更新每个粒子的状态 { Particle &p = this->particles[i]; p.Life -= dt * 0.05; //减掉寿命 if (p.Life > 0.0f)//没死的话 { p.Velocity = p.Velocity + dt * this->gravity;//更新速度 p.Position += p.Velocity * dt;//更新位置 p.Color.a = p.Life;//更新颜色 } }}
4、Draw函数
void ParticleGenerator::Draw(mat4 projection, mat4 view, mat4 model){ glBlendFunc(GL_SRC_ALPHA, GL_ONE);//开启融混 this->shader.Use(); for (vector<Particle>::iterator it = this->particles.begin(); it != this->particles.end(); it++) { if (it->Life > 0.0f) { glUniform3f(glGetUniformLocation(this->shader.Program, "offset"), it->Position.x, it->Position.y, it->Position.z); //传递坐标更改值,因为我暂时没用Transformfeedback,所以用了累计函数的形式进行更新 glUniform4f(glGetUniformLocation(this->shader.Program, "color"), it->Color.x, it->Color.y, it->Color.z, it->Color.w); //传递颜色更改值 glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "projection"), 1, GL_FALSE, value_ptr(projection)); glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "view"), 1, GL_FALSE, value_ptr(view)); glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "model"), 1, GL_FALSE, value_ptr(model)); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, this->texture); glBindVertexArray(this->VAO); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); } } glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//将融混模式调回默认状态}
5、firstUnusedParticle函数,获取最先死亡的粒子
GLuint ParticleGenerator::firstUnusedParticle(){ //因为粒子随着时间生成,所以我们可以用一个lastUsedParticle记录上一个死亡的粒子的下标,因为下一个死亡的粒子的下标往往在上一个死亡粒子的后面 for (GLuint i = lastUsedParticle; i < this->amount; ++i) { if (this->particles[i].Life <= 0.0f) { lastUsedParticle = i; return i; } } //如果没有找到的话,我们再找前面是否有粒子死亡 for (GLuint i = 0; i < lastUsedParticle; ++i) { if (this->particles[i].Life <= 0.0f) { lastUsedParticle = i; return i; } } lastUsedParticle = 0; return -1;}
6、respawnParticle函数
void ParticleGenerator::respawnParticle(Particle &particle, vec3 position,vec3 velocity, vec3 offset){ GLfloat random1 = ((rand() % 100) - 50) / 10.0f; GLfloat random2 = ((rand() % 100) - 50) / 10.0f; GLfloat rColor = 0.5 + ((rand() % 100) / 100.0f); particle.Position = position;//定义初始位置 particle.Color = vec4(rColor, rColor, rColor, 1.0f);//定义初始颜色 particle.Life = 1.0f;//定义生命值大小 vec3 direction = normalize(vec3(random1, 0.0f, random2)); particle.Velocity = (velocity + direction * 100.0f + offset) * 0.1f;//定义初始速度}
最后我们需要在main函数中调用:
ParticleGenerator *particle = new ParticleGenerator(particleshader, textureofparticle, 10000, vec3(0.0f, -9.8f, 0.0f));particle->Update(deltaTime, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 500.0f, 0.0f), 2, vec3(0.0f));//参数分别为距离绘制上一帧的时间差,发射器初始位置,粒子初始速度,更新粒子的数量,发射器范围大小(类比于枪械的口径)particle->Draw(projection, camera.GetViewMatrix(), model);
0 0
- 没有使用transformfeedback的粒子系统
- 将粒子发射器与Transformfeedback相结合
- [libgdx游戏开发教程]使用Libgdx进行游戏开发(8)-没有美工的程序员,能够依赖的还有粒子系统
- cocos2d-html5 粒子系统的使用
- 简单的粒子系统~~
- 粒子系统的管理
- 粒子系统的学习
- iOS的粒子系统
- 粒子系统的实现
- 我的Cocos2d-x学习笔记(二十一)内置粒子系统、使用粒子特效文件
- Ogre中使用粒子系统
- 使用OpenGL实现粒子系统: 漂亮的喷雾
- Android开发_libgdx粒子系统的使用(七)
- libgdx游戏引擎教程(三)libgdx粒子系统的使用
- libgdx游戏引擎——libgdx粒子系统的使用
- 粒子编辑器的使用
- 粒子系统的简单实现
- 一个简单的粒子系统
- 最大子序列和
- Linux学习日记(2)
- 线性结构_链表
- POJ2407 Relatives 【欧拉函数模板】
- 计算机网络原理之物理层(一)
- 没有使用transformfeedback的粒子系统
- 机房收费系统——【三】软件需求说明书
- Matlab用三种格式来表示日期与时间
- hiho1482出勤记录II
- Java 8并发工具包漫游指南
- 猜算式
- [nODE之三]http模块练习1
- Android自定义View 一<最简单的自定义View>
- 一般开启Tomcat找不到类, java.lang.ClassNotFoundException: