Revision: 15971
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15971
Author:   unclezeiv
Date:     2008-08-05 14:50:46 +0200 (Tue, 05 Aug 2008)

Log Message:
-----------
Faster tree creation time. The improvement is already pretty tangible but more 
optimizations are on the way.

Also changed the intensity conversion formula for area lights: now it should do 
a better (but still not perfect) job in matching the default (Blender internal) 
intensity of area lights. Attention testers: this means that existing blend 
files will render differently from this revision on.

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-08-05 12:41:53 UTC (rev 15970)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c 
2008-08-05 12:50:46 UTC (rev 15971)
@@ -33,6 +33,7 @@
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
 #include "BLI_heap.h"
+#include "BLI_kdtree.h"
 #include "BLI_rand.h"
 #include "DNA_group_types.h"
 #include "DNA_lamp_types.h"
@@ -233,11 +234,13 @@
        return (one->luminance + two->luminance) * VEC_LEN_SQ(diff);
 }
 
-static void add_new_cluster(LightcutsCluster * array, LightcutsClusterPair * 
minpair, int * root)
+/* returns 0 if the new cluster uses the first child as representative, 1 
otherwise */
+static int add_new_cluster(LightcutsCluster * array, LightcutsClusterPair * 
minpair, int * root)
 {
        LightcutsCluster *one = &array[minpair->first];
        LightcutsCluster *two = &array[minpair->second];
        LightcutsCluster *dest = &array[*root];
+       int rep;
 
        /* mark children elements as already in tree */
        one->in_tree = 1;
@@ -269,10 +272,12 @@
        if (BLI_frand() * (one->luminance + two->luminance) < one->luminance) {
                dest->lar= one->lar;
                VECCOPY(dest->col, one->col);
+               rep= 0;
        }
        else {
                dest->lar= two->lar;
                VECCOPY(dest->col, two->col);
+               rep= 1;
        }
        dest->intensity= dest->luminance / LC_LUMINOSITY(dest->col);
        
@@ -284,6 +289,8 @@
        dest->sphere_dist= MAX2(one->sphere_dist, two->sphere_dist);
 
        (*root)++;
+       
+       return rep;
 }
 
 static void find_and_insert_new_min(Heap * heap, LightcutsCluster * array, int 
size, LightcutsClusterPair * pair, int id, int from, float c)
@@ -324,6 +331,77 @@
        }
 }
 
+/* this one uses kd tree */
+static void find_and_insert_new_min2(Heap * heap, KDTree * tree, KDTreeNearest 
*nearest, LightcutsCluster * array, LightcutsClusterPair * pair, int id, float 
c)
+{
+       LightcutsCluster *one= &array[id];
+       int near_idx= -1;
+       float pair_metric, metric;
+       float max_dist;
+       int found, j, other= -1;
+       
+       /* find nearest light in kdtree */
+       found= BLI_kdtree_find_n_nearest(tree, 2, one->lar->co, NULL, nearest);
+       
+       /*
+        * TODO: XXX: a bit hackish way to exclude the current element:
+        * we look for the 2 nearest elements and discard the current one
+        */
+       for (j= 0; j < found; j++)
+               if (nearest[j].index!= id)
+                       near_idx= nearest[j].index;
+       
+       /* when a single element is remaining, the search fails */
+       if (near_idx== -1)
+               return;
+       
+       /* compute metric w.r.t. the nearest element */
+       pair_metric= lightcuts_compute_metric(c, one, &array[near_idx]);
+       metric= pair_metric;
+       other= near_idx;
+       
+       /*
+        * compute maximum interesting distance:
+        * we are sure that elements further away have a greater metric value
+        */
+       max_dist= sqrtf(pair_metric / one->luminance);
+       
+       /* get all lights within that distance */
+       found= BLI_kdtree_find_in_sphere(tree, max_dist, one->lar->co, NULL, 
nearest);
+       
+       /* for each light compute metric and maximum distance */
+       /*
+        * TODO: better yet would be to take advantage of such knowledge
+        * while traversing the kdtree
+        */
+       for (j= 0; j < found; j++) {
+               LightcutsCluster *two= &array[nearest[j].index];
+               
+               if (nearest[j].index== id)
+                       continue;
+               
+               /* note: elements in "nearest" are sorted by distance */
+               if (nearest[j].dist > max_dist)
+                       break;
+               
+               pair_metric= lightcuts_compute_metric(c, one, two);
+               max_dist= sqrtf(pair_metric / one->luminance);
+               
+               if (pair_metric < metric) {
+                       other= two->id;
+                       metric= pair_metric;
+               }
+       }
+       
+       if (other != -1)
+       {
+               pair->first = id;
+               pair->second = other;
+
+               BLI_heap_insert(heap, metric, pair);
+       }
+}
+
 static void lightcuts_fill_array(ListBase *pointlights, LightcutsTree *tree, 
int cur_type)
 {
        GroupObject *go;
@@ -526,6 +604,117 @@
        MEM_freeN(pair_array);
 }
 
+/* this one uses kdtree */
+static void lightcuts_build_tree2(LightcutsTree *tree, float c)
+{
+       int i, rep, cluster_id= 0;
+       LightcutsCluster *array= tree->array;
+#ifdef LIGHTCUTS_DEBUG
+       double p1, p2;
+       char timestr[256];
+#endif
+
+       Heap * heap = BLI_heap_new();
+       LightcutsClusterPair *pair_array= 
MEM_callocN(sizeof(LightcutsClusterPair) * tree->counter * 2, "pair_array");
+       
+       KDTree* kdtree = BLI_kdtree_new(tree->counter);
+       KDTreeNearest *nearest= MEM_callocN(sizeof(KDTreeNearest) * 
tree->counter, "kdtreenearest");
+
+#ifdef LIGHTCUTS_DEBUG
+       p1= PIL_check_seconds_timer();
+#endif
+       
+       /* kdtree construction */
+       for (i= 0; i < tree->counter; i++)
+               BLI_kdtree_insert(kdtree, i, array[i].lar->co, NULL);
+
+#ifdef LIGHTCUTS_DEBUG
+       p2 = PIL_check_seconds_timer();
+       BLI_timestr(p2 - p1, timestr);
+       printf("add nodes: %s\n", timestr);
+       p1=p2;
+#endif
+       
+       BLI_kdtree_balance(kdtree);
+
+#ifdef LIGHTCUTS_DEBUG
+       p2 = PIL_check_seconds_timer();
+       BLI_timestr(p2 - p1, timestr);
+       printf("balance: %s\n", timestr);
+       p1=p2;
+#endif
+       
+       BLI_kdtree_build_correspondence(kdtree, 2);
+
+#ifdef LIGHTCUTS_DEBUG
+       p2 = PIL_check_seconds_timer();
+       BLI_timestr(p2 - p1, timestr);
+       printf("corr: %s\n", timestr);
+       p1=p2;
+#endif
+               
+       for (i = 0; i < tree->counter; i++)
+               if (array[i].type != CLUSTER_EMPTY)
+                       find_and_insert_new_min2(heap, kdtree, nearest, array, 
&pair_array[i], i, c);
+
+       /* now we have a nice heap with shortest metric for each element */
+       /* heap size = N (number of lights) - 1, and it doesn't grow */
+
+       /* go through heap building the tree */
+       while (!BLI_heap_empty(heap)) {
+               LightcutsClusterPair * minpair = (LightcutsClusterPair 
*)BLI_heap_popmin(heap);
+               short in_tree1 = array[minpair->first].in_tree;
+               short in_tree2 = array[minpair->second].in_tree;
+
+               if (in_tree1)
+                       continue;
+
+               /* we look for another minimum */
+               if (in_tree2) {
+                       find_and_insert_new_min2(heap, kdtree, nearest, array, 
minpair, minpair->first, c);
+                       continue;
+               }
+
+               /* valid pair: build cluster out of it, mark children as used */
+               cluster_id = tree->free;
+               rep= add_new_cluster(array, minpair, &tree->free);
+               
+               if (rep==0) {
+                       BLI_kdtree_weak_delete(kdtree, minpair->second);
+                       BLI_kdtree_change_index(kdtree, minpair->first, 
tree->free -1);
+               }
+               else {
+                       BLI_kdtree_weak_delete(kdtree, minpair->first);
+                       BLI_kdtree_change_index(kdtree, minpair->second, 
tree->free -1);
+               }
+
+               /* new search, avoid considering in_tree children */
+               find_and_insert_new_min2(heap, kdtree, nearest, array, minpair, 
cluster_id, c);
+       }
+
+       BLI_heap_free(heap, 0);
+       BLI_kdtree_free(kdtree);
+
+#ifdef LIGHTCUTS_DEBUG
+       p2 = PIL_check_seconds_timer();
+       BLI_timestr(p2 - p1, timestr);
+       printf("finally do stuff: %s\n", timestr);
+       p1=p2;
+#endif
+
+       /* the last cluster added is the root of the tree */
+       tree->root = cluster_id;
+
+#ifdef LIGHTCUTS_DEBUG
+       dbg_check_tree(array, tree->root);
+       dbg_print_tree(array, tree->root, 0);
+#endif
+       printf(" %d nodes used.\n", tree->root + 1);
+
+       MEM_freeN(pair_array);
+       MEM_freeN(nearest);
+}
+
 static void init_lamp(Render * re, LampRen * lar)
 {
        /* float xs, ys, dist, distkw; */
@@ -875,8 +1064,8 @@
        realw= sqrtf(VEC_LEN_SQ(orig->mat[0])) * orig->area_size;
        realh= sqrtf(VEC_LEN_SQ(orig->mat[1])) * orig->area_sizey;
        
-       n= MAX2((int)(density * realw), 1) * MAX2((int)(density * realh), 1); 
-       factor= 0.5f * sqrtf(orig->dist) * realw * realh / n;
+       n= MAX2((int)(density * realw), 1) * MAX2((int)(density * realh), 1);
+       factor= 2.0 * M_PI * orig->dist / (4.0 * realw * realh * n);
 
        /* XXX: TODO: temporary check just to avoid freezing on undue densities 
*/
        if (lcd->light_counter + n > re->r.lightcuts_max_lights) {
@@ -1041,7 +1230,7 @@
                if (lcd->trees[i].counter > 0) {
                        lightcuts_fill_array(pointlights, &lcd->trees[i], i);
                        printf("Lightcuts: building %s tree - ", tree_names[i]);
-                       lightcuts_build_tree(&lcd->trees[i], lcd->bb_diag_sq);
+                       lightcuts_build_tree2(&lcd->trees[i], lcd->bb_diag_sq);
                }
        }
        


_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to