[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [15715] branches/soc-2008-unclezeiv/source /blender/render/intern/source/lightcuts.c: Added support for all lamp falloff types, except custom curves.
Davide Vercelli
unclezeiv at kerid.org
Wed Jul 23 18:59:54 CEST 2008
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)) {
More information about the Bf-blender-cvs
mailing list