[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [14984] branches/soc-2008-unclezeiv/source /blender/render/intern: Added tree traversal: the basic skeleton of the algorithm is now in place.
Davide Vercelli
davide.vercelli at gmail.com
Mon May 26 19:46:35 CEST 2008
Revision: 14984
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=14984
Author: unclezeiv
Date: 2008-05-26 19:46:35 +0200 (Mon, 26 May 2008)
Log Message:
-----------
Added tree traversal: the basic skeleton of the algorithm is now in place.
Right now there is a very long list of limitations, in particular:
- works only with diffuse lambert shading
- works only with omni ("Lamp") lights
- diffuse and shadow render layers aren't updated properly
Moreover, some test scenes are not being rendered correctly yet.
Note: in shadeoutput.c, I've been working on a copy of shade_one_light: eventually I'll get rid of the copy and refactor the original function, but in the meanwhile, as a work in progress, I prefer to fiddle with a copy in order to avoid problems while merging.
Also, disabled lightcuts for 3dview shading.
Modified Paths:
--------------
branches/soc-2008-unclezeiv/source/blender/render/intern/include/lightcuts.h
branches/soc-2008-unclezeiv/source/blender/render/intern/source/convertblender.c
branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c
branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c
Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/include/lightcuts.h
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/include/lightcuts.h 2008-05-26 16:19:30 UTC (rev 14983)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/include/lightcuts.h 2008-05-26 17:46:35 UTC (rev 14984)
@@ -33,4 +33,8 @@
void lightcuts_create_point_lights(Render * re);
+typedef float (*LightContribFunc)(LampRen *lar, ShadeInput *shi);
+
+void lightcuts_do_lights(LightContribFunc get_contrib, ShadeInput *shi, float * diff);
+
#endif /*LIGHTCUTS_H_*/
Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/source/convertblender.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/convertblender.c 2008-05-26 16:19:30 UTC (rev 14983)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/convertblender.c 2008-05-26 17:46:35 UTC (rev 14984)
@@ -5425,7 +5425,7 @@
/* renderdata setup and exceptions */
re->r= scene->r;
-
+
RE_init_threadcount(re);
re->flag |= R_GLOB_NOPUNOFLIP;
@@ -5442,6 +5442,7 @@
re->r.mode &= ~R_SHADOW;
re->r.mode &= ~R_RAYTRACE;
}
+ re->r.mode &= ~R_LIGHTCUTS;
/* setup render stuff */
re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c 2008-05-26 16:19:30 UTC (rev 14983)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c 2008-05-26 17:46:35 UTC (rev 14984)
@@ -63,6 +63,7 @@
float intensity;
float min[3];
float max[3];
+ LampRen * lar;
} LightcutsCluster;
typedef struct LightcutsClusterPair
@@ -89,6 +90,11 @@
return (one->intensity + two->intensity) * VEC_LEN_SQ(diff);
}
+static LampRen * random_select(LampRen * one, float ione, LampRen * two, float itwo)
+{
+ return (BLI_frand() * (ione + itwo)) < ione ? one : two;
+}
+
static void add_new_cluster(LightcutsCluster * array, LightcutsClusterPair * minpair, int * root)
{
LightcutsCluster *one = &array[minpair->first];
@@ -112,6 +118,9 @@
DO_MINMAX(two->min, dest->min, dest->max);
DO_MINMAX(two->max, dest->min, dest->max);
+ /* the representative light is chosen randomly among children */
+ dest->lar = random_select(one->lar, one->intensity, two->lar, two->intensity);
+
(*root)++;
}
@@ -161,6 +170,7 @@
/* id of root node */
int root_local;
/* TODO: equivalent data structures for sun and spot */
+float max_local_dist;
static void lightcuts_fill_array(ListBase * pointlights)
{
@@ -186,6 +196,7 @@
clus->intensity = lar->energy;
VECCOPY(clus->min, lar->co);
VECCOPY(clus->max, lar->co);
+ clus->lar = lar;
clus++;
free_local++;
@@ -308,12 +319,6 @@
}
}
-/*
- * proof-of-concept functionality:
- * for each existing "lamp" or "sun", add another one, identical but:
- * - having a random colour
- * - displaced of 1 unit along light direction
- */
void lightcuts_create_point_lights(Render * re)
{
GroupObject *go, *gonew;
@@ -322,6 +327,7 @@
LampRen *lar, *larnew;
float r, g, b, n;
int count = 0;
+ max_local_dist = -1.0f;
for(go=lights->first; go; go= go->next) {
lar= go->lampren;
@@ -339,7 +345,23 @@
if (lar->type!=LA_LOCAL)
continue;
- /* then create a new one */
+ /*
+ * each light will contribute only marginally to the shadowing
+ * that's why here I set a simpler sampling method
+ * TODO: QMC may be restored for stronger lights
+ */
+ lar->ray_samp_method = LA_SAMP_CONSTANT;
+
+ if (lar->dist < max_local_dist || max_local_dist < 0.0f)
+ max_local_dist = lar->dist;
+
+#if 0
+ /*
+ * proof-of-concept functionality:
+ * for each existing "lamp" or "sun", add another one, identical but:
+ * - having a random colour
+ * - displaced of 1 unit along light direction
+ */
gonew= MEM_callocN(sizeof(GroupObject), "groupobject");
BLI_addtail(pointlights, gonew);
gonew->recalc= go->recalc;
@@ -376,6 +398,7 @@
BLI_addtail(&re->lampren, larnew);
gonew->lampren= larnew;
+#endif
}
if (pointlights->first)
@@ -384,3 +407,156 @@
lightcuts_build_tree();
}
}
+
+typedef struct CutNode {
+ int id;
+ float contr_factor;
+ float contr_own[3];
+ float contr_clus[3];
+ float error_bound;
+} CutNode;
+
+#define LIGHTCUTS_ERROR_RATE 0.02
+#define LIGHTCUTS_MAX_CUT 1000
+
+/* TODO: tentative calculation, will look better into it */
+#define LC_LUMINOSITY(c) (0.299*c[0] + 0.587*c[1] + 0.114*c[2])
+
+/* error bound: geometric term */
+/* TODO: right now is working only for point lights */
+float calc_geometric_eb(int id, float *pos)
+{
+ /* find the nearest point in the bounding box */
+ float *min= array_local[id].min;
+ float *max= 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 max_local_dist / (max_local_dist + len_sq);
+}
+
+#define VECCOPYMUL(v1,v2,aS) {*(v1)= *(v2)*aS; *(v1+1)= *(v2+1)*aS; *(v1+2)= *(v2+2)*aS;}
+
+/*
+ * what about intensity? which one should we use?
+ * RESOLUTION: the one of the lamp, then adjusted
+ */
+
+void lightcuts_do_lights(LightContribFunc get_contrib, ShadeInput *shi, float * diff)
+{
+ /* TODO: show that this size is always sufficient */
+ CutNode cut_nodes[LIGHTCUTS_MAX_CUT * 2];
+ int free_node= 1;
+
+ /* this heap maintaines the current cut */
+ /* TODO: its maximum size is known in advance, this allows to
+ * preallocate it and share it between subsequent executions
+ */
+ Heap *cut= BLI_heap_new();
+
+ /* this is the total radiance estimate, continuously updated */
+ float totest[3]= {0.0f, 0.0f, 0.0f};
+
+ memset(cut_nodes, 0, sizeof(cut_nodes));
+
+ {
+ CutNode *root= &cut_nodes[0];
+ LampRen *lar= array_local[root_local].lar;
+
+ root->id= root_local;
+
+ root->contr_factor= get_contrib(lar, shi);
+
+ root->contr_own[0]= lar->r * root->contr_factor;
+ root->contr_own[1]= lar->g * root->contr_factor;
+ root->contr_own[2]= lar->b * root->contr_factor;
+
+ root->contr_clus[0]= root->contr_own[0] * array_local[root_local].intensity / lar->energy;
+ root->contr_clus[1]= root->contr_own[1] * array_local[root_local].intensity / lar->energy;
+ root->contr_clus[2]= root->contr_own[2] * array_local[root_local].intensity / lar->energy;
+
+ root->error_bound= calc_geometric_eb(root_local, shi->co);
+
+ VECADD(totest, totest, root->contr_clus);
+
+ BLI_heap_insert(cut, -root->error_bound, root);
+ }
+
+ /* at each iteration the heap grows by one, but we have a maximum size */
+ while (BLI_heap_size(cut) < LIGHTCUTS_MAX_CUT && BLI_heap_size(cut) > 0) {
+ CutNode *node= BLI_heap_popmin(cut);
+ LightcutsCluster *parent= &array_local[node->id];
+
+ if (parent->child1==0 && parent->child2==0)
+ continue;
+
+ if (LC_LUMINOSITY(totest) * LIGHTCUTS_ERROR_RATE > node->error_bound * parent->intensity) {
+ break;
+ } else {
+ LightcutsCluster *rep= &array_local[parent->child1];
+ LightcutsCluster *unrep= &array_local[parent->child2];
+ CutNode *c_rep= &cut_nodes[free_node];
+ CutNode *c_unrep= &cut_nodes[free_node + 1];
+
+ free_node += 2;
+
+ if (parent->lar != rep->lar)
+ SWAP(LightcutsCluster*, rep, unrep);
+
+ /*
+ * XXX: numerically questionable
+ * but please note that it's the same quantity
+ * we are not calculating it in different ways
+ */
+ VECSUB(totest, totest, node->contr_clus);
+
+ /* this is a strong assumption on linearity of intensity contribution... is it strong indeed?
+ * and numerically questionable again */
+ /* TODO: there is room to reuse the same block here */
+
+ /* for the reprsented light we can reuse most calculations */
+ c_rep->contr_factor= node->contr_factor;
+ VECCOPY(c_rep->contr_own, node->contr_own);
+ VECCOPYMUL(c_rep->contr_clus, c_rep->contr_own, rep->intensity / rep->lar->energy);
+ c_rep->error_bound= calc_geometric_eb(rep->id, shi->co);
+ c_rep->id= rep->id;
+
+ BLI_heap_insert(cut, -c_rep->error_bound, c_rep);
+
+ VECADD(totest, totest, c_rep->contr_clus);
+
+ /* for the "unrepresented" light we have to compute stuff from scratch */
+ c_unrep->contr_factor= get_contrib(unrep->lar, shi);
+ c_unrep->contr_own[0]= unrep->lar->r * c_unrep->contr_factor;
+ c_unrep->contr_own[1]= unrep->lar->g * c_unrep->contr_factor;
+ c_unrep->contr_own[2]= unrep->lar->b * c_unrep->contr_factor;
+ c_unrep->contr_clus[0]= c_unrep->contr_own[0] * unrep->intensity / unrep->lar->energy;
+ c_unrep->contr_clus[1]= c_unrep->contr_own[1] * unrep->intensity / unrep->lar->energy;
+ c_unrep->contr_clus[2]= c_unrep->contr_own[2] * unrep->intensity / unrep->lar->energy;
+ c_unrep->error_bound= calc_geometric_eb(unrep->id, shi->co);
+ c_unrep->id= unrep->id;
+ BLI_heap_insert(cut, -c_unrep->error_bound, c_unrep);
+
+ VECADD(totest, totest, c_unrep->contr_clus);
+ }
+ }
+
+ /*
+ * here, the content of the queue IS the cut, but we already should have
+ * an updated TOTREP value (even thought numerically questionable?)
+ */
+
+ VECADD(diff, diff, totest);
+
+ BLI_heap_free(cut, 0);
+}
Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c 2008-05-26 16:19:30 UTC (rev 14983)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c 2008-05-26 17:46:35 UTC (rev 14984)
@@ -43,6 +43,7 @@
#include "DNA_material_types.h"
/* local include */
+#include "lightcuts.h"
#include "occlusion.h"
#include "renderpipeline.h"
#include "render_types.h"
@@ -1524,6 +1525,8 @@
diff[2]= R.wrld.linfac*(1.0f-exp( diff[2]*R.wrld.logfac) );
}
+static float single_light_contrib(LampRen *lar, ShadeInput *shi);
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list