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.
This commit is contained in:
parent
7dd15b7113
commit
d0bcb6efea
Notes:
blender-bot
2023-02-14 07:36:17 +01:00
Referenced by issue #88449: Blender LTS: Maintenance Task 2.93 Referenced by issue #88449, Blender LTS: Maintenance Task 2.93 Referenced by issue #68290, Baked particles dont render in final frame
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue