diff options
author | Campbell Barton <campbell@blender.org> | 2022-04-14 09:58:15 +0300 |
---|---|---|
committer | Philipp Oeser <info@graphics-engineer.com> | 2022-04-19 16:58:43 +0300 |
commit | d0bcb6efead49a269d3b9b6f29ef07f5241fa137 (patch) | |
tree | 3888a05e83add9f14a24ef5600d15e2510c66ed3 | |
parent | 7dd15b7113493f002401ee3447a0b52d09889eaf (diff) |
Fix T68290: Baked particles don't render in final frame
Particles baked into memory would never load the final frame because
of an off-by-one error calculating the particles `dietime`.
This value indicates the frame which the particle ceases to exist but
was being set to the end-frame which caused this bug as the scenes
end-frame is inclusive.
While the last frame was properly written and read from memory,
the `dietime` was set to the last frame causing all the particles to be
considered dead when calculating the cached particle system.
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 25 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 23 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_particle_types.h | 7 |
3 files changed, 37 insertions, 18 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index ae685357151..544c80ebc7b 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -1254,7 +1254,9 @@ typedef struct ParticleInterpolationData { PTCacheEditPoint *epoint; PTCacheEditKey *ekey[2]; - float birthtime, dietime; + float birthtime; + /** Die on this frame, see #ParticleData.dietime for details. */ + float dietime; int bspline; } ParticleInterpolationData; /** @@ -1316,15 +1318,15 @@ static void get_pointcache_keys_for_time(Object *UNUSED(ob), } static int get_pointcache_times_for_particle(PointCache *cache, int index, - float *start, - float *end) + float *r_start, + float *r_dietime) { PTCacheMem *pm; int ret = 0; for (pm = cache->mem_cache.first; pm; pm = pm->next) { if (BKE_ptcache_mem_index_find(pm, index) >= 0) { - *start = pm->frame; + *r_start = pm->frame; ret++; break; } @@ -1332,7 +1334,8 @@ static int get_pointcache_times_for_particle(PointCache *cache, for (pm = cache->mem_cache.last; pm; pm = pm->prev) { if (BKE_ptcache_mem_index_find(pm, index) >= 0) { - *end = pm->frame; + /* Die *after* the last available frame. */ + *r_dietime = pm->frame + 1; ret++; break; } @@ -1348,7 +1351,9 @@ float psys_get_dietime_from_cache(PointCache *cache, int index) for (pm = cache->mem_cache.last; pm; pm = pm->prev) { if (BKE_ptcache_mem_index_find(pm, index) >= 0) { - return (float)pm->frame; + /* Die *after* the last available frame. */ + dietime = pm->frame + 1; + break; } } @@ -1379,14 +1384,14 @@ static void init_particle_interpolation(Object *ob, pind->dietime = (key + pa->totkey - 1)->time; } else if (pind->cache) { - float start = 0.0f, end = 0.0f; + float start = 0.0f, dietime = 0.0f; get_pointcache_keys_for_time(ob, pind->cache, &pind->pm, -1, 0.0f, NULL, NULL); pind->birthtime = pa ? pa->time : pind->cache->startframe; - pind->dietime = pa ? pa->dietime : pind->cache->endframe; + pind->dietime = pa ? pa->dietime : (pind->cache->endframe + 1); - if (get_pointcache_times_for_particle(pind->cache, pa - psys->particles, &start, &end)) { + if (get_pointcache_times_for_particle(pind->cache, pa - psys->particles, &start, &dietime)) { pind->birthtime = MAX2(pind->birthtime, start); - pind->dietime = MIN2(pind->dietime, end); + pind->dietime = MIN2(pind->dietime, dietime + 1); } } else { diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 17434ee8023..98430bc422c 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -300,8 +300,10 @@ static int ptcache_particle_write(int index, void *psys_v, void **data, int cfra } } else { - /* Particles are only stored in their lifetime. */ - if (cfra < pa->time - step || cfra > pa->dietime + step) { + /* Inclusive ranges for particle lifetime (`dietime - 1` for an inclusive end-frame). */ + const int pa_sfra = (int)pa->time - step; + const int pa_efra = ((int)pa->dietime - 1) + step; + if (!(cfra >= pa_sfra && cfra <= pa_efra)) { return 0; } } @@ -414,9 +416,12 @@ static void ptcache_particle_interpolate(int index, pa = psys->particles + index; - /* particle wasn't read from first cache so can't interpolate */ - if ((int)cfra1 < pa->time - psys->pointcache->step || - (int)cfra1 > pa->dietime + psys->pointcache->step) { + /* Inclusive ranges for particle lifetime (`dietime - 1` for an inclusive end-frame). */ + const int pa_sfra = (int)pa->time - psys->pointcache->step; + const int pa_efra = ((int)pa->dietime - 1) + psys->pointcache->step; + + /* Particle wasn't read from first cache so can't interpolate. */ + if (!(cfra1 >= pa_sfra && cfra1 <= pa_efra)) { return; } @@ -497,12 +502,16 @@ static int ptcache_particle_totwrite(void *psys_v, int cfra) if (psys->part->flag & PART_DIED) { /* Also store dead particles when they are displayed. */ for (p = 0; p < psys->totpart; p++, pa++) { - totwrite += (cfra >= pa->time - step); + const int pa_sfra = (int)pa->time - step; + totwrite += (cfra >= pa_sfra); } } else { for (p = 0; p < psys->totpart; p++, pa++) { - totwrite += (cfra >= pa->time - step && cfra <= pa->dietime + step); + /* Inclusive ranges for particle lifetime (`dietime - 1` for an inclusive end-frame). */ + const int pa_sfra = (int)pa->time - step; + const int pa_efra = ((int)pa->dietime - 1) + step; + totwrite += (cfra >= pa_sfra) && (cfra <= pa_efra); } } diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index cc40e26b92b..570a2f7cffd 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -123,7 +123,12 @@ typedef struct ParticleData { /** Die-time is not necessarily time+lifetime as. */ float time, lifetime; - /** Particles can die unnaturally (collision). */ + /** + * Particles can die unnaturally (collision). + * + * \note Particles die on this frame, be sure to add 1 when clamping the lifetime of particles + * to inclusive ranges such as the scenes end frame. See: T68290. + */ float dietime; /** |