Fix T48991: some particles emitted at a distance from object.
authorAlexander Gavrilov <angavrilov@gmail.com>
Mon, 1 Aug 2016 18:45:42 +0000 (21:45 +0300)
committerAlexander Gavrilov <angavrilov@gmail.com>
Mon, 1 Aug 2016 19:14:56 +0000 (22:14 +0300)
The cause seems to be that despite dt_frac being computed as
1/(subframes+1) with integer subframes value, it doesn't always
add up to exactly 1.0 due to precision limitations. If the sum
is similar to 1.00000???, the last subframe is skipped, and all
particles that were supposed to be emitted in that interval are
emitted next frame, with the code working incorrectly due to
skewed time range.

To fix, separate the code from the dynamic timestep feature that
adjusts the last subframe length into a separate function, and
use it even when dynamic timestep is disabled.

source/blender/blenkernel/intern/particle_system.c

index e7561ee699e0e06307b64456b1619ad24d548d83..8e3e2f5d6d08fb1c8b99662d4d26acb8716303a0 100644 (file)
@@ -3311,7 +3311,7 @@ static float get_base_time_step(ParticleSettings *part)
        return 1.0f / (float) (part->subframes + 1);
 }
 /* Update time step size to suit current conditions. */
-static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim, float t_frac)
+static void update_timestep(ParticleSystem *psys, ParticleSimulationData *sim)
 {
        float dt_target;
        if (sim->courant_num == 0.0f)
@@ -3331,7 +3331,10 @@ static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim,
                psys->dt_frac = interpf(dt_target, psys->dt_frac, TIMESTEP_EXPANSION_FACTOR);
        else
                psys->dt_frac = dt_target;
+}
 
+static float sync_timestep(ParticleSystem *psys, float t_frac)
+{
        /* Sync with frame end if it's close. */
        if (t_frac == 1.0f)
                return psys->dt_frac;
@@ -3991,7 +3994,9 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
                                printf("%f,%f,%f,%f\n", cfra+dframe+t_frac - 1.f, t_frac, dt_frac, sim->courant_num);
 #endif
                                if (part->time_flag & PART_TIME_AUTOSF)
-                                       dt_frac = update_timestep(psys, sim, t_frac);
+                                       update_timestep(psys, sim);
+                               /* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */
+                               dt_frac = sync_timestep(psys, t_frac);
                        }
                }
        }