[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [15715] branches/soc-2008-unclezeiv/source /blender/render/intern/source/lightcuts.c: Added support for all lamp falloff types, except custom curves.

Davide Vercelli unclezeiv at kerid.org
Wed Jul 23 18:59:54 CEST 2008


Revision: 15715
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15715
Author:   unclezeiv
Date:     2008-07-23 18:59:54 +0200 (Wed, 23 Jul 2008)

Log Message:
-----------
Added support for all lamp falloff types, except custom curves. Lamp falloffs are now handled per-cluster instead of globally as it was before: this should give better error bounding in general.

Limitations:
- sphere option still unsupported
- custom curves falloff is currently trivially bound to 1.0; it could be handled slightly better but it's not a priority right now

Also minor changes in debug code.

Modified Paths:
--------------
    branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c

Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c	2008-07-23 15:45:23 UTC (rev 15714)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c	2008-07-23 16:59:54 UTC (rev 15715)
@@ -65,6 +65,24 @@
 #define TREE_SPOT  2
 #define _TREES_SIZE 3
 
+#define FALLOFF_CONST  0
+#define FALLOFF_LINEAR 1
+#define FALLOFF_QUAD   2
+#define FALLOFF_MIX    3
+#define FALLOFF_SLIDER 3
+
+/*
+ * This is a table to select the "worst falloff" for a cluster, given the
+ * falloff types of its children.
+ * This is needed in order to always calculate a *conservative* error bound.
+ */
+static short falloff_merge[][4] = {
+	{FALLOFF_CONST , FALLOFF_CONST , FALLOFF_CONST , FALLOFF_CONST },
+	{FALLOFF_CONST , FALLOFF_LINEAR, FALLOFF_MIX   , FALLOFF_MIX   },
+	{FALLOFF_CONST , FALLOFF_MIX   , FALLOFF_QUAD  , FALLOFF_MIX   },
+	{FALLOFF_CONST , FALLOFF_MIX   , FALLOFF_MIX   , FALLOFF_MIX   },
+};
+
 #define CLUSTER_TYPE_TO_ARRAY_IDX(c) ((c)-1)
 
 /* strings for guarded alloc */
@@ -77,12 +95,9 @@
 {
 	short type;
 	short in_tree;
-	int id; /* must be able to accomodate millions of lights */
+	int id; /* must be able to accommodate millions of lights */
 	int child1;
 	int child2;
-#ifdef LIGHTCUTS_DEBUG
-	int dbg_parent;
-#endif
 	float intensity;
 	float min[3];
 	float max[3];
@@ -92,6 +107,11 @@
 	float cone_angle;
 	float luminance;
 	LampRen * lar;
+	short falloff_type, pad;
+	float falloff_dist;
+#ifdef LIGHTCUTS_DEBUG
+	int dbg_parent;
+#endif
 } LightcutsCluster;
 
 typedef struct LightcutsClusterPair
@@ -126,9 +146,6 @@
 
 	LightcutsTree trees[_TREES_SIZE];
 
-	float max_local_dist; /* maximum distance for local lights */
-	float max_spot_dist; /* maximum distance for oriented lights */
-
 	int light_counter;
 
 	float error_rate;
@@ -246,6 +263,10 @@
 		VECCOPY(dest->col, two->col);
 	}
 	dest->intensity= dest->luminance / LC_LUMINOSITY(dest->col);
+	
+	/* worst case falloff type/dist for conservative error estimation */
+	dest->falloff_type= falloff_merge[one->falloff_type][two->falloff_type];
+	dest->falloff_dist= MAX2(one->falloff_dist, two->falloff_dist);
 
 	(*root)++;
 }
@@ -341,6 +362,43 @@
 		clus->col[1]= lar->g / lar->energy;
 		clus->col[2]= lar->b / lar->energy;
 		clus->luminance= LC_LUMINOSITY(clus->col) * lar->energy;
+		
+		switch (lar->falloff_type) {
+		case LA_FALLOFF_CONSTANT:
+		case LA_FALLOFF_CURVE: /* basically unsupported */
+			clus->falloff_type= FALLOFF_CONST;
+			clus->falloff_dist= 0.0f;
+			break;
+		case LA_FALLOFF_INVLINEAR:
+			clus->falloff_type= FALLOFF_LINEAR;
+			clus->falloff_dist= lar->dist;
+			break;
+		case LA_FALLOFF_INVSQUARE:
+			clus->falloff_type= FALLOFF_QUAD;
+			clus->falloff_dist= lar->dist;
+			break;
+		case LA_FALLOFF_SLIDERS:
+			if (lar->ld1==0.0f) {
+				clus->falloff_type= FALLOFF_QUAD;
+				clus->falloff_dist= lar->dist * lar->dist / lar->ld2;
+			}
+			else if (lar->ld2==0.0f) {
+				clus->falloff_type= FALLOFF_LINEAR;
+				clus->falloff_dist= lar->dist / lar->ld1;
+			}
+			else {
+				/*
+				 * We bound the generic slider case ("LinQuad weighted") as if
+				 * we were mixing separate linear and quadratic falloffs; by
+				 * trivial manipulation, the general slider equation is bounded
+				 * both by a linear falloff with distance = d/ld1 and by a
+				 * quadratic falloff with distance = d^2/ld2 
+				 */
+				clus->falloff_type= FALLOFF_MIX;
+				clus->falloff_dist= lar->dist * MAX2(1.0f / lar->ld1, lar->dist / lar->ld2);
+			}
+			break;
+		}
 
 		clus++;
 		tree->free++;
@@ -354,10 +412,18 @@
 	int i;
 	for (i = 0; i < lev; i++)
 		printf("-");
-	printf(" id %d, int %f, lum %f\n", el->id, el->intensity, el->luminance);
-
-	if (el->child1 == 0 && el->child2 == 0)
+	printf(" id %d, int %f, lum %f, falloff_t %d, _dist %f, ",
+			el->id, el->intensity, el->luminance,
+			el->falloff_type, el->falloff_dist);
+	
+	if (el->child1 != 0 && el->lar == array[el->child1].lar)
+		printf("rep %d\n", el->child1);
+	else if (el->child2 != 0 && el->lar == array[el->child2].lar)
+		printf("rep %d\n", el->child2);
+	else {
+		printf("\n");
 		return;
+	}
 
 	dbg_print_tree(array, el->child1, lev + 1);
 	dbg_print_tree(array, el->child2, lev + 1);
@@ -867,10 +933,6 @@
 		/* check deallocation */
 		gonew->lampren= lar;
 
-		/* TODO: handle other attenuation models */
-		if (lar->dist < lcd->max_spot_dist)
-			lcd->max_spot_dist= lar->dist;
-
 		lcd->trees[TREE_SPOT].counter++;
 		lcd->light_counter++;
 		lar->ray_samp_method = LA_SAMP_CONSTANT;
@@ -892,8 +954,6 @@
 
 	re->lcdata = lcd = MEM_callocN(sizeof(LightcutsData), "LightcutsData");
 	pointlights= &lcd->pointlights;
-	lcd->max_local_dist= MAXFLOAT;
-	lcd->max_spot_dist= MAXFLOAT;
 	lcd->light_counter= 0;
 	
 	if (re->r.lightcuts_env_map > 0)
@@ -918,22 +978,12 @@
 		switch (lar->type) {
 		case LA_LOCAL:
 			lcd->trees[TREE_LOCAL].counter++;
-
-			/* TODO: handle other attenuation models */
-			if (lar->dist < lcd->max_local_dist)
-				lcd->max_local_dist = lar->dist;
-
 			break;
 		case LA_SUN:
 			lcd->trees[TREE_SUN].counter++;
 			break;
 		case LA_SPOT:
-			/* TODO: check if it's a valid spot */
-			
-			/* TODO: handle other attenuation models */
-			if (lar->dist < lcd->max_spot_dist)
-				lcd->max_spot_dist= lar->dist;
-			
+			/* TODO: check if it's a valid spot */			
 			lcd->trees[TREE_SPOT].counter++;
 			break;
 		default:
@@ -1062,32 +1112,45 @@
 	return eb_diff + eb_spec;
 }
 
-/* error bound: geometric term */
-static float calc_geometric_eb(LightcutsData *lcd, LightcutsCluster *clus, float *pos)
+static float get_attenuation(LightcutsCluster *clus, float *pos)
 {
-	/* find the nearest point in the bounding box */
 	float *min= clus->min;
 	float *max= clus->max;
-	float nearest[3];
-	float len_sq;
+	float nearest[3], len_sq;
 	
-	if (clus->type == CLUSTER_SUN)
+	if (clus->falloff_type == FALLOFF_CONST)
 		return 1.0f;
 	
-	nearest[0]= pos[0] < min[0] ? min[0] : (pos[0] > max[0] ? max[0] : pos[0]);
-	nearest[1]= pos[1] < min[1] ? min[1] : (pos[1] > max[1] ? max[1] : pos[1]);
-	nearest[2]= pos[2] < min[2] ? min[2] : (pos[2] > max[2] ? max[2] : pos[2]);
-
-	VECSUB(nearest, nearest, pos);
+	/* find the nearest point in the bounding box */
+	nearest[0]= CLAMPIS(pos[0], min[0], max[0]) - pos[0];
+	nearest[1]= CLAMPIS(pos[1], min[1], max[1]) - pos[1];
+	nearest[2]= CLAMPIS(pos[2], min[2], max[2]) - pos[2];
+	
 	len_sq= VEC_LEN_SQ(nearest);
+	
+	switch (clus->falloff_type) {
+	/* FALLOFF_CONST already considered as early out */
+	case FALLOFF_LINEAR:
+		return clus->falloff_dist / (clus->falloff_dist + sqrtf(len_sq));
+	case FALLOFF_QUAD:
+		return clus->falloff_dist / (clus->falloff_dist + len_sq);
+	case FALLOFF_MIX:
+		return clus->falloff_dist / (clus->falloff_dist + (len_sq < 1.0f ? len_sq : sqrtf(len_sq)));
+	default:
+		return 1.0f;
+	}
+}
 
-	/*
-	 * TODO: could take the various supported attenuation functions into account,
-	 * using the worst case among the one found while creating the tree
-	 */
+/* error bound: geometric term */
+static float calc_geometric_eb(LightcutsData *lcd, LightcutsCluster *clus, float *pos)
+{	
+	if (clus->type == CLUSTER_SUN)
+		return 1.0f;
+	
 	if (clus->type == CLUSTER_LOCAL)
-		return lcd->max_local_dist / (lcd->max_local_dist + len_sq);
-	else {
+		return get_attenuation(clus, pos);
+	
+	{
 		float newmin[3], transmin[3];
 		float newmax[3], transmax[3];
 		float cos_t, angle;
@@ -1105,9 +1168,10 @@
 		
 		if (angle <= clus->cone_angle)
 			return 1.0;
-		return lcd->max_spot_dist / (lcd->max_spot_dist + len_sq) * MAX2(0.0f, cosf(angle - clus->cone_angle));
+		return get_attenuation(clus, pos) * MAX2(0.0f, cosf(angle - clus->cone_angle));
 		
 		/*
+		 * TODO: possible optimizations
 		 * cos(a+b) = cos_a*cos_b - sin_a*sin_b
 		 * cos(angle-ca) = cos_t * cos_ca - sin_T * sin_ca
 		 * - cos_ca and sin_ca precomputable in initial step
@@ -1255,15 +1319,16 @@
 
 		hinode= &array[cn_hinode->id];
 #ifdef LIGHTCUTS_DEBUG
-		if (lcd->dbg_first_pixel==0)
-			printf("E t:%d id:%4d eb:%7.5f ebl:%7.5f fc:%7.5f (c1:%4d c2:%4d)\n",
+		if (lcd->dbg_first_pixel==0) {
+			printf("E t:%d id:%4d eb:%7.5f ebl:%7.5f cf:%7.5f fc:%7.5f (c1:%4d c2:%4d)\n",
 					CLUSTER_TYPE_TO_ARRAY_IDX(cn_hinode->type), cn_hinode->id,
-					cn_hinode->error_bound, cn_hinode->error_bound * hinode->luminance, cn_hinode->f_clus,
+					cn_hinode->error_bound, cn_hinode->error_bound * hinode->luminance, cn_hinode->contr_factor, cn_hinode->f_clus,
 					hinode->child1, hinode->child2);
+		}
 		if (cn_hinode->error_bound + FLT_EPSILON < cn_hinode->contr_factor) {
-			printf("troublesome node! at %d, %d (it=%d): eb %7.5f < cf %7.5f, (%10.6f * 10^6)\n",
-			shi->xs, shi->ys, it, cn_hinode->error_bound, cn_hinode->contr_factor, 1000000.0f * fabs(cn_hinode->error_bound - cn_hinode->contr_factor));
-			break;
+			printf("troublesome node! at %d, %d (it=%d) (id=%4d): eb %7.5f < cf %7.5f, (%10.6f * 10^6)\n",
+					shi->xs, shi->ys, it, cn_hinode->id, cn_hinode->error_bound, cn_hinode->contr_factor, 1000000.0f * fabs(cn_hinode->error_bound - cn_hinode->contr_factor));
+			// break;
 		}
 
 		if (IS_LEAF(hinode)) {





More information about the Bf-blender-cvs mailing list