Implement color variation in particle system

This commit is contained in:
Marianne Gagnon 2014-03-15 13:35:51 -04:00
parent de820054b6
commit 0425cf2ef4
8 changed files with 140 additions and 29 deletions

View File

@ -5,6 +5,7 @@ uniform vec2 screen;
in float lf;
in vec2 tc;
in vec3 pc;
out vec4 color;
@ -18,6 +19,6 @@ void main(void)
vec4 EnvPos = invproj * (2. * vec4(xy, EnvZ, 1.0) - 1.);
EnvPos /= EnvPos.w;
float alpha = clamp((EnvPos.z - FragmentPos.z) * 0.3, 0., 1.);
color = texture(tex, tc);
color = texture(tex, tc) * vec4(pc, 1.0);
color.a *= alpha * smoothstep(1., 0.8, lf);
}

View File

@ -1,5 +1,7 @@
uniform mat4 ProjectionMatrix;
uniform mat4 ViewMatrix;
uniform vec3 color_from;
uniform vec3 color_to;
in vec2 quadcorner;
in vec2 texcoord;
@ -9,11 +11,13 @@ in float size;
out float lf;
out vec2 tc;
out vec3 pc;
void main(void)
{
tc = texcoord;
lf = lifetime;
pc = color_from + (color_to - color_from) * lifetime;
vec3 newposition = position;
vec4 viewpos = ViewMatrix * vec4(newposition, 1.0);

View File

@ -197,8 +197,8 @@ void initGL()
}
// Mostly from shader tutorial
static
GLuint LoadShader(const char * file, unsigned type) {
static GLuint LoadShader(const char * file, unsigned type)
{
GLuint Id = glCreateShader(type);
std::string Code = "#version 330\n";
std::ifstream Stream(file, std::ios::in);
@ -218,7 +218,8 @@ GLuint LoadShader(const char * file, unsigned type) {
glCompileShader(Id);
glGetShaderiv(Id, GL_COMPILE_STATUS, &Result);
if (Result == GL_FALSE) {
if (Result == GL_FALSE)
{
glGetShaderiv(Id, GL_INFO_LOG_LENGTH, &InfoLogLength);
char *ErrorMessage = new char[InfoLogLength];
glGetShaderInfoLog(Id, InfoLogLength, NULL, ErrorMessage);
@ -229,7 +230,8 @@ GLuint LoadShader(const char * file, unsigned type) {
return Id;
}
GLuint LoadProgram(const char * vertex_file_path, const char * fragment_file_path) {
GLuint LoadProgram(const char * vertex_file_path, const char * fragment_file_path)
{
GLuint VertexShaderID = LoadShader(vertex_file_path, GL_VERTEX_SHADER);
GLuint FragmentShaderID = LoadShader(fragment_file_path, GL_FRAGMENT_SHADER);
@ -255,7 +257,8 @@ GLuint LoadProgram(const char * vertex_file_path, const char * fragment_file_pat
return ProgramID;
}
GLuint LoadProgram(const char * vertex_file_path, const char * geometry_file_path, const char * fragment_file_path) {
GLuint LoadProgram(const char * vertex_file_path, const char * geometry_file_path, const char * fragment_file_path)
{
GLuint VertexShaderID = LoadShader(vertex_file_path, GL_VERTEX_SHADER);
GLuint FragmentShaderID = LoadShader(fragment_file_path, GL_FRAGMENT_SHADER);
GLuint GeometryShaderID = LoadShader(geometry_file_path, GL_GEOMETRY_SHADER);
@ -284,7 +287,8 @@ GLuint LoadProgram(const char * vertex_file_path, const char * geometry_file_pat
return ProgramID;
}
GLuint LoadTFBProgram(const char * vertex_file_path, const char **varyings, unsigned varyingscount) {
GLuint LoadTFBProgram(const char * vertex_file_path, const char **varyings, unsigned varyingscount)
{
GLuint Shader = LoadShader(vertex_file_path, GL_VERTEX_SHADER);
GLuint Program = glCreateProgram();
glAttachShader(Program, Shader);
@ -294,7 +298,8 @@ GLuint LoadTFBProgram(const char * vertex_file_path, const char **varyings, unsi
GLint Result = GL_FALSE;
int InfoLogLength;
glGetProgramiv(Program, GL_LINK_STATUS, &Result);
if (Result == GL_FALSE) {
if (Result == GL_FALSE)
{
glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &InfoLogLength);
char *ErrorMessage = new char[InfoLogLength];
glGetProgramInfoLog(Program, InfoLogLength, NULL, ErrorMessage);
@ -305,11 +310,13 @@ GLuint LoadTFBProgram(const char * vertex_file_path, const char **varyings, unsi
return Program;
}
GLuint getTextureGLuint(irr::video::ITexture *tex) {
GLuint getTextureGLuint(irr::video::ITexture *tex)
{
return static_cast<irr::video::COpenGLTexture*>(tex)->getOpenGLTextureName();
}
GLuint getDepthTexture(irr::video::ITexture *tex) {
GLuint getDepthTexture(irr::video::ITexture *tex)
{
assert(tex->isRenderTarget());
return static_cast<irr::video::COpenGLFBOTexture*>(tex)->DepthBufferTexture;
}

View File

@ -39,6 +39,10 @@ ParticleSystemProxy::ParticleSystemProxy(bool createDefaultEmitter,
glGenVertexArrays(1, &non_current_rendering_vao);
size_increase_factor = 0.;
m_color_from[0] = m_color_from[1] = m_color_from[2] = 1.0;
m_color_to[0] = m_color_to[1] = m_color_to[2] = 1.0;
// We set these later but avoid coverity report them
heighmapbuffer = 0;
heightmaptexture = 0;
@ -82,11 +86,8 @@ ParticleSystemProxy::~ParticleSystemProxy()
}
void ParticleSystemProxy::setAlphaAdditive(bool val) { m_alpha_additive = val; }
void ParticleSystemProxy::setIncreaseFactor(float val) { size_increase_factor = val; }
void ParticleSystemProxy::setFlip() {
void ParticleSystemProxy::setFlip()
{
flip = true;
float *quaternions = new float[4 * count];
for (unsigned i = 0; i < count; i++)
@ -114,7 +115,8 @@ void ParticleSystemProxy::setFlip() {
}
void ParticleSystemProxy::setHeightmap(const std::vector<std::vector<float> > &hm,
float f1, float f2, float f3, float f4) {
float f1, float f2, float f3, float f4)
{
track_x = f1, track_z = f2, track_x_len = f3, track_z_len = f4;
unsigned width = hm.size();
@ -189,7 +191,8 @@ void ParticleSystemProxy::generateParticlesFromPointEmitter(scene::IParticlePoin
{
ParticleData *particles = new ParticleData[count], *initialvalue = new ParticleData[count];
for (unsigned i = 0; i < count; i++) {
for (unsigned i = 0; i < count; i++)
{
particles[i].PositionX = 0;
particles[i].PositionY = 0;
particles[i].PositionZ = 0;
@ -300,6 +303,7 @@ void ParticleSystemProxy::FlipParticleVAOBind(GLuint PositionBuffer, GLuint Quat
glEnableVertexAttribArray(ParticleShader::FlipParticleRender::attrib_rotationvec);
glEnableVertexAttribArray(ParticleShader::FlipParticleRender::attrib_anglespeed);
glBindBuffer(GL_ARRAY_BUFFER, QuaternionBuffer);
glVertexAttribPointer(ParticleShader::FlipParticleRender::attrib_rotationvec, 3, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glVertexAttribPointer(ParticleShader::FlipParticleRender::attrib_anglespeed, 1, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (GLvoid *)(3 * sizeof(float)));
@ -307,6 +311,7 @@ void ParticleSystemProxy::FlipParticleVAOBind(GLuint PositionBuffer, GLuint Quat
glBindBuffer(GL_ARRAY_BUFFER, quad_vertex_buffer);
glVertexAttribPointer(ParticleShader::FlipParticleRender::attrib_quadcorner, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glVertexAttribPointer(ParticleShader::FlipParticleRender::attrib_texcoord, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (GLvoid *)(2 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, PositionBuffer);
glVertexAttribPointer(ParticleShader::FlipParticleRender::attrib_pos, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleData), 0);
glVertexAttribPointer(ParticleShader::FlipParticleRender::attrib_lf, 1, GL_FLOAT, GL_FALSE, sizeof(ParticleData), (GLvoid *)(3 * sizeof(float)));
@ -330,6 +335,7 @@ void ParticleSystemProxy::SimpleParticleVAOBind(GLuint PositionBuffer)
glBindBuffer(GL_ARRAY_BUFFER, quad_vertex_buffer);
glVertexAttribPointer(ParticleShader::SimpleParticleRender::attrib_quadcorner, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glVertexAttribPointer(ParticleShader::SimpleParticleRender::attrib_texcoord, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (GLvoid *)(2 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, PositionBuffer);
glVertexAttribPointer(ParticleShader::SimpleParticleRender::attrib_pos, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleData), 0);
glVertexAttribPointer(ParticleShader::SimpleParticleRender::attrib_lf, 1, GL_FLOAT, GL_FALSE, sizeof(ParticleData), (GLvoid *)(3 * sizeof(float)));
@ -364,19 +370,22 @@ void ParticleSystemProxy::SimpleSimulationBind(GLuint PositionBuffer, GLuint Ini
void ParticleSystemProxy::HeightmapSimulationBind(GLuint PositionBuffer, GLuint InitialValuesBuffer)
{
// Position buffer
glEnableVertexAttribArray(ParticleShader::HeightmapSimulationShader::attrib_position);
glEnableVertexAttribArray(ParticleShader::HeightmapSimulationShader::attrib_lifetime);
glEnableVertexAttribArray(ParticleShader::HeightmapSimulationShader::attrib_velocity);
// glEnableVertexAttribArray(ParticleShader::HeightmapSimulationShader::attrib_size);
glBindBuffer(GL_ARRAY_BUFFER, PositionBuffer);
glVertexAttribPointer(ParticleShader::HeightmapSimulationShader::attrib_position, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleData), (GLvoid*)0);
glVertexAttribPointer(ParticleShader::HeightmapSimulationShader::attrib_lifetime, 1, GL_FLOAT, GL_FALSE, sizeof(ParticleData), (GLvoid*)(3 * sizeof(float)));
glVertexAttribPointer(ParticleShader::HeightmapSimulationShader::attrib_velocity, 4, GL_FLOAT, GL_FALSE, sizeof(ParticleData), (GLvoid*)(4 * sizeof(float)));
//glVertexAttribPointer(ParticleShader::HeightmapSimulationShader::attrib_size, 1, GL_FLOAT, GL_FALSE, sizeof(ParticleData), (GLvoid*)(7 * sizeof(float)));
// Initial values buffer
glEnableVertexAttribArray(ParticleShader::HeightmapSimulationShader::attrib_initial_position);
glEnableVertexAttribArray(ParticleShader::HeightmapSimulationShader::attrib_initial_lifetime);
glEnableVertexAttribArray(ParticleShader::HeightmapSimulationShader::attrib_initial_velocity);
glEnableVertexAttribArray(ParticleShader::HeightmapSimulationShader::attrib_initial_size);
glBindBuffer(GL_ARRAY_BUFFER, InitialValuesBuffer);
glVertexAttribPointer(ParticleShader::HeightmapSimulationShader::attrib_initial_position, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleData), (GLvoid*)0);
glVertexAttribPointer(ParticleShader::HeightmapSimulationShader::attrib_initial_lifetime, 1, GL_FLOAT, GL_FALSE, sizeof(ParticleData), (GLvoid*)(3 * sizeof(float)));
@ -534,7 +543,8 @@ void ParticleSystemProxy::drawNotFlip()
setTexture(0, texture, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR);
setTexture(1, static_cast<video::COpenGLFBOTexture *>(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH))->DepthBufferTexture, GL_NEAREST, GL_NEAREST);
ParticleShader::SimpleParticleRender::setUniforms(irr_driver->getViewMatrix(), irr_driver->getProjMatrix(), irr_driver->getInvProjMatrix(), screen[0], screen[1], 0, 1);
ParticleShader::SimpleParticleRender::setUniforms(irr_driver->getViewMatrix(), irr_driver->getProjMatrix(),
irr_driver->getInvProjMatrix(), screen[0], screen[1], 0, 1, this);
glBindVertexArray(current_rendering_vao);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, count);

View File

@ -19,6 +19,8 @@ protected:
GLuint current_rendering_flip_vao, non_current_rendering_flip_vao;
bool m_alpha_additive, has_height_map, flip;
float size_increase_factor, track_x, track_z, track_x_len, track_z_len;
float m_color_from[3];
float m_color_to[3];
static GLuint quad_vertex_buffer;
@ -55,8 +57,12 @@ public:
virtual void setEmitter(scene::IParticleEmitter* emitter);
virtual void render();
virtual void OnRegisterSceneNode();
void setAlphaAdditive(bool);
void setIncreaseFactor(float);
void setAlphaAdditive(bool val) { m_alpha_additive = val; }
void setIncreaseFactor(float val) { size_increase_factor = val; }
void setColorFrom(float r, float g, float b) { m_color_from[0] = r; m_color_from[1] = g; m_color_from[2] = b; }
void setColorTo(float r, float g, float b) { m_color_to[0] = r; m_color_to[1] = g; m_color_to[2] = b; }
const float* getColorFrom() const { return m_color_from; }
const float* getColorTo() const { return m_color_to; }
void setHeightmap(const std::vector<std::vector<float> >&, float, float, float, float);
void setFlip();
};

View File

@ -248,6 +248,40 @@ protected:
core::vector2df ScaleFactor;
};
// ============================================================================
class ColorAffector : public scene::IParticleAffector
{
protected:
core::vector3df m_color_from;
core::vector3df m_color_to;
public:
ColorAffector(const core::vector3df& colorFrom, const core::vector3df& colorTo) :
m_color_from(colorFrom), m_color_to(colorTo)
{
}
virtual void affect(u32 now, scene::SParticle *particlearray, u32 count)
{
for (u32 i = 0; i<count; i++)
{
const u32 maxdiff = particlearray[i].endTime - particlearray[i].startTime;
const u32 curdiff = now - particlearray[i].startTime;
const f32 timefraction = (f32)curdiff / maxdiff;
core::vector3df curr_color = m_color_from + (m_color_to - m_color_from)* timefraction;
particlearray[i].color = video::SColor(255, (int)curr_color.X, (int)curr_color.Y, (int)curr_color.Z);
}
}
virtual scene::E_PARTICLE_AFFECTOR_TYPE getType() const
{
return scene::EPAT_SCALE;
}
};
// ============================================================================
@ -487,7 +521,7 @@ void ParticleEmitter::setParticleType(const ParticleKind* type)
{
m_emitter = m_node->createPointEmitter(velocity,
type->getMinRate(), type->getMaxRate(),
type->getMinColor(), type->getMaxColor(),
type->getMinColor(), type->getMinColor(),
lifeTimeMin, lifeTimeMax,
m_particle_type->getAngleSpread() /* angle */
);
@ -503,7 +537,7 @@ void ParticleEmitter::setParticleType(const ParticleKind* type)
box_size_x, box_size_y, -0.6f - type->getBoxSizeZ()),
velocity,
type->getMinRate(), type->getMaxRate(),
type->getMinColor(), type->getMaxColor(),
type->getMinColor(), type->getMinColor(),
lifeTimeMin, lifeTimeMax,
m_particle_type->getAngleSpread()
);
@ -536,7 +570,7 @@ void ParticleEmitter::setParticleType(const ParticleKind* type)
m_particle_type->getSphereRadius(),
velocity,
type->getMinRate(), type->getMaxRate(),
type->getMinColor(), type->getMaxColor(),
type->getMinColor(), type->getMinColor(),
lifeTimeMin, lifeTimeMax,
m_particle_type->getAngleSpread()
);
@ -600,6 +634,38 @@ void ParticleEmitter::setParticleType(const ParticleKind* type)
}
}
if (type->getMinColor() != type->getMaxColor())
{
if (m_is_glsl)
{
video::SColor color_from = type->getMinColor();
static_cast<ParticleSystemProxy *>(m_node)->setColorFrom(color_from.getRed() / 255.0f,
color_from.getGreen() / 255.0f,
color_from.getBlue() / 255.0f);
video::SColor color_to = type->getMaxColor();
static_cast<ParticleSystemProxy *>(m_node)->setColorTo(color_to.getRed() / 255.0f,
color_to.getGreen() / 255.0f,
color_to.getBlue() / 255.0f);
}
else
{
video::SColor color_from = type->getMinColor();
core::vector3df color_from_v = core::vector3df(color_from.getRed(),
color_from.getGreen(),
color_from.getBlue());
video::SColor color_to = type->getMaxColor();
core::vector3df color_to_v = core::vector3df(color_to.getRed(),
color_to.getGreen(),
color_to.getBlue());
ColorAffector* affector = new ColorAffector(color_from_v, color_to_v);
m_node->addAffector(affector);
affector->drop();
}
}
const float windspeed = type->getWindSpeed();
if (windspeed > 0.01f)
{

View File

@ -18,6 +18,7 @@
#include "graphics/callbacks.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/gpuparticles.hpp"
#include "graphics/shaders.hpp"
#include "io/file_manager.hpp"
#include "utils/log.hpp"
@ -1293,7 +1294,9 @@ namespace ParticleShader
GLuint SimpleParticleRender::uniform_dtex;
GLuint SimpleParticleRender::uniform_screen;
GLuint SimpleParticleRender::uniform_invproj;
GLuint SimpleParticleRender::uniform_color_from;
GLuint SimpleParticleRender::uniform_color_to;
void SimpleParticleRender::init()
{
Program = LoadProgram(file_manager->getAsset("shaders/particle.vert").c_str(), file_manager->getAsset("shaders/particle.frag").c_str());
@ -1310,9 +1313,15 @@ namespace ParticleShader
uniform_invproj = glGetUniformLocation(Program, "invproj");
uniform_screen = glGetUniformLocation(Program, "screen");
uniform_dtex = glGetUniformLocation(Program, "dtex");
uniform_color_from = glGetUniformLocation(Program, "color_from");
assert(uniform_color_from != -1);
uniform_color_to = glGetUniformLocation(Program, "color_to");
assert(uniform_color_to != -1);
}
void SimpleParticleRender::setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 InvProjMatrix, float width, float height, unsigned TU_tex, unsigned TU_dtex)
void SimpleParticleRender::setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix,
const core::matrix4 InvProjMatrix, float width, float height, unsigned TU_tex, unsigned TU_dtex,
const ParticleSystemProxy* particle_system)
{
glUniformMatrix4fv(uniform_invproj, 1, GL_FALSE, InvProjMatrix.pointer());
glUniform2f(uniform_screen, width, height);
@ -1320,6 +1329,11 @@ namespace ParticleShader
glUniformMatrix4fv(uniform_viewmatrix, 1, GL_FALSE, irr_driver->getViewMatrix().pointer());
glUniform1i(uniform_tex, TU_tex);
glUniform1i(uniform_dtex, TU_dtex);
const float* color_from = particle_system->getColorFrom();
const float* color_to = particle_system->getColorTo();
glUniform3f(uniform_color_from, color_from[0], color_from[1], color_from[2]);
glUniform3f(uniform_color_to, color_to[0], color_to[1], color_to[2]);
}
GLuint FlipParticleRender::Program;

View File

@ -23,6 +23,7 @@
typedef unsigned int GLuint;
using namespace irr;
class ParticleSystemProxy;
class SharedObject
{
@ -361,10 +362,12 @@ class SimpleParticleRender
public:
static GLuint Program;
static GLuint attrib_pos, attrib_lf, attrib_quadcorner, attrib_texcoord, attrib_sz;
static GLuint uniform_matrix, uniform_viewmatrix, uniform_tex, uniform_dtex, uniform_screen, uniform_invproj;
static GLuint uniform_matrix, uniform_viewmatrix, uniform_tex, uniform_dtex, uniform_screen, uniform_invproj, uniform_color_from, uniform_color_to;
static void init();
static void setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 InvProjMatrix, float width, float height, unsigned TU_tex, unsigned TU_normal_and_depth);
static void setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix,
const core::matrix4 InvProjMatrix, float width, float height, unsigned TU_tex,
unsigned TU_normal_and_depth, const ParticleSystemProxy* particle_system);
};
class FlipParticleRender