[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [15761] branches/soc-2008-unclezeiv/source /blender/render/intern/source: Added support for all diffuse shaders.

Davide Vercelli davide.vercelli at gmail.com
Fri Jul 25 18:09:36 CEST 2008


Revision: 15761
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15761
Author:   unclezeiv
Date:     2008-07-25 18:09:35 +0200 (Fri, 25 Jul 2008)

Log Message:
-----------
Added support for all diffuse shaders. This required to bound the maximum value of the shader over a cluster of lights.

Also:
- removed unused values from the OrenNayar shader
- some macros were passed a function call as a parameter, thus issuing it more than once: fixed.

Limitations:
- the Oren Nayar shader was pretty complex to bound and the resulting code looks a bit slow; there's room for optimizations though
- more testing required

Modified Paths:
--------------
    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/source/lightcuts.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c	2008-07-25 13:45:57 UTC (rev 15760)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/lightcuts.c	2008-07-25 16:09:35 UTC (rev 15761)
@@ -154,10 +154,6 @@
 
 	CutNode *cut_nodes;
 	int cut_nodes_size;
-#ifdef LIGHTCUTS_DEBUG
-	short dbg_first_pixel;
-	short dbg_jolly;
-#endif
 	int stat_samples;
 	int stat_cut_size;
 	int stat_rays_shot;
@@ -165,6 +161,9 @@
 	
 	double start_time;
 	double tree_creation_time;
+#ifdef LIGHTCUTS_DEBUG
+	int dbg_first_pixel;
+#endif
 } LightcutsData;
 
 #define VEC_LEN_SQ(v) (v[0]*v[0] + v[1]*v[1] + v[2]*v[2])
@@ -395,8 +394,10 @@
 				 * both by a linear falloff with distance = d/ld1 and by a
 				 * quadratic falloff with distance = d^2/ld2 
 				 */
+				float d1= 1.0f / lar->ld1;
+				float d2= lar->dist / lar->ld2;
 				clus->falloff_type= FALLOFF_MIX;
-				clus->falloff_dist= lar->dist * MAX2(1.0f / lar->ld1, lar->dist / lar->ld2);
+				clus->falloff_dist= lar->dist * MAX2(d1, d2);
 			}
 			break;
 		}
@@ -1089,18 +1090,145 @@
 
 float spec(float inp, int hard);
 
+float bound_OrenNayar_Diff(float max_dot, float min_dot, float *n, float *v, float *tmin, float *tmax, float rough_sq)
+{
+	float nv, t, A, B;
+	float View_B[3], lmin[3], lmax[3], mat[3][3];
+	float bound_sin_tan, x;
+	
+	if(max_dot <= 0.0f)
+		return 0.0f;
+	
+	/* Dot product between surface normal and view vector */
+	nv= INPR(n, v);
+	nv= MAX2(nv, 0.0f);
+	
+	/*
+	 * original forumla is:
+	 *     t = dot(Lit_B, View_B)
+	 * where _B vectors are normalized vectors perpendicular to the normal,
+	 * pointing towards the light and the camera respectively.
+	 *   To bound this we exploit the usual cosine bounding mechanism in
+	 * View_B's direction.  
+	 */
+	
+	/* TODO: optim: View_B and mat could be precomputed per sample */
+	VECADDFAC(View_B, v, n, -nv);
+	Normalize(View_B);
+	
+	get_axis_matrix(mat, View_B);
+	transform_aabb(mat, tmin, tmax, lmin, lmax);
+	t = compute_cosine_bound(lmin, lmax);
+	
+	/*
+	 * real formula is
+	 *     a = MAX(acos(realnl), acos(nv)), b = MIN(*)
+	 *     sin(a) * tan(b)
+	 * this is equivalent to:
+	 *     a = MAX(realnl, nv), b = MIN(*)
+	 *     sqrt(1 - a * a) * sqrt(1 - b * b) / b
+	 * which in turn is bound by:
+	 *     sqrt(1 - b * b) * sqrt(1 - b * b) / b = (1 - b * b) / b
+	 * Tighter bounds could possibly be found.
+	 */
+	x = MIN3(nv, min_dot, 0.95);
+	bound_sin_tan= 1 / x - x;
+	
+	/* TODO: optim: these values can be precomputed (also in shadeoutput.c) */
+	A = 1.0f - 0.5f * rough_sq / (rough_sq + 0.33f);
+	B = 0.45f * rough_sq / (rough_sq + 0.09f);
+	
+	return max_dot * (A + B * t * bound_sin_tan);
+}
+
+float bound_Toon_Diff(float min_ang, float size, float smooth)
+{
+	float ang = saacos( (double)(min_ang) );
+
+	if( ang < size ) return 1.0f;
+	if( ang >= (size + smooth) || smooth == 0.0f ) return 0.0f;
+	return 1.0f - ((ang - size) / smooth);
+}
+
+float bound_Minnaert_Diff(float max_dot, float *n, float *v, float darkness)
+{
+	float nv;
+	
+	if (max_dot <= 0.0f)
+		return 0.0f;
+
+	/* nv = dot product between surface normal and view vector */
+	/* TODO: optim: nv could be precomputed per sample */
+	nv = INPR(n, v);
+	nv = MAX2(nv, 0.0f);
+
+	/* The Real model */
+	if (darkness <= 1.0f)
+		return max_dot * pow(MAX2(nv * max_dot, 0.1f), darkness - 1.0f);
+	
+	/* Nvidia model */
+	return max_dot * pow(1.001f - nv, darkness - 1.0f);
+}
+
+float bound_Fresnel_Diff(float max_dot, float grad, float fac)
+{
+	float t2;
+	
+	if(fac==0.0f) return 1.0f;
+	
+	/* XXX: not sure: are negative values allowed? */
+	if(max_dot>0.0f) t2= 1.0f+max_dot;
+	else t2= 1.0f-max_dot;
+	
+	t2= grad + (1.0f-grad)*pow(t2, fac);
+	
+	return CLAMPIS(t2, 0.0f, 1.0f);
+}
+
 /* error bound: material term */
-/* TODO: currently supporting only lambertian diffuse and Phong specular */
+/* TODO: currently supporting only Phong specular */
 static float calc_material_eb(LightcutsCluster *clus, ShadeInput *shi, float tsm[3][3], float *tspos, float msm[3][3], float *mspos)
 {
-	float tmin[3], tmax[3], eb_diff, eb_spec=0.0f;
+	float tmin[3], tmax[3], eb_diff, eb_spec=0.0f, cb;
 	transform_aabb(tsm, clus->min, clus->max, tmin, tmax);
 	if (clus->type != CLUSTER_SUN) {
 		VECADD(tmin, tspos, tmin);
 		VECADD(tmax, tspos, tmax);
 	}
-	eb_diff= MAX2(compute_cosine_bound(tmin, tmax), 0.0) * shi->refl;
-	/* TODO: optimize */
+	cb= compute_cosine_bound(tmin, tmax);
+	
+	/* TODO: potentially optimizable, the shader is always the same over a sample */
+	switch(shi->mat->diff_shader) {
+	case MA_DIFF_TOON:
+		eb_diff= bound_Toon_Diff(MAX2(cb, 0.0), shi->mat->param[0], shi->mat->param[1]);
+		break;
+	case MA_DIFF_MINNAERT:
+		eb_diff= bound_Minnaert_Diff(MAX2(cb, 0.0), shi->vn, shi->view, shi->mat->darkness);
+		break;
+	case MA_DIFF_FRESNEL:
+		eb_diff= bound_Fresnel_Diff(MAX2(cb, 0.0), shi->mat->param[0], shi->mat->param[1]);
+		break;
+	case MA_DIFF_ORENNAYAR:
+		{
+			/* TODO: optim: tsmdwn is always the same over the sample */
+			float tsmdwn[3][3], tdmin[3], tdmax[3], minb;
+			VECCOPY(tsmdwn[0], tsm[1]);
+			VECCOPY(tsmdwn[1], tsm[0]);
+			VECCOPY(tsmdwn[2], tsm[2]);
+			VECNEG(tsmdwn[2]);
+			transform_aabb(tsmdwn, clus->min, clus->max, tdmin, tdmax);
+			if (clus->type != CLUSTER_SUN) {
+				VECADD(tdmin, tspos, tdmin);
+				VECADD(tdmax, tspos, tdmax);
+			}
+			minb= compute_cosine_bound(tdmin, tdmax);
+			eb_diff= bound_OrenNayar_Diff(MAX2(cb, 0.0f), MAX2(minb, 0.0f), shi->vn, shi->view, clus->min, clus->max, shi->mat->roughness * shi->mat->roughness);
+		}
+		break;
+	default:
+		eb_diff= MAX2(cb, 0.0) * shi->refl;
+	}
+	
 	if (shi->mat->spec_shader==MA_SPEC_PHONG) {
 		transform_aabb(msm, clus->min, clus->max, tmin, tmax);
 		if (clus->type != CLUSTER_SUN) {
@@ -1108,7 +1236,8 @@
 			VECADD(tmax, mspos, tmax);
 		}
 		// t= shadfac[3]*shi->spec*visifac*specfac;
-		eb_spec= spec(MAX2(compute_cosine_bound(tmin, tmax), 0.0), shi->har) * shi->spec;
+		cb= compute_cosine_bound(tmin, tmax);
+		eb_spec= spec(MAX2(cb, 0.0), shi->har) * shi->spec;
 	}
 	return eb_diff + eb_spec;
 }
@@ -1169,8 +1298,10 @@
 		
 		if (angle <= clus->cone_angle)
 			return 1.0;
-		return get_attenuation(clus, pos) * MAX2(0.0f, cosf(angle - clus->cone_angle));
 		
+		cos_t= cosf(angle - clus->cone_angle);
+		return get_attenuation(clus, pos) * MAX2(0.0f, cos_t);
+		
 		/*
 		 * TODO: possible optimizations
 		 * cos(a+b) = cos_a*cos_b - sin_a*sin_b

Modified: branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c	2008-07-25 13:45:57 UTC (rev 15760)
+++ branches/soc-2008-unclezeiv/source/blender/render/intern/source/shadeoutput.c	2008-07-25 16:09:35 UTC (rev 15761)
@@ -696,7 +696,7 @@
 }
 
 /* cartoon render diffuse */
-static float Toon_Diff( float *n, float *l, float *v, float size, float smooth )
+static float Toon_Diff( float *n, float *l, float size, float smooth )
 {
 	float rslt, ang;
 
@@ -715,23 +715,14 @@
 
 /* 'nl' is either dot product, or return value of area light */
 /* in latter case, only last multiplication uses 'nl' */
-static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough_sq )
+static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough_sq)
 {
-	float i, nh, nv, vh, realnl, h[3];
+	float i, nv, realnl;
 	float a, b, t, A, B;
 	float Lit_A, View_A, Lit_B[3], View_B[3];
 	
 	if(nl<0.0f) return 0.0f; /* value from area light */
-	
-	h[0]= v[0]+l[0];
-	h[1]= v[1]+l[1];
-	h[2]= v[2]+l[2];
-	Normalize(h);
-	
-	/* Dot product between surface normal and half-way vector */
-	nh= INPR(n, h);
-	nh= MAX2(nh, 0.0f);
-	
+		
 	/* Dot product between surface normal and view vector */
 	nv= INPR(n, v);
 	nv= MAX2(nv, 0.0f);
@@ -739,11 +730,7 @@
 	/* Dot product between surface normal and light vector */
 	realnl= INPR(n, l);
 	if(realnl<=0.0f) return 0.0f;
-	
-	/* Dot product between view vector and halfway vector */
-	vh= INPR(v, h);
-	vh= MAX2(vh, 0.0f);
-	
+		
 	Lit_A = saacos(realnl);
 	View_A = saacos( nv );
 	
@@ -1300,7 +1287,7 @@
 		
 		/* diffuse shaders (oren nayer gets inp from area light) */
 		if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness * ma->roughness);
-		else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);
+		else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, ma->param[0], ma->param[1]);
 		else if(ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness);
 		else if(ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]);
 		else is= inp;	// Lambert
@@ -1924,7 +1911,7 @@
 #ifdef LC_LATER /* we start by supporting only lambert */
 		/* diffuse shaders (oren nayer gets inp from area light) */
 		if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness * ma->roughness);
-		else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);
+		else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, ma->param[0], ma->param[1]);
 		else if(ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness);
 		else if(ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]);
 		else is= inp;	// Lambert
@@ -2099,10 +2086,11 @@
 {
 	Material *ma= shi->mat;
 	float lv[3], lampdist, shadfac[4];
-	float i, is, i_noshad, inp, *vn;
+	float i, is, i_noshad, inp, *vn, *view, phongcorr=1.0f;
 	float visifac;
 	
 	vn= shi->vn;
+	view= shi->view;
 	
 	*pi= *pi_noshad= *pt= 0.0f;
 	
@@ -2116,8 +2104,33 @@
 
 	/* dot product and reflectivity */
 	/* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */
-	i= is= inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
+	inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
 	
+	/* diffuse shaders */
+	if(lar->mode & LA_NO_DIFF) {
+		is= 0.0f;	// skip shaders
+	}
+#ifdef LC_USELESS
+	else if(lar->type==LA_HEMI) {
+		is= 0.5f*inp + 0.5f;
+	}
+#endif
+	else {
+#ifdef LC_USELESS /* we convert area lights in pointlights */
+		if(lar->type==LA_AREA)
+			inp= area_lamp_energy_multisample(lar, shi->co, vn);
+#endif
+

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list