When the particles position is computed, the position of the emitter in both current and previous frames is now taken into account. There is no more visual artifact when the particles velocity and emitter velocity are not aligned (for example with nitro particles when a kart is skidding)

This commit is contained in:
Elderme 2015-08-13 14:50:33 +02:00
parent 43d5dbeb3e
commit 01c8b25cb6
3 changed files with 58 additions and 33 deletions

View File

@ -1,4 +1,5 @@
uniform int dt;
uniform mat4 previous_frame_sourcematrix;
uniform mat4 sourcematrix;
uniform int level;
uniform float size_increase_factor;
@ -32,31 +33,44 @@ out float new_size;
void main(void)
{
float updated_lifetime = lifetime + (float(dt)/lifetime_initial);
if (updated_lifetime > 1.)
{
if (gl_VertexID < level)
float updated_lifetime = lifetime + (float(dt)/lifetime_initial);
if (updated_lifetime > 1.)
{
float dt_from_last_frame = fract(updated_lifetime) * lifetime_initial;
vec4 updated_initialposition = sourcematrix * vec4(particle_position_initial, 1.0);
vec4 updated_initial_velocity = sourcematrix * vec4(particle_position_initial + particle_velocity_initial, 1.0) - updated_initialposition;
new_particle_position = updated_initialposition.xyz + updated_initial_velocity.xyz * float(dt_from_last_frame);
new_particle_velocity = updated_initial_velocity.xyz;
new_lifetime = fract(updated_lifetime);
new_size = mix(size_initial, size_initial * size_increase_factor, fract(updated_lifetime));
if (gl_VertexID < level)
{
float dt_from_last_frame = fract(updated_lifetime) * lifetime_initial;
float coeff = 1. - dt_from_last_frame / dt;
vec4 previous_frame_position = previous_frame_sourcematrix * vec4(particle_position_initial, 1.0);
vec4 current_frame_position = sourcematrix * vec4(particle_position_initial, 1.0);
vec4 updated_initialposition = mix(previous_frame_position,
current_frame_position,
coeff);
vec4 updated_initial_velocity = mix(previous_frame_sourcematrix * vec4(particle_velocity_initial, 0.0),
sourcematrix * vec4(particle_velocity_initial, 0.0),
coeff) ; //TODO: add emitter speed
//+ (current_frame_position - previous_frame_position) / dt;
new_particle_position = updated_initialposition.xyz + dt_from_last_frame * updated_initial_velocity.xyz;
new_particle_velocity = updated_initial_velocity.xyz;
new_lifetime = fract(updated_lifetime);
new_size = mix(size_initial, size_initial * size_increase_factor, fract(updated_lifetime));
}
else
{
new_lifetime = fract(updated_lifetime);
new_size = 0;
}
}
else
{
new_lifetime = fract(updated_lifetime);
new_size = 0;
new_particle_position = particle_position + particle_velocity.xyz * float(dt);
new_particle_velocity = particle_velocity;
new_lifetime = updated_lifetime;
new_size = (size == 0) ? 0. : mix(size_initial, size_initial * size_increase_factor, updated_lifetime);
}
}
else
{
new_particle_position = particle_position + particle_velocity.xyz * float(dt);
new_particle_velocity = particle_velocity;
new_lifetime = updated_lifetime;
new_size = (size == 0) ? 0. : mix(size_initial, size_initial * size_increase_factor, updated_lifetime);
}
gl_Position = vec4(0.);
gl_Position = vec4(0.);
}

View File

@ -37,7 +37,7 @@
/** Transform feedback shader that simulates the particles on GPU.
*/
class PointEmitterShader : public Shader
< PointEmitterShader, core::matrix4, int, int, float >
< PointEmitterShader, core::matrix4, core::matrix4, int, int, float >
{
public:
PointEmitterShader()
@ -45,7 +45,8 @@ public:
const char *varyings[] = { "new_particle_position", "new_lifetime",
"new_particle_velocity", "new_size" };
loadTFBProgram("pointemitter.vert", varyings, 4);
assignUniforms("sourcematrix", "dt", "level", "size_increase_factor");
assignUniforms("previous_frame_sourcematrix", "sourcematrix",
"dt", "level", "size_increase_factor");
} // PointEmitterShader
}; // PointEmitterShader
@ -262,7 +263,7 @@ void ParticleSystemProxy::generateParticlesFromPointEmitter(scene::IParticlePoin
ParticleParams[i].PositionZ = 0;
// Initial lifetime is >1
InitialValues[i].Lifetime = 2.;
memcpy(&(InitialValues[i].PositionX), &(ParticleParams[i].PositionX), 3 * sizeof(float));
generateLifetimeSizeDirection(emitter, ParticleParams[i].Lifetime, ParticleParams[i].Size,
@ -466,11 +467,11 @@ void ParticleSystemProxy::CommonSimulationVAO(GLuint position_vbo, GLuint initia
}
void ParticleSystemProxy::simulate()
{
{
int timediff = int(GUIEngine::getLatestDt() * 1000.f);
int active_count = getEmitter()->getMaxLifeTime() * getEmitter()->getMaxParticlesPerSecond() / 1000;
core::matrix4 matrix = getAbsoluteTransformation();
glEnable(GL_RASTERIZER_DISCARD);
if (has_height_map)
{
@ -482,9 +483,10 @@ void ParticleSystemProxy::simulate()
else
{
PointEmitterShader::getInstance()->use();
PointEmitterShader::getInstance()->setUniforms(matrix, timediff, active_count, size_increase_factor);
PointEmitterShader::getInstance()->setUniforms(m_previous_frame_matrix, matrix, timediff, active_count, size_increase_factor);
}
m_previous_frame_matrix = matrix;
glBindVertexArray(current_simulation_vao);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfb_buffers[1]);
@ -617,8 +619,14 @@ void ParticleSystemProxy::render() {
return;
}
if (m_first_execution)
{
generateVAOs();
m_first_execution = false;
simulate();
draw();
m_previous_frame_matrix = getAbsoluteTransformation();
m_first_execution = false;
}
else
{
simulate();
draw();
}
}

View File

@ -42,7 +42,10 @@ protected:
bool m_randomize_initial_y;
GLuint texture;
/** Previous frame particles emitter source matrix */
core::matrix4 m_previous_frame_matrix;
/** Current count of particles. */
unsigned m_count;
/** Previous count - for error handling only. */