Fix for [#19955] 2.5 Particles are calculated wrong when object has any transform animation

* The exact location of particle birth wasn't cached if cache step was greater than 1, so the interpolation from an unborn particle to a living one wasn't accurate at all.
* Although not ideal, the current solution is to copy the birth location to the previous cached frame so it's always exact. This should work properly for memory & disk cache.
* This fix shouldn't cause any problems, but exhaustive tests of caching are difficult so be sure to let me know if there's strange behavior.
This commit is contained in:
2010-02-25 00:03:16 +00:00
parent 47d79b04d1
commit d1f19d7e84
2 changed files with 79 additions and 14 deletions

View File

@@ -55,6 +55,7 @@
/* File open options, for BKE_ptcache_file_open */
#define PTCACHE_FILE_READ 0
#define PTCACHE_FILE_WRITE 1
#define PTCACHE_FILE_UPDATE 2
/* PTCacheID types */
#define PTCACHE_TYPE_SOFTBODY 0

View File

@@ -203,9 +203,9 @@ static int ptcache_write_particle(int index, void *psys_v, void **data)
ParticleData *pa = psys->particles + index;
BoidParticle *boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
float times[3] = {pa->time, pa->dietime, pa->lifetime};
int step = psys->pointcache->step;
if(data[BPHYS_DATA_INDEX]) {
int step = psys->pointcache->step;
/* No need to store unborn or died particles */
if(pa->time - step > pa->state.time || pa->dietime + step < pa->state.time)
return 0;
@@ -222,7 +222,8 @@ static int ptcache_write_particle(int index, void *psys_v, void **data)
if(boid)
PTCACHE_DATA_FROM(data, BPHYS_DATA_BOIDS, &boid->data);
return 1;
/* return flag 1+1=2 for newly born particles to copy exact birth location to previously cached frame */
return 1 + (pa->state.time >= pa->time && pa->prev_state.time <= pa->time);
}
void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time)
{
@@ -249,6 +250,10 @@ static void ptcache_read_particle(int index, void *psys_v, void **data, float fr
BKE_ptcache_make_particle_key(&pa->state, 0, data, cfra);
/* set frames cached before birth to birth time */
if(cfra < pa->time)
pa->state.time = pa->time;
if(data[BPHYS_DATA_SIZE])
PTCACHE_DATA_TO(data, BPHYS_DATA_SIZE, 0, &pa->size);
@@ -1148,6 +1153,9 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
} else if (mode==PTCACHE_FILE_WRITE) {
BLI_make_existing_file(filename); /* will create the dir if needs be, same as //textures is created */
fp = fopen(filename, "wb");
} else if (mode==PTCACHE_FILE_UPDATE) {
BLI_make_existing_file(filename);
fp = fopen(filename, "rb+");
}
if (!fp)
@@ -1253,6 +1261,18 @@ static void ptcache_file_init_pointers(PTCacheFile *pf)
pf->cur[BPHYS_DATA_BOIDS] = data_types & (1<<BPHYS_DATA_BOIDS) ? &pf->data.boids : NULL;
}
static void ptcache_file_seek_pointers(int index, PTCacheFile *pf)
{
int i, size=0;
int data_types = pf->data_types;
for(i=0; i<BPHYS_TOT_DATA; i++)
size += pf->data_types & (1<<i) ? ptcache_data_size[i] : 0;
ptcache_file_init_pointers(pf);
/* size of default header + data up to index */
fseek(pf->fp, 8 + 3*sizeof(int) + index * size, SEEK_SET);
}
void BKE_ptcache_mem_init_pointers(PTCacheMem *pm)
{
int data_types = pm->data_types;
@@ -1271,6 +1291,14 @@ void BKE_ptcache_mem_incr_pointers(PTCacheMem *pm)
pm->cur[i] = (char*)pm->cur[i] + ptcache_data_size[i];
}
}
void BKE_ptcache_mem_seek_pointers(int index, PTCacheMem *pm)
{
int data_types = pm->data_types;
int i;
for(i=0; i<BPHYS_TOT_DATA; i++)
pm->cur[i] = data_types & (1<<i) ? (char*)pm->data[i] + index * ptcache_data_size[i] : NULL;
}
static void ptcache_alloc_data(PTCacheMem *pm)
{
int data_types = pm->data_types;
@@ -1453,7 +1481,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec)
else if(pid->read_header(pf2)) {
ptcache_file_init_pointers(pf2);
totpoint2 = pf2->totpoint;
index2 = pf->data_types & BPHYS_DATA_INDEX ? &pf2->data.index : &i;
index2 = pf2->data_types & BPHYS_DATA_INDEX ? &pf2->data.index : &i;
}
}
else {
@@ -1615,7 +1643,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec)
int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
{
PointCache *cache = pid->cache;
PTCacheFile *pf= NULL;
PTCacheFile *pf= NULL, *pf2= NULL;
int i;
int totpoint = pid->totpoint(pid->calldata);
int add = 0, overwrite = 0;
@@ -1625,7 +1653,7 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
return 0;
if(cache->flag & PTCACHE_DISK_CACHE) {
int efra = cache->endframe;
int ofra, efra = cache->endframe;
if(cfra==0)
add = 1;
@@ -1636,7 +1664,6 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
add = 1;
}
else {
int ofra;
/* find last cached frame */
while(efra > cache->startframe && !BKE_ptcache_id_exist(pid, efra))
efra--;
@@ -1679,11 +1706,36 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
}
else
for(i=0; i<totpoint; i++) {
if(pid->write_elem && pid->write_elem(i, pid->calldata, pf->cur))
if(!ptcache_file_write_data(pf)) {
ptcache_file_close(pf);
return 0;
if(pid->write_elem) {
int write = pid->write_elem(i, pid->calldata, pf->cur);
if(write) {
if(!ptcache_file_write_data(pf)) {
ptcache_file_close(pf);
if(pf2) ptcache_file_close(pf2);
return 0;
}
/* newly born particles have to be copied to previous cached frame */
else if(overwrite && write == 2) {
if(!pf2) {
pf2 = ptcache_file_open(pid, PTCACHE_FILE_UPDATE, ofra);
if(!pf2) {
ptcache_file_close(pf);
return 0;
}
pf2->type = pid->type;
pf2->totpoint = totpoint;
pf2->data_types = pid->data_types;
}
ptcache_file_seek_pointers(i, pf2);
pid->write_elem(i, pid->calldata, pf2->cur);
if(!ptcache_file_write_data(pf2)) {
ptcache_file_close(pf);
ptcache_file_close(pf2);
return 0;
}
}
}
}
}
}
}
@@ -1728,8 +1780,19 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
BKE_ptcache_mem_init_pointers(pm);
for(i=0; i<totpoint; i++) {
if(pid->write_elem && pid->write_elem(i, pid->calldata, pm->cur))
BKE_ptcache_mem_incr_pointers(pm);
if(pid->write_elem) {
int write = pid->write_elem(i, pid->calldata, pm->cur);
if(write) {
BKE_ptcache_mem_incr_pointers(pm);
/* newly born particles have to be copied to previous cached frame */
if(overwrite && write == 2) {
pm2 = cache->mem_cache.last;
BKE_ptcache_mem_seek_pointers(i, pm2);
pid->write_elem(i, pid->calldata, pm2->cur);
}
}
}
}
//ptcache_make_index_array(pm, pid->totpoint(pid->calldata));
@@ -1748,8 +1811,9 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
cache->flag |= PTCACHE_FRAMES_SKIPPED;
}
if(pf)
ptcache_file_close(pf);
if(pf) ptcache_file_close(pf);
if(pf2) ptcache_file_close(pf2);
BKE_ptcache_update_info(pid);