[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [14984] branches/soc-2008-unclezeiv/source /blender/render/intern: Added tree traversal: the basic skeleton of the algorithm is now in place.

Davide Vercelli davide.vercelli at gmail.com
Mon May 26 19:46:35 CEST 2008


Revision: 14984
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=14984
Author:   unclezeiv
Date:     2008-05-26 19:46:35 +0200 (Mon, 26 May 2008)

Log Message:
-----------
Added tree traversal: the basic skeleton of the algorithm is now in place.
Right now there is a very long list of limitations, in particular:
- works only with diffuse lambert shading
- works only with omni ("Lamp") lights
- diffuse and shadow render layers aren't updated properly
Moreover, some test scenes are not being rendered correctly yet.

Note: in shadeoutput.c, I've been working on a copy of shade_one_light: eventually I'll get rid of the copy and refactor the original function, but in the meanwhile, as a work in progress, I prefer to fiddle with a copy in order to avoid problems while merging.

Also, disabled lightcuts for 3dview shading.

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

Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/include/lightcuts.h
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/include/lightcuts.h	2008-05-26 16:19:30 UTC (rev 14983)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/include/lightcuts.h	2008-05-26 17:46:35 UTC (rev 14984)
@@ -33,4 +33,8 @@
 
 void lightcuts_create_point_lights(Render * re);
 
+typedef float (*LightContribFunc)(LampRen *lar, ShadeInput *shi);
+
+void lightcuts_do_lights(LightContribFunc get_contrib, ShadeInput *shi, float * diff);
+
 #endif /*LIGHTCUTS_H_*/

Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/source/convertblender.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/convertblender.c	2008-05-26 16:19:30 UTC (rev 14983)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/convertblender.c	2008-05-26 17:46:35 UTC (rev 14984)
@@ -5425,7 +5425,7 @@
 
 	/* renderdata setup and exceptions */
 	re->r= scene->r;
-	
+		
 	RE_init_threadcount(re);
 	
 	re->flag |= R_GLOB_NOPUNOFLIP;
@@ -5442,6 +5442,7 @@
 		re->r.mode &= ~R_SHADOW;
 		re->r.mode &= ~R_RAYTRACE;
 	}
+	re->r.mode &= ~R_LIGHTCUTS;
 	
 	/* setup render stuff */
 	re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);

Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c	2008-05-26 16:19:30 UTC (rev 14983)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c	2008-05-26 17:46:35 UTC (rev 14984)
@@ -63,6 +63,7 @@
 	float intensity;
 	float min[3];
 	float max[3];
+	LampRen * lar;
 } LightcutsCluster;
 
 typedef struct LightcutsClusterPair
@@ -89,6 +90,11 @@
 	return (one->intensity + two->intensity) * VEC_LEN_SQ(diff);
 }
 
+static LampRen * random_select(LampRen * one, float ione, LampRen * two, float itwo)
+{
+	return (BLI_frand() * (ione + itwo)) < ione ? one : two;
+}
+
 static void add_new_cluster(LightcutsCluster * array, LightcutsClusterPair * minpair, int * root)
 {
 	LightcutsCluster *one = &array[minpair->first];
@@ -112,6 +118,9 @@
 	DO_MINMAX(two->min, dest->min, dest->max);
 	DO_MINMAX(two->max, dest->min, dest->max);
 	
+	/* the representative light is chosen randomly among children */
+	dest->lar = random_select(one->lar, one->intensity, two->lar, two->intensity);
+	
 	(*root)++;
 }
 
@@ -161,6 +170,7 @@
 /* id of root node */
 int root_local;
 /* TODO: equivalent data structures for sun and spot */
+float max_local_dist;
 
 static void lightcuts_fill_array(ListBase * pointlights)
 {
@@ -186,6 +196,7 @@
 		clus->intensity = lar->energy;
 		VECCOPY(clus->min, lar->co);
 		VECCOPY(clus->max, lar->co);
+		clus->lar = lar;
 		
 		clus++;
 		free_local++;
@@ -308,12 +319,6 @@
 	}
 }
 
-/*
- * proof-of-concept functionality:
- * for each existing "lamp" or "sun", add another one, identical but:
- * - having a random colour
- * - displaced of 1 unit along light direction
- */
 void lightcuts_create_point_lights(Render * re)
 {	
 	GroupObject *go, *gonew;
@@ -322,6 +327,7 @@
 	LampRen *lar, *larnew;
 	float r, g, b, n;
 	int count = 0;
+	max_local_dist = -1.0f;
 	
 	for(go=lights->first; go; go= go->next) {
 		lar= go->lampren;
@@ -339,7 +345,23 @@
 		if (lar->type!=LA_LOCAL)
 			continue;
 		
-		/* then create a new one */
+		/* 
+		 * each light will contribute only marginally to the shadowing
+		 * that's why here I set a simpler sampling method
+		 * TODO: QMC may be restored for stronger lights
+		 */
+		lar->ray_samp_method = LA_SAMP_CONSTANT;
+		
+		if (lar->dist < max_local_dist || max_local_dist < 0.0f)
+			max_local_dist = lar->dist;
+		
+#if 0
+		/*
+		 * proof-of-concept functionality:
+		 * for each existing "lamp" or "sun", add another one, identical but:
+		 * - having a random colour
+		 * - displaced of 1 unit along light direction
+		 */
 		gonew= MEM_callocN(sizeof(GroupObject), "groupobject");
 		BLI_addtail(pointlights, gonew);
 		gonew->recalc= go->recalc;
@@ -376,6 +398,7 @@
 		
 		BLI_addtail(&re->lampren, larnew);
 		gonew->lampren= larnew;
+#endif
 	}
 	
 	if (pointlights->first)
@@ -384,3 +407,156 @@
 		lightcuts_build_tree();
 	}
 }
+
+typedef struct CutNode {
+	int id;
+	float contr_factor;
+	float contr_own[3];
+	float contr_clus[3];
+	float error_bound;
+} CutNode;
+
+#define LIGHTCUTS_ERROR_RATE 0.02
+#define LIGHTCUTS_MAX_CUT 1000
+
+/* TODO: tentative calculation, will look better into it */
+#define LC_LUMINOSITY(c) (0.299*c[0] + 0.587*c[1] + 0.114*c[2])
+
+/* error bound: geometric term */
+/* TODO: right now is working only for point lights */
+float calc_geometric_eb(int id, float *pos)
+{
+	/* find the nearest point in the bounding box */
+	float *min= array_local[id].min;
+	float *max= array_local[id].max;
+	float nearest[3];
+	float len_sq;
+	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);
+	len_sq= VEC_LEN_SQ(nearest);
+	
+	/* 
+	 * TODO: could take the various supported attenuation functions into account,
+	 * using the worst case among the one found while creating the tree
+	 */	
+	return max_local_dist / (max_local_dist + len_sq);
+}
+
+#define VECCOPYMUL(v1,v2,aS) {*(v1)= *(v2)*aS; *(v1+1)= *(v2+1)*aS; *(v1+2)= *(v2+2)*aS;}
+
+/*
+ * what about intensity? which one should we use?
+ * RESOLUTION: the one of the lamp, then adjusted
+ */
+
+void lightcuts_do_lights(LightContribFunc get_contrib, ShadeInput *shi, float * diff)
+{
+	/* TODO: show that this size is always sufficient */
+	CutNode cut_nodes[LIGHTCUTS_MAX_CUT * 2];
+	int free_node= 1;
+	
+	/* this heap maintaines the current cut */
+	/* TODO: its maximum size is known in advance, this allows to
+	 * preallocate it and share it between subsequent executions
+	 */
+	Heap *cut= BLI_heap_new();
+	
+	/* this is the total radiance estimate, continuously updated */
+	float totest[3]= {0.0f, 0.0f, 0.0f};
+	
+	memset(cut_nodes, 0, sizeof(cut_nodes));
+	
+	{
+		CutNode *root= &cut_nodes[0];
+		LampRen *lar= array_local[root_local].lar;
+		
+		root->id= root_local;
+		
+		root->contr_factor= get_contrib(lar, shi);
+		
+		root->contr_own[0]= lar->r * root->contr_factor;
+		root->contr_own[1]= lar->g * root->contr_factor;
+		root->contr_own[2]= lar->b * root->contr_factor;
+		
+		root->contr_clus[0]= root->contr_own[0] * array_local[root_local].intensity / lar->energy;
+		root->contr_clus[1]= root->contr_own[1] * array_local[root_local].intensity / lar->energy;
+		root->contr_clus[2]= root->contr_own[2] * array_local[root_local].intensity / lar->energy;
+		
+		root->error_bound= calc_geometric_eb(root_local, shi->co);
+		
+		VECADD(totest, totest, root->contr_clus);
+		
+		BLI_heap_insert(cut, -root->error_bound, root);
+	}
+	
+	/* at each iteration the heap grows by one, but we have a maximum size */
+	while (BLI_heap_size(cut) < LIGHTCUTS_MAX_CUT && BLI_heap_size(cut) > 0) {
+		CutNode *node= BLI_heap_popmin(cut);
+		LightcutsCluster *parent= &array_local[node->id];
+		
+		if (parent->child1==0 && parent->child2==0)
+			continue;
+				
+		if (LC_LUMINOSITY(totest) * LIGHTCUTS_ERROR_RATE > node->error_bound * parent->intensity) {
+			break;
+		} else {
+			LightcutsCluster *rep= &array_local[parent->child1];
+			LightcutsCluster *unrep= &array_local[parent->child2];
+			CutNode *c_rep= &cut_nodes[free_node];
+			CutNode *c_unrep= &cut_nodes[free_node + 1];
+			
+			free_node += 2;
+			
+			if (parent->lar != rep->lar)
+				SWAP(LightcutsCluster*, rep, unrep);
+						
+			/*
+			 * XXX: numerically questionable
+			 * but please note that it's the same quantity
+			 * we are not calculating it in different ways
+			 */
+			VECSUB(totest, totest, node->contr_clus);
+			
+			/* this is a strong assumption on linearity of intensity contribution... is it strong indeed?
+			 * and numerically questionable again */
+			/* TODO: there is room to reuse the same block here */
+			
+			/* for the reprsented light we can reuse most calculations */
+			c_rep->contr_factor= node->contr_factor;
+			VECCOPY(c_rep->contr_own, node->contr_own);
+			VECCOPYMUL(c_rep->contr_clus, c_rep->contr_own, rep->intensity / rep->lar->energy);
+			c_rep->error_bound= calc_geometric_eb(rep->id, shi->co);
+			c_rep->id= rep->id;
+			
+			BLI_heap_insert(cut, -c_rep->error_bound, c_rep);
+			
+			VECADD(totest, totest, c_rep->contr_clus);
+			
+			/* for the "unrepresented" light we have to compute stuff from scratch */
+			c_unrep->contr_factor= get_contrib(unrep->lar, shi);
+			c_unrep->contr_own[0]= unrep->lar->r * c_unrep->contr_factor;
+			c_unrep->contr_own[1]= unrep->lar->g * c_unrep->contr_factor;
+			c_unrep->contr_own[2]= unrep->lar->b * c_unrep->contr_factor;
+			c_unrep->contr_clus[0]= c_unrep->contr_own[0] * unrep->intensity / unrep->lar->energy;
+			c_unrep->contr_clus[1]= c_unrep->contr_own[1] * unrep->intensity / unrep->lar->energy;
+			c_unrep->contr_clus[2]= c_unrep->contr_own[2] * unrep->intensity / unrep->lar->energy;
+			c_unrep->error_bound= calc_geometric_eb(unrep->id, shi->co);
+			c_unrep->id= unrep->id;
+			BLI_heap_insert(cut, -c_unrep->error_bound, c_unrep);
+			
+			VECADD(totest, totest, c_unrep->contr_clus);
+		}
+	}
+	
+	/*
+	 * here, the content of the queue IS the cut, but we already should have
+	 * an updated TOTREP value (even thought numerically questionable?)
+	 */
+	
+	VECADD(diff, diff, totest);
+	
+	BLI_heap_free(cut, 0);
+}

Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c	2008-05-26 16:19:30 UTC (rev 14983)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c	2008-05-26 17:46:35 UTC (rev 14984)
@@ -43,6 +43,7 @@
 #include "DNA_material_types.h"
 
 /* local include */
+#include "lightcuts.h"
 #include "occlusion.h"
 #include "renderpipeline.h"
 #include "render_types.h"
@@ -1524,6 +1525,8 @@
 	diff[2]= R.wrld.linfac*(1.0f-exp( diff[2]*R.wrld.logfac) );
 }
 
+static float single_light_contrib(LampRen *lar, ShadeInput *shi);
+

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list