[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