[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [16179] branches/soc-2008-unclezeiv/source /blender: indirect lighting, big WIP commit:
Davide Vercelli
davide.vercelli at gmail.com
Mon Aug 18 20:22:08 CEST 2008
Revision: 16179
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16179
Author: unclezeiv
Date: 2008-08-18 20:22:06 +0200 (Mon, 18 Aug 2008)
Log Message:
-----------
indirect lighting, big WIP commit:
- code to sample surface colors for indirect lights, this allows color bleeding (warning: contains ugly hacks to please/tame the internal render api)
- experimental/simplistic code to support second bounce
- toggle to render only indirect lighting (useful for testing)
please note that this code *has* a couple of known bugs
also corrected some former bugs:
- wrong random cosine weighted direction
- while copying matrices from area lights, scale should not be taken into account
Modified Paths:
--------------
branches/soc-2008-unclezeiv/source/blender/makesdna/DNA_scene_types.h
branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c
branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeinput.c
branches/soc-2008-unclezeiv/source/blender/src/buttons_scene.c
Modified: branches/soc-2008-unclezeiv/source/blender/makesdna/DNA_scene_types.h
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/makesdna/DNA_scene_types.h 2008-08-18 18:16:32 UTC (rev 16178)
+++ branches/soc-2008-unclezeiv/source/blender/makesdna/DNA_scene_types.h 2008-08-18 18:22:06 UTC (rev 16179)
@@ -319,7 +319,7 @@
short lightcuts_env_map;
short lightcuts_indirect;
float lightcuts_indir_fac;
- short lightcuts_random_dirs;
+ short lightcuts_options;
short lightcuts_color_weight;
} RenderData;
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-18 18:16:32 UTC (rev 16178)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c 2008-08-18 18:22:06 UTC (rev 16179)
@@ -73,6 +73,10 @@
#define FALLOFF_MIX 3
#define FALLOFF_SLIDER 3
+#define LC_OPT_RANDOM_DIRS 0x01
+#define LC_OPT_ONLY_INDIR 0x02
+#define LC_OPT_2ND_BOUNCE 0x04
+
/*
* This is a table to select the "worst falloff" for a cluster, given the
* falloff types of its children.
@@ -165,10 +169,13 @@
int stat_samples;
int stat_cut_size;
int stat_rays_shot;
+ int stat_discard_nohit;
+ int stat_discard_black;
+ int stat_discard_nan;
float scene_diag;
float indir_fac;
int do_indir;
- int random_dirs;
+ int options;
double start_time;
double tree_creation_time;
@@ -687,7 +694,7 @@
MEM_freeN(nearest);
}
-static void init_lamp(Render * re, LampRen * lar)
+static void lamp_init(Render * re, LampRen * lar)
{
/* float xs, ys, dist, distkw; */
/* TODO: what is xs ys ?? where are they used? */
@@ -813,17 +820,29 @@
*/
}
+static void lamp_delete(LampRen * lar)
+{
+ MEM_freeN(lar->shadsamp);
+ MEM_freeN(lar);
+}
+
static void create_lamp_oriented(Render * re, LampRen * lar, LampRen * orig)
{
- init_lamp(re, lar);
+ lamp_init(re, lar);
lar->dist= orig->dist;
lar->distkw= lar->dist * lar->dist; /* who uses this? */
lar->lay= orig->lay;
/* same as original area light */
VECCOPY(lar->vec, orig->vec);
- Mat3CpyMat3(lar->imat, orig->imat);
+
Mat3CpyMat3(lar->mat, orig->mat);
+ /* but we don't want to preserve scale */
+ Normalize(lar->mat[0]);
+ Normalize(lar->mat[1]);
+ Normalize(lar->mat[2]);
+ Mat3Inv(lar->imat, lar->mat);
+
lar->type = LA_SPOT;
}
@@ -886,7 +905,7 @@
gonew->ob= 0;
lar = (LampRen *)MEM_callocN(sizeof(LampRen), "lampren");
- init_lamp(re, lar);
+ lamp_init(re, lar);
lar->type = LA_SUN;
lar->lay= 0xffffffff; /* XXX: check */
@@ -1031,92 +1050,238 @@
dir[2]= sqrtf(1 - sin_th * sin_th);
/* uniformly weighted angle around axis Z */
- phi= BLI_frand() * M_PI;
+ phi= 2.0 * BLI_frand() * M_PI;
dir[0]= cosf(phi) * sin_th;
dir[1]= sinf(phi) * sin_th;
}
-static void add_virtual_point_light(Render * re, LightcutsData *lcd, LampRen *orig, float *col)
+/* XXX: terrible hack currently needed by get_bounce_color */
+extern struct Render R;
+
+static float get_bounce_color(LightcutsData *lcd, int obi, VlakRen *vla, float *co, LampRen *lar, float *col, short isect)
{
- GroupObject *gonew;
+ ShadeInput shitmp, *shi= &shitmp;
+ ShadeResult shr;
+ Group light_override;
+ GroupObject go;
+ float savecol[3], energy, max_col;
+ int max_idx;
+
+ /* hack: increase current color/energy in order to avoid too dark results */
+ energy= lar->energy;
+ savecol[0]= lar->r;
+ savecol[1]= lar->g;
+ savecol[2]= lar->b;
+ lar->r /= lar->energy;
+ lar->g /= lar->energy;
+ lar->b /= lar->energy;
+ lar->energy= 1.0f;
+
+ /* fake group object in order to use "light override" */
+ go.lampren= lar;
+ go.next= go.prev= 0x0;
+ light_override.gobject.first= &go;
+ light_override.gobject.last= &go;
+
+ /* long and complex shade input initialization */
+ memset(shi, 0, sizeof(ShadeInput));
+
+ /* from shade_input_initialize, but without a RenderLayer */
+ shi->sample= 0; // sample;
+ shi->thread= 0; // pa->thread;
+ shi->do_preview= 0; // R.r.scemode & R_NODE_PREVIEW;
+ shi->lay= ~0x0; // rl->lay;
+ shi->layflag= SCE_LAY_SOLID; // rl->layflag;
+ shi->passflag= SCE_PASS_RGBA | SCE_PASS_DIFFUSE; // rl->passflag;
+ shi->combinedflag= SCE_PASS_RGBA | SCE_PASS_DIFFUSE; // ~rl->pass_xor;
+ shi->mat_override= 0; // rl->mat_override;
+ shi->light_override= &light_override; // rl->light_override;
+
+ /* simplified code from shade_samples_fill_with_ps */
+ shi->obi= &R.objectinstance[obi];
+ shi->obr= shi->obi->obr;
+ shi->facenr= vla->index; // (facenr-1) & RE_QUAD_MASK;
+ if (isect==2)
+ shade_input_set_triangle_i(shi, shi->obi, vla, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, shi->obi, vla, 0, 1, 2);
+
+ shi->mask= 0x1; // curmask;
+ shi->samplenr= 0; // R.shadowsamplenr[shi->thread]++;
+
+ /*
+ * code layout taken from shade_input_set_viewco, but of course here we
+ * don't have any pixel coordinate to start from
+ */
+
+#if 0
+ {
+ float dface, v1[3], fac, div;
+
+ // calc_view_vector(shi->view, x, y); /* returns not normalized, so is in viewplane coords */
+ /* XXX: maybe this is wrong, it expects things in "camera" (thus original sample) space? */
+ VECSUB(shi->view, co, lar->co);
+
+ VECCOPY(v1, shi->v1->co);
+
+ /* ? */
+ if(shi->obi->flag & R_TRANSFORMED)
+ Mat4MulVecfl(shi->obi->mat, v1);
+
+ dface= INPR(v1, shi->facenor);
+
+ div= INPR(shi->facenor, shi->view);
+ if (div!=0.0f) fac= dface/div;
+ else fac= 0.0f;
+
+ shi->co[0]= fac*shi->view[0];
+ shi->co[1]= fac*shi->view[1];
+ shi->co[2]= fac*shi->view[2];
+
+ /* cannot normalize earlier, code above needs it at viewplane level */
+ Normalize(shi->view);
+ }
+#else
+ VECCOPY(shi->co, co);
+ VECSUB(shi->view, co, lar->co);
+ Normalize(shi->view);
+#endif
+
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+ shade_input_set_shade_texco(shi);
+
+ /* from shade_input_do_shade */
+ /* copy all relevant material vars, note, keep this synced with render_types.h */
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
+ shi->har= shi->mat->har;
+
+ /* TODO: call shade_input_do_shade directly instead if you want to support also node materials here */
+ shade_material_loop(shi, &shr);
+
+ /* now we finally obtain the shaded color */
+ VECCOPY(col, shr.col);
+
+ /* restore lar colors */
+ lar->energy= energy;
+ lar->r= savecol[0];
+ lar->g= savecol[1];
+ lar->b= savecol[2];
+
+ max_col= MAX3(shr.col[0], shr.col[1], shr.col[2]);
+
+ if (max_col==0.0f) {
+ lcd->stat_discard_black+= 10000;
+ return 0.0f;
+ }
+
+ /* code to avoid zero division and riduce numerical problems */
+ max_idx= max_col==shr.col[0] ? 0 : max_col==shr.col[1] ? 1 : 2;
+
+ return shr.diff[max_idx] / shr.col[max_idx];
+}
+
+static void add_virtual_point_light(Render * re, LightcutsData *lcd, LampRen *orig, float *col, int lev)
+{
+ GroupObject *go;
LampRen *lar;
VlakRen *vla;
Isect isec;
- float tmp[3], dist;
+ float scol[3], co[3], fac;
- isec.mode= RE_RAY_MIRROR; /* TODO: check */
+ /* first we trace a ray from the current sample to the scene */
+ isec.mode= RE_RAY_MIRROR;
isec.faceorig= NULL;
isec.oborig= 0;
VECCOPY(isec.start, orig->co);
- if (lcd->random_dirs) {
+ if (lcd->options & LC_OPT_RANDOM_DIRS)
get_cosine_weighted_random_direction(isec.vec);
- Mat3MulVecfl(orig->mat, isec.vec);
- VECNEG(isec.vec);
+ else {
+ isec.vec[0]= 0.0f;
+ isec.vec[1]= 0.0f;
+ isec.vec[2]= 1.0f;
}
- else
- VECCOPY(isec.vec, orig->vec);
+ Mat3MulVecfl(orig->mat, isec.vec);
+ VECNEG(isec.vec);
+
VECADDFAC(isec.end, isec.start, isec.vec, lcd->scene_diag);
- if (!RE_ray_tree_intersect(re->raytree, &isec))
+ if (!RE_ray_tree_intersect(re->raytree, &isec)) {
+ lcd->stat_discard_nohit++;
return;
+ }
+ /* we have a hit: place a new lamp there, with proper direction and color */
+
vla= (VlakRen*)isec.face;
+ /* XXX: avoiding self intersections with 0.01, better number required */
+ VECADDFAC(co, isec.start, isec.vec, isec.labda - 0.01);
+ fac= get_bounce_color(lcd, isec.ob, vla, co, orig, scol, isec.isect);
+
+ if (fac == 0.0f) {
+ lcd->stat_discard_black++;
+ return;
+ }
+
+#ifdef LIGHTCUTS_DEBUG
+ if (fac >= 0.499f) {
+ lcd->stat_discard_nan++;
+ return;
+ }
+#endif
+
lar= (LampRen *)MEM_callocN(sizeof(LampRen), "lampren");
- init_lamp(re, lar);
+ lamp_init(re, lar);
/* XXX: fixed distance or proportional to orig->dist? */
lar->dist= orig->dist / 2;
lar->distkw= lar->dist * lar->dist;
lar->lay= orig->lay;
+
+ /* lamp is oriented as (negated) face normal */
VECCOPY(lar->vec, vla->n);
VECNEG(lar->vec);
VECCOPY(lar->mat[2], vla->n);
VecOrthoBasisf(lar->mat[2], lar->mat[0], lar->mat[1]);
Mat3Inv(lar->imat, lar->mat);
lar->type = LA_SPOT;
-
- /* XXX: err... something better than 0.01? */
- VECADDFAC(lar->co, isec.start, isec.vec, isec.labda - 0.01);
-
- /* TODO: read color */
- lar->energy= lamp_get_visibility(orig, lar->co, tmp, &dist);
- lar->energy*= 1.0 / (lcd->indir_fac * lcd->do_indir);
- lar->r= lar->energy * col[0];// * isec.col[0];
- lar->g= lar->energy * col[1];// * isec.col[1];
- lar->b= lar->energy * col[2];// * isec.col[2];
-
-#ifdef LIGHTCUTS_DEBUG
- //printf("coordinates: %4f %4f %4f\n", lar->co[0], lar->co[1], lar->co[2]);
-#endif
-
- gonew= MEM_callocN(sizeof(GroupObject), "groupobject");
- BLI_addtail(&lcd->pointlights, gonew);
+ VECCOPY(lar->co, co);
+ lar->ray_samp_method= LA_SAMP_CONSTANT;
+
+ /* note that lamp_get_visibility is called in get_bounce_color */
+ lar->energy= fac * orig->energy * (lev + 1) * lcd->indir_fac / lcd->do_indir;
+
+ /* TODO: without proper spectrum handling, this could be too darkening */
+ scol[0]*= col[0];
+ scol[1]*= col[1];
+ scol[2]*= col[2];
+ lar->r= lar->energy * scol[0];
+ lar->g= lar->energy * scol[1];
+ lar->b= lar->energy * scol[2];
+
/* XXX: see remarks on similar code in convert_environment_map */
- gonew->ob= 0;
-
+ go= MEM_callocN(sizeof(GroupObject), "groupobject");
+ BLI_addtail(&lcd->pointlights, go);
+ go->ob= 0;
BLI_addtail(&re->lampren, lar);
- /* check deallocation */
- gonew->lampren= lar;
+ go->lampren= lar;
lcd->trees[TREE_SPOT].counter++;
lcd->light_counter++;
lcd->vpl_counter++;
- lar->ray_samp_method = LA_SAMP_CONSTANT;
+
+ if (lev > 0)
+ add_virtual_point_light(re, lcd, lar, scol, lev - 1);
}
-static float get_area_light_area(LampRen *lar)
+static float get_area_light_actual_area(LampRen *lar)
{
- float realw, realh;
-
- realw= sqrtf(VEC_LEN_SQ(lar->mat[0])) * lar->area_size;
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list