[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