[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [27347] trunk/blender/source/blender/ blenkernel: Point cache optimization: only cache particles that are alive.

Janne Karhu jhkarh at gmail.com
Tue Mar 9 04:01:20 CET 2010


Revision: 27347
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=27347
Author:   jhk
Date:     2010-03-09 04:01:18 +0100 (Tue, 09 Mar 2010)

Log Message:
-----------
Point cache optimization: only cache particles that are alive.

This reduces point cache sizes dramatically especially if particle
life time is small compared to total simulation length. For example
with the settings: particle amount = 10000, start = 1, end = 200,
life = 10, cache step = 1, the unoptimized blend file size (compressed)
was a little over 22 Mb and with this optimization the file is a little
under 2 Mb (again compressed). In addition to saving memory/disk space
this also probably speeds up reading from cache, since there's less
data to read.

As an additional fix the memory cache size (displayed in cache panel)
is now calculated correctly.

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/BKE_pointcache.h
    trunk/blender/source/blender/blenkernel/intern/particle.c
    trunk/blender/source/blender/blenkernel/intern/pointcache.c

Modified: trunk/blender/source/blender/blenkernel/BKE_pointcache.h
===================================================================
--- trunk/blender/source/blender/blenkernel/BKE_pointcache.h	2010-03-09 02:29:59 UTC (rev 27346)
+++ trunk/blender/source/blender/blenkernel/BKE_pointcache.h	2010-03-09 03:01:18 UTC (rev 27347)
@@ -118,7 +118,7 @@
 	unsigned int data_types, info_types;
 
 	/* copies point data to cache data */
-	int (*write_elem)(int index, void *calldata, void **data);
+	int (*write_elem)(int index, void *calldata, void **data, int cfra);
 	/* copies point data to cache data */
 	int (*write_stream)(PTCacheFile *pf, void *calldata);
 	/* copies cache cata to point data */
@@ -128,10 +128,10 @@
 	/* interpolated between previously read point data and cache data */
 	void (*interpolate_elem)(int index, void *calldata, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data);
 
-	/* total number of simulated points */
-	int (*totpoint)(void *calldata);
-	/* number of points written for current cache frame (currently not used) */
-	int (*totwrite)(void *calldata);
+	/* total number of simulated points (the cfra parameter is just for using same function pointer with totwrite) */
+	int (*totpoint)(void *calldata, int cfra);
+	/* number of points written for current cache frame */
+	int (*totwrite)(void *calldata, int cfra);
 
 	int (*write_header)(PTCacheFile *pf);
 	int (*read_header)(PTCacheFile *pf);

Modified: trunk/blender/source/blender/blenkernel/intern/particle.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/particle.c	2010-03-09 02:29:59 UTC (rev 27346)
+++ trunk/blender/source/blender/blenkernel/intern/particle.c	2010-03-09 03:01:18 UTC (rev 27347)
@@ -1067,12 +1067,12 @@
 			while(pm && pm->next && (float)pm->frame < t)
 				pm = pm->next;
 
-			BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] : index, pm->data, (float)pm->frame);
-			BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] : index, pm->prev->data, (float)pm->prev->frame);
+			BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] - 1 : index, pm->data, (float)pm->frame);
+			BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] - 1 : index, pm->prev->data, (float)pm->prev->frame);
 		}
 		else if(cache->mem_cache.first) {
 			PTCacheMem *pm2 = cache->mem_cache.first;
-			BKE_ptcache_make_particle_key(key2, pm2->index_array ? pm2->index_array[index] : index, pm2->data, (float)pm2->frame);
+			BKE_ptcache_make_particle_key(key2, pm2->index_array ? pm2->index_array[index] - 1 : index, pm2->data, (float)pm2->frame);
 			copy_particle_key(key1, key2, 1);
 		}
 	}

Modified: trunk/blender/source/blender/blenkernel/intern/pointcache.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/pointcache.c	2010-03-09 02:29:59 UTC (rev 27346)
+++ trunk/blender/source/blender/blenkernel/intern/pointcache.c	2010-03-09 03:01:18 UTC (rev 27347)
@@ -135,7 +135,7 @@
 	return 1;
 }
 /* Softbody functions */
-static int ptcache_write_softbody(int index, void *soft_v, void **data)
+static int ptcache_write_softbody(int index, void *soft_v, void **data, int cfra)
 {
 	SoftBody *soft= soft_v;
 	BodyPoint *bp = soft->bpoint + index;
@@ -191,13 +191,13 @@
 	VECCOPY(bp->pos, keys->co);
 	VECCOPY(bp->vec, keys->vel);
 }
-static int ptcache_totpoint_softbody(void *soft_v)
+static int ptcache_totpoint_softbody(void *soft_v, int cfra)
 {
 	SoftBody *soft= soft_v;
 	return soft->totpoint;
 }
 /* Particle functions */
-static int ptcache_write_particle(int index, void *psys_v, void **data)
+static int ptcache_write_particle(int index, void *psys_v, void **data, int cfra)
 {
 	ParticleSystem *psys= psys_v;
 	ParticleData *pa = psys->particles + index;
@@ -205,11 +205,9 @@
 	float times[3] = {pa->time, pa->dietime, pa->lifetime};
 	int step = psys->pointcache->step;
 
-	if(data[BPHYS_DATA_INDEX]) {
-		/* No need to store unborn or died particles */
-		if(pa->time - step > pa->state.time || pa->dietime + step < pa->state.time)
-			return 0;
-	}
+	/* No need to store unborn or died particles outside cache step bounds */
+	if(data[BPHYS_DATA_INDEX] && (cfra < pa->time - step || cfra > pa->dietime + step))
+		return 0;
 	
 	PTCACHE_DATA_FROM(data, BPHYS_DATA_INDEX, &index);
 	PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, pa->state.co);
@@ -236,9 +234,15 @@
 static void ptcache_read_particle(int index, void *psys_v, void **data, float frs_sec, float cfra, float *old_data)
 {
 	ParticleSystem *psys= psys_v;
-	ParticleData *pa = psys->particles + index;
-	BoidParticle *boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
+	ParticleData *pa;
+	BoidParticle *boid;
 
+	if(index >= psys->totpart)
+		return;
+
+	pa = psys->particles + index;
+	boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
+
 	if(cfra > pa->state.time)
 		memcpy(&pa->prev_state, &pa->state, sizeof(ParticleKey));
 
@@ -288,10 +292,19 @@
 static void ptcache_interpolate_particle(int index, void *psys_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data)
 {
 	ParticleSystem *psys= psys_v;
-	ParticleData *pa = psys->particles + index;
+	ParticleData *pa;
 	ParticleKey keys[4];
 	float dfra;
 
+	if(index >= psys->totpart)
+		return;
+
+	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)
+		return;
+
 	cfra = MIN2(cfra, pa->dietime);
 	cfra1 = MIN2(cfra1, pa->dietime);
 	cfra2 = MIN2(cfra2, pa->dietime);
@@ -338,27 +351,21 @@
 	pa->state.time = cfra;
 }
 
-static int ptcache_totpoint_particle(void *psys_v)
+static int ptcache_totpoint_particle(void *psys_v, int cfra)
 {
 	ParticleSystem *psys = psys_v;
 	return psys->totpart;
 }
-static int ptcache_totwrite_particle(void *psys_v)
+static int ptcache_totwrite_particle(void *psys_v, int cfra)
 {
 	ParticleSystem *psys = psys_v;
+	ParticleData *pa= psys->particles;
+	int p, step = psys->pointcache->step;
 	int totwrite = 0;
 
-	/* TODO for later */
-	//if((psys->part->flag & (PART_UNBORN|PART_DIED))==0) {
-	//	ParticleData *pa= psys->particles;
-	//	int p, step = psys->pointcache->step;
+	for(p=0; p<psys->totpart; p++,pa++)
+		totwrite += (cfra >= pa->time - step && cfra <= pa->dietime + step);
 
-	//	for(p=0; p<psys->totpart; p++,pa++)
-	//		totwrite += (pa->time - step > pa->state.time || pa->dietime + step > pa->state.time);
-	//}
-	//else
-		totwrite= psys->totpart;
-
 	return totwrite;
 }
 
@@ -489,7 +496,7 @@
 //}
 //
 /* Cloth functions */
-static int ptcache_write_cloth(int index, void *cloth_v, void **data)
+static int ptcache_write_cloth(int index, void *cloth_v, void **data, int cfra)
 {
 	ClothModifierData *clmd= cloth_v;
 	Cloth *cloth= clmd->clothObject;
@@ -554,7 +561,7 @@
 	/* should vert->xconst be interpolated somehow too? - jahka */
 }
 
-static int ptcache_totpoint_cloth(void *cloth_v)
+static int ptcache_totpoint_cloth(void *cloth_v, int cfra)
 {
 	ClothModifierData *clmd= cloth_v;
 	return clmd->clothObject->numverts;
@@ -615,12 +622,8 @@
 	pid->write_header= ptcache_write_basic_header;
 	pid->read_header= ptcache_read_basic_header;
 
-	pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY);
+	pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY) | (1<<BPHYS_DATA_INDEX);
 
-	/* TODO for later */
-	//if((psys->part->flag & (PART_UNBORN|PART_DIED))==0)
-	//	pid->data_types|= (1<<BPHYS_DATA_INDEX);
-
 	if(psys->part->phystype == PART_PHYS_BOIDS)
 		pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION) | (1<<BPHYS_DATA_BOIDS);
 
@@ -635,7 +638,7 @@
 }
 
 /* Smoke functions */
-static int ptcache_totpoint_smoke(void *smoke_v)
+static int ptcache_totpoint_smoke(void *smoke_v, int cfra)
 {
 	SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
 	SmokeDomainSettings *sds = smd->domain;
@@ -648,7 +651,7 @@
 }
 
 /* Smoke functions */
-static int ptcache_totpoint_smoke_turbulence(void *smoke_v)
+static int ptcache_totpoint_smoke_turbulence(void *smoke_v, int cfra)
 {
 	SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
 	SmokeDomainSettings *sds = smd->domain;
@@ -1266,12 +1269,32 @@
 	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;
+	if(data_types & (1<<BPHYS_DATA_INDEX)) {
+		int totpoint;
+		/* The simplest solution is to just write to the very end. This may cause
+		 * some data duplication, but since it's on disk it's not so bad. The correct
+		 * thing would be to search through the file for the correct index and only
+		 * write to the end if it's not found, but this could be quite slow.
+		 */
+		fseek(pf->fp, 8 + sizeof(int), SEEK_SET);
+		fread(&totpoint, sizeof(int), 1, pf->fp);
+		
+		totpoint++;
 
+		fseek(pf->fp, 8 + sizeof(int), SEEK_SET);
+		fwrite(&totpoint, sizeof(int), 1, pf->fp);
+
+		fseek(pf->fp, 0, SEEK_END);
+	}
+	else {
+		for(i=0; i<BPHYS_TOT_DATA; i++)
+			size += pf->data_types & (1<<i) ? ptcache_data_size[i] : 0;
+
+		/* size of default header + data up to index */
+		fseek(pf->fp, 8 + 3*sizeof(int) + index * size, SEEK_SET);
+	}
+
 	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)
 {
@@ -1291,13 +1314,24 @@
 			pm->cur[i] = (char*)pm->cur[i] + ptcache_data_size[i];
 	}
 }
-void BKE_ptcache_mem_seek_pointers(int index, PTCacheMem *pm)
+static int BKE_ptcache_mem_seek_pointers(int point_index, PTCacheMem *pm)
 {
 	int data_types = pm->data_types;
-	int i;
+	int i, index = pm->index_array ? pm->index_array[point_index] - 1 : point_index;
 
+	if(index < 0) {
+		/* Can't give proper location without reallocation, so don't give any location.
+		 * Some points will be cached improperly, but this only happens with simulation
+		 * steps bigger than cache->step, so the cache has to be recalculated anyways
+		 * at some point.
+		 */
+		return 0;
+	}
+
 	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;
+
+	return 1;
 }
 static void ptcache_alloc_data(PTCacheMem *pm)
 {

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list