[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