[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [15283] branches/soc-2008-unclezeiv/source /blender/render/intern/source/lightcuts.c: Major commit: added support for directional lights.

Davide Vercelli davide.vercelli at gmail.com
Fri Jun 20 01:51:12 CEST 2008


Revision: 15283
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15283
Author:   unclezeiv
Date:     2008-06-20 01:50:20 +0200 (Fri, 20 Jun 2008)

Log Message:
-----------
Major commit: added support for directional lights.

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-06-19 19:09:21 UTC (rev 15282)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c	2008-06-19 23:50:20 UTC (rev 15283)
@@ -51,6 +51,8 @@
 #define CLUSTER_SUN   2
 #define CLUSTER_SPOT  3
 
+#define LA_TYPE_TO_CLUSTER_TYPE(c) ((c)+1)
+
 /* node of the lightcuts tree */
 typedef struct LightcutsCluster
 {
@@ -78,6 +80,8 @@
 
 typedef struct CutNode {
 	int id;
+	short type;
+	short pad;
 	float error_bound;
 	float contr_factor;
 	float contr_factor_noshad;
@@ -92,7 +96,15 @@
 	LightcutsCluster *array_local;
 	int free_local; /* location of first empty slot */
 	int root_local; /* id of root node */
+	int counter_local;
+
 	float max_local_dist; /* maximum distance for local lights */
+
+	LightcutsCluster *array_sun;
+	int free_sun; /* location of first empty slot */
+	int root_sun; /* id of root node */
+	int counter_sun;
+
 	int light_counter;
 	
 	float error_rate;
@@ -213,31 +225,45 @@
 	}
 }
 
-static void lightcuts_fill_array(LightcutsData *lcd, ListBase * pointlights)
+static void lightcuts_fill_array(ListBase * pointlights, LightcutsCluster **array, int *n_free, int max_lights, char * name, int cur_type)
 {
 	GroupObject *go;
 	LampRen *lar;
 	LightcutsCluster *clus;
 	
-	lcd->array_local= MEM_callocN(sizeof(LightcutsCluster) * lcd->max_lights * 2, "array_local");
-	lcd->free_local= 0;
-	lcd->root_local= 0;
-	
-	clus= lcd->array_local;
+	*array= MEM_callocN(sizeof(LightcutsCluster) * max_lights * 2, name);
+	*n_free= 0;
+
+	clus= *array;
 		
 	for(go = pointlights->first; go; go = go->next) {
 		lar = go->lampren;
 		if (lar==NULL) continue;
 		
-		if (lar->type!=LA_LOCAL)
+		if (lar->type!=cur_type)
 			continue;
 		
-		clus->type = CLUSTER_LOCAL;
+		clus->type = LA_TYPE_TO_CLUSTER_TYPE(cur_type);
 		clus->in_tree = 0;
-		clus->id = lcd->free_local;
+		clus->id = *n_free;
 		clus->intensity = lar->energy;
-		VECCOPY(clus->min, lar->co);
-		VECCOPY(clus->max, lar->co);
+
+		switch (lar->type) {
+		case LA_LOCAL:
+			VECCOPY(clus->min, lar->co);
+			VECCOPY(clus->max, lar->co);
+			break;
+		case LA_SUN:
+			/*
+			 * the position of a directional light is meaningless
+			 * we give them a conventional position on the unit sphere
+			 */
+			clus->min[0]= -lar->vec[0];
+			clus->min[1]= -lar->vec[1];
+			clus->min[2]= -lar->vec[2];
+			VECCOPY(clus->max, clus->min);
+			break;
+		}
 		clus->lar = lar;
 		
 		/* we need the original lamp color, not the premultiplied one */
@@ -248,14 +274,14 @@
 		clus->luminance= LC_LUMINOSITY(clus->col) * lar->energy;
 		
 		clus++;
-		lcd->free_local++;
+		(*n_free)++;
 	}
 }
 
 #ifdef LIGHTCUTS_DEBUG
-static void dbg_print_tree(LightcutsCluster *array, int root, int lev)
+static void dbg_print_tree(LightcutsCluster *array, int n_root, int lev)
 {
-	LightcutsCluster *el= &array[root];
+	LightcutsCluster *el= &array[n_root];
 	int i;
 	for (i = 0; i < lev; i++)
 		printf("-");
@@ -268,9 +294,9 @@
 	dbg_print_tree(array, el->child2, lev + 1);		
 }
 
-static void dbg_check_tree(LightcutsCluster *array, int root)
+static void dbg_check_tree(LightcutsCluster *array, int n_root)
 {
-	LightcutsCluster *el= &array[root];
+	LightcutsCluster *el= &array[n_root];
 	
 	if (el->child1 == 0 && el->child2 == 0)
 		return;
@@ -283,21 +309,21 @@
 	dbg_check_tree(array, el->child2);		
 }
 #endif
-	
-static void lightcuts_build_tree(LightcutsData *lcd)
+
+static void lightcuts_build_tree(int max_lights, LightcutsCluster *array, int *n_free, int *n_root)
 {	
 	int i, cluster_id = 0;
 	
 	Heap * heap = BLI_heap_new();
-	/* TODO: taylor size */
-	LightcutsClusterPair *pair_array= MEM_callocN(sizeof(LightcutsClusterPair) * lcd->max_lights * 2, "pair_array");
+	/* TODO: taylor size: done. current TODO is "check if it works" */
+	LightcutsClusterPair *pair_array= MEM_callocN(sizeof(LightcutsClusterPair) * max_lights * 2, "pair_array");
 	
-	for (i = 0; i < lcd->max_lights; i++)
+	for (i = 0; i < max_lights; i++)
 	{
-		if (lcd->array_local[i].type == CLUSTER_EMPTY)
+		if (array[i].type == CLUSTER_EMPTY)
 			break;
 				
-		find_and_insert_new_min(heap, lcd->array_local, lcd->max_lights * 2, &pair_array[i], i, i + 1);
+		find_and_insert_new_min(heap, array, max_lights * 2, &pair_array[i], i, i + 1);
 	}
 	
 	/* now we have a nice heap with shortest metric for each element */
@@ -307,8 +333,8 @@
 	while (!BLI_heap_empty(heap))
 	{
 		LightcutsClusterPair * minpair = (LightcutsClusterPair *)BLI_heap_popmin(heap);
-		short in_tree1 = lcd->array_local[minpair->first].in_tree;
-		short in_tree2 = lcd->array_local[minpair->second].in_tree;
+		short in_tree1 = array[minpair->first].in_tree;
+		short in_tree2 = array[minpair->second].in_tree;
 		
 		if (in_tree1)
 			continue;
@@ -316,28 +342,28 @@
 		/* we look for another minimum */		
 		if (in_tree2)
 		{
-			find_and_insert_new_min(heap, lcd->array_local, lcd->max_lights * 2, minpair, minpair->first, 0);
+			find_and_insert_new_min(heap, array, max_lights * 2, minpair, minpair->first, 0);
 			continue;
 		}
 		
 		/* valid pair: build cluster out of it, mark children as used */
-		cluster_id = lcd->free_local;
-		add_new_cluster(lcd->array_local, minpair, &lcd->free_local);
+		cluster_id = *n_free;
+		add_new_cluster(array, minpair, n_free);
 		
 		/* new search, avoid considering in_tree children */
-		find_and_insert_new_min(heap, lcd->array_local, lcd->max_lights * 2, minpair, cluster_id, 0);
+		find_and_insert_new_min(heap, array, max_lights * 2, minpair, cluster_id, 0);
 	}
 	
 	BLI_heap_free(heap, 0);
 	
 	/* the last cluster added is the root of the tree */	
-	lcd->root_local = cluster_id;
+	*n_root = cluster_id;
 
 #ifdef LIGHTCUTS_DEBUG
-	dbg_check_tree(lcd->array_local, lcd->root_local);
-	/* dbg_print_tree(lcd->array_local, lcd->root_local, 0); */
+	dbg_check_tree(array, *n_root);
+	dbg_print_tree(array, *n_root, 0);
 #endif
-	printf("Lightcuts tree built. %d nodes used.\n", lcd->root_local);
+	printf(" %d nodes used.\n", *n_root + 1);
 	
 	MEM_freeN(pair_array);
 }
@@ -421,9 +447,25 @@
 		gonew->ob= 0;
 		gonew->recalc= go->recalc;
 		
-		if (lar->type!=LA_LOCAL)
+		switch (lar->type) {
+		case LA_LOCAL:
+			lcd->counter_local++;
+			
+			/* TODO: handle other attenuation models */
+
+			if (lar->dist < lcd->max_local_dist)
+				lcd->max_local_dist = lar->dist;
+			
+			break;
+		case LA_SUN:
+			lcd->counter_sun++;
+			break;
+		default:
 			continue;
+		}
 		
+		lcd->light_counter++;
+		
 		/* 
 		 * each light will contribute only marginally to the shadowing
 		 * that's why here I set a simpler sampling method
@@ -431,11 +473,6 @@
 		 */
 		lar->ray_samp_method = LA_SAMP_CONSTANT;
 		
-		if (lar->dist < lcd->max_local_dist)
-			lcd->max_local_dist = lar->dist;
-		
-		lcd->light_counter++;
-		
 #ifdef LIGHTCUTS_CURRENTLY_UNUSED
 		/*
 		 * proof-of-concept functionality:
@@ -486,23 +523,34 @@
 	lcd->max_lights= lcd->light_counter;
 	lcd->error_rate= re->r.lightcuts_max_error;
 	lcd->max_cut= MIN2(re->r.lightcuts_max_cut, lcd->light_counter);
+
+	/* build LA_LOCAL tree */
+	if (lcd->counter_local > 0) {
+		lightcuts_fill_array(pointlights, &lcd->array_local, &lcd->free_local, lcd->counter_local, "lc_array_local", LA_LOCAL);
+		printf("Lightcuts: local (Lamp) lights tree built - ");
+		lightcuts_build_tree(lcd->counter_local, lcd->array_local, &lcd->free_local, &lcd->root_local);
+	}
+
+	/* build LA_SUN tree */
+	if (lcd->counter_sun > 0) {
+		lightcuts_fill_array(pointlights, &lcd->array_sun, &lcd->free_sun, lcd->counter_sun, "lc_array_sun", LA_SUN);
+		printf("Lightcuts: directional (Sun) lights tree built - ");
+		lightcuts_build_tree(lcd->counter_sun, lcd->array_sun, &lcd->free_sun, &lcd->root_sun);
+	}
 	
-	lightcuts_fill_array(lcd, pointlights);
-	lightcuts_build_tree(lcd);
-	
 	lcd->cut_nodes_size= (lcd->max_lights * 2 + 1);
 	lcd->cut_nodes= MEM_callocN(sizeof(CutNode) * lcd->cut_nodes_size * re->r.threads, "cut_nodes");
 }
 
 /* Adapted from "Transforming Axis-Aligned Bounding Boxes" by Jim Arvo, "Graphics Gems", Academic Press, 1990 */
-static void transform_aabb(float tsm[4][4], float min[3], float max[3], float rmin[3], float rmax[3])
+static void transform_aabb(float tsm[4][4], float min[3], float max[3], float rmin[3], float rmax[3], int do_transl)
 {
 	int i, j;
 	float a, b;
 	
 	for (i = 0; i < 3; i++) {
 		/* translation */
-		rmin[i]= rmax[i]= tsm[i][3];
+		rmin[i]= rmax[i]= (do_transl ? tsm[i][3] : 0.0f);
 		
 		for (j = 0; j < 3; j++) {
 			a= tsm[i][j] * min[j];
@@ -563,31 +611,34 @@
 static float calc_material_eb(float tsm[4][4], LightcutsCluster *clus)
 {
 	float tmin[3], tmax[3];
-	transform_aabb(tsm, clus->min, clus->max, tmin, tmax);
+	transform_aabb(tsm, clus->min, clus->max, tmin, tmax, (clus->type!=CLUSTER_SUN));
 	return MAX2(compute_cosine_bound(tmin, tmax), 0.0);
 }
 
 /* error bound: geometric term */
-/* TODO: right now is working only for omnidirectional (LA_LOCAL) lights */
-static float calc_geometric_eb(LightcutsData *lcd, int id, float *pos)
+/* TODO: missing LA_SPOT eb */
+static float calc_geometric_eb(LightcutsData *lcd, LightcutsCluster *clus, float *pos)
 {
-	/* find the nearest point in the bounding box */
-	float *min= lcd->array_local[id].min;
-	float *max= lcd->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 lcd->max_local_dist / (lcd->max_local_dist + len_sq);
+	if (clus->type==CLUSTER_LOCAL) {
+		/* find the nearest point in the bounding box */
+		float *min= clus->min;
+		float *max= clus->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);
+
+		/* 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list