粒子系统—雪景模拟

1. 粒子系统

粒子系统是用来模拟微小粒子的物理学模型,一般用于火焰、爆炸等由微小粒子组成的物理现象的模拟。一般而言,粒子系统由大量具有颜色、位置、速度等特征的粒子组成。通常用于游戏中的特效或者雨雪、火焰等模拟。

2.粒子的属性:

  • 位置
  • 速度
  • 颜色
  • 声明周期
  • 重力

一般而言粒子具有以上的属性,但是可以根据具体的情况来增加或者减少一些属性,还可以给粒子加上其他物理特性,如可以让落在地面的粒子反弹等。

3.下雪效果的粒子系统

这里给出一个opengl实现的模拟下雪效果的粒子系统,具体代码如下:

// particles.h
#ifndef OPENGLUS_EXAMPLES_PARTICLES_H
#define OPENGLUS_EXAMPLES_PARTICLES_H
#include <vector>
#include <random>

#include "instance.h"
#include "program.h"

#include "glm/glm.hpp"

namespace openglus {

struct Particle {
public:
  Particle( )
    : offset(area_randomer(e), 200.0f, area_randomer(e)),
    speed(0.0f, speed_randomer(e), 0.0f), size(size_randomer(e))
  { }

public:
  static std::default_random_engine e;
  static std::uniform_real_distribution<double> speed_randomer;
  static std::uniform_int_distribution<unsigned> size_randomer;
  static std::uniform_real_distribution<double> area_randomer;

public:
  glm::vec3 offset, speed;
  GLfloat size;
};


class ParticleSystem {
public:
  ParticleSystem(GLuint max_particles);
  void Update(GLfloat time_passed, const glm::vec3& camera_pos);
  void Draw(Program& program);

private:
  void Init( );
  void BufferData();

private:
  GLuint nums_;
  std::vector<Particle> particles_;
  Instance<GLfloat> snow_instance_;
  std::vector<glm::vec3> offset_;
  std::vector<GLfloat> size_;
};

} // namespace openglus

#endif // OPENGLUS_EXAMPLES_PARTICLES_H

在该粒子系统中,雪粒子只有位置、大小与速度不同,其他属性都被忽略,对于雪粒子,在opengl中使用GL_POINTS模式绘制,并且给粒子贴上雪的纹理,采用instance形式绘制,会提高效率。
// particles.cc
#include "particles.h"

#include <algorithm>
#include <random>
#include <cstddef>

#include "gl/glew.h"

namespace openglus {

std::default_random_engine Particle::e;
std::uniform_real_distribution<double> Particle::speed_randomer(2.0, 5.0);
std::uniform_int_distribution<unsigned> Particle::size_randomer(3, 10);
std::uniform_real_distribution<double> Particle::area_randomer(-100, 100);

ParticleSystem::ParticleSystem(GLuint max_particles)
  : nums_(max_particles), particles_(max_particles), snow_instance_({0.0f, 0.0f, 0.0f})
{
  Init( );
}


void ParticleSystem::Init( )
{
  snow_instance_.SetBaseMeshAttribute(0, 3, GL_FLOAT, 3 * sizeof(GLfloat));
  snow_instance_.AddInstanceAttribute(nums_ * 3 * sizeof(GLfloat), 1, 3, GL_FLOAT, 3 * sizeof(GLfloat));
  snow_instance_.AddInstanceAttribute(nums_ * sizeof(GLfloat), 2, 1, GL_FLOAT, sizeof(GLfloat));
}


void ParticleSystem::Update(GLfloat time_passed, const glm::vec3& camera_pos)
{
  std::vector<glm::vec3> offset;
  std::vector<GLfloat> size;
  
  for (int i = 0; i < nums_; ++i) {
    Particle& p = particles_[i];
    if (p.offset.y > 0.0f) {
      p.offset -= p.speed * time_passed * 5.0f;
      offset.push_back(glm::vec3(p.offset));
      size.push_back(p.size);
    } else {
      p = Particle( );
    }
  }
  std::swap(offset_, offset);
  std::swap(size_, size);
  BufferData();
}


void ParticleSystem::BufferData()
{
  snow_instance_.BufferStreamData(1, offset_.size( ) * 3 * sizeof(GLfloat), offset_.data( ));
  snow_instance_.BufferStreamData(2, size_.size( ) * sizeof(GLfloat), size_.data( ));
}

void ParticleSystem::Draw(Program& program)
{
  snow_instance_.DrawArray(program, 1, offset_.size( ), GL_POINTS);
}

} // namespace openglus

绘制效果:

posted @ 2016-05-29 14:35  Leptus  阅读(3489)  评论(0编辑  收藏  举报