粒子系統—雪景模擬


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

繪制效果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM