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. @@

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

Reply via email to