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)) {


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

Reply via email to