[Bf-blender-cvs] [ad26407] master: Cycles: Implement approximate reflectance profiles

Sergey Sharybin noreply at git.blender.org
Thu Feb 4 09:27:57 CET 2016


Commit: ad26407b525c15595694aab49c0a7f1669886fc8
Author: Sergey Sharybin
Date:   Thu Feb 4 03:34:49 2016 +0500
Branches: master
https://developer.blender.org/rBad26407b525c15595694aab49c0a7f1669886fc8

Cycles: Implement approximate reflectance profiles

Using this paper:

  http://graphics.pixar.com/library/ApproxBSSRDF/paper.pdf

This model gives less blurry results than the Cubic and Gaussian
we had implemented:

- Cubic: https://developer.blender.org/F279670
- Burley: https://developer.blender.org/F279671

The model is called "Christensen-Burley" in the interface, which
actually should be read as "Physically based" or "Realistic".

Reviewers: juicyfruit, dingto, lukasstockner97, brecht

Reviewed By: brecht, dingto

Subscribers: robocyte

Differential Revision: https://developer.blender.org/D1759

===================================================================

M	intern/cycles/app/cycles_xml.cpp
M	intern/cycles/blender/blender_shader.cpp
M	intern/cycles/kernel/closure/bssrdf.h
M	intern/cycles/kernel/osl/osl_bssrdf.cpp
M	intern/cycles/kernel/osl/osl_bssrdf.h
M	intern/cycles/kernel/osl/osl_closures.cpp
M	intern/cycles/kernel/osl/osl_closures.h
M	intern/cycles/kernel/osl/osl_shader.cpp
M	intern/cycles/kernel/shaders/node_subsurface_scattering.osl
M	intern/cycles/kernel/shaders/stdosl.h
M	intern/cycles/kernel/svm/svm_closure.h
M	intern/cycles/kernel/svm/svm_types.h
M	intern/cycles/render/nodes.cpp
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/makesrna/intern/rna_nodetree.c

===================================================================

diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index b366e93..dd1dae1 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -596,8 +596,10 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
 			xml_read_string(&falloff, node, "falloff");
 			if(falloff == "cubic")
 				sss->closure = CLOSURE_BSSRDF_CUBIC_ID;
-			else
+			else if(falloff == "gaussian")
 				sss->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
+			else /*if(falloff == "burley")*/
+				sss->closure = CLOSURE_BSSRDF_BURLEY_ID;
 
 			snode = sss;
 		}
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 8870507..a40eaf5 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -405,6 +405,9 @@ static ShaderNode *add_node(Scene *scene,
 			case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
 				subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
 				break;
+			case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
+				subsurface->closure = CLOSURE_BSSRDF_BURLEY_ID;
+				break;
 		}
 
 		node = subsurface;
diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h
index b986ab6..041832e 100644
--- a/intern/cycles/kernel/closure/bssrdf.h
+++ b/intern/cycles/kernel/closure/bssrdf.h
@@ -192,6 +192,110 @@ ccl_device void bssrdf_cubic_sample(ShaderClosure *sc, float xi, float *r, float
 	*h = sqrtf(Rm*Rm - r_*r_);
 }
 
+/* Approximate Reflectance Profiles
+ * http://graphics.pixar.com/library/ApproxBSSRDF/paper.pdf
+ */
+
+ccl_device_inline float bssrdf_burley_fitting(float A)
+{
+	/* Diffuse surface transmission, equation (6). */
+	return 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
+}
+
+/* Scale mean free path length so it gives similar looking result
+ * to Cubic and Gaussian models.
+ */
+ccl_device_inline float bssrdf_burley_compatible_mfp(float r)
+{
+	return 0.5f * M_1_PI_F * r;
+}
+
+ccl_device float bssrdf_burley_eval(ShaderClosure *sc, float r)
+{
+	/* Mean free path length. */
+	const float l = bssrdf_burley_compatible_mfp(sc->data0);
+	/* Surface albedo. */
+	const float A = sc->data2;
+	const float s = bssrdf_burley_fitting(A);
+	/* Burley refletance profile, equation (3).
+	 *
+	 * Note that surface albedo is already included into sc->weight, no need to
+	 * multiply by this term here.
+	 */
+	float exp_r_3_d = expf(-s*r / (3.0f * l));
+	float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
+	return s * (exp_r_d + exp_r_3_d) / (8*M_PI_F*l*r);
+}
+
+ccl_device float bssrdf_burley_pdf(ShaderClosure *sc, float r)
+{
+	return bssrdf_burley_eval(sc, r);
+}
+
+/* Find the radius for desired CDF value.
+ * Returns scaled radius, meaning the result is to be scaled up by d.
+ * Since there's no closed form solution we do Newton-Raphson method to find it.
+ */
+ccl_device float bssrdf_burley_root_find(float xi)
+{
+	const float tolerance = 1e-6f;
+	const int max_iteration_count = 10;
+	/* Do initial guess based on manual curve fitting, this allows us to reduce
+	 * number of iterations to maximum 4 across the [0..1] range. We keep maximum
+	 * number of iteration higher just to be sure we didn't miss root in some
+	 * corner case.
+	 */
+	float r;
+	if (xi <= 0.9f) {
+		r = expf(xi * xi * 2.4f) - 1.0f;
+	}
+	else {
+		float a = expf(xi * xi * 4.0f) - 1.0f;
+		r = a*a;
+	}
+	/* Solve against scaled radius. */
+	for(int i = 0; i < max_iteration_count; i++) {
+		float exp_r_3 = expf(-r / 3.0f);
+		float exp_r = exp_r_3 * exp_r_3 * exp_r_3;
+		float f = 1.0f - 0.25f * exp_r - 0.75f * exp_r_3 - xi;
+		float f_ = 0.25f * exp_r + 0.25f * exp_r_3;
+
+		if(fabsf(f) < tolerance || f_ == 0.0f) {
+			break;
+		}
+
+		r = r - f/f_;
+		if(r < 0.0f) {
+			r = 0.0f;
+		}
+	}
+	return r;
+}
+
+ccl_device void bssrdf_burley_sample(ShaderClosure *sc,
+                                     float xi,
+                                     float *r,
+                                     float *h)
+{
+	/* Mean free path length. */
+	const float l = bssrdf_burley_compatible_mfp(sc->data0);
+	/* Surface albedo. */
+	const float A = sc->data2;
+	const float s = bssrdf_burley_fitting(A);
+	const float d = l / s;
+	/* This is a bit arbitrary, just need big enough radius so it matches
+	 * the mean free length, but still not too big so sampling is still
+	 * effective. Might need some further tweaks.
+	 */
+	const float Rm = 10.0f*d;
+	const float r_ = bssrdf_burley_root_find(xi) * d;
+
+	*r = r_;
+
+	/* h^2 + r^2 = Rm^2 */
+	*h = sqrtf(Rm*Rm - r_*r_);
+}
+
 /* None BSSRDF falloff
  *
  * Samples distributed over disk with no falloff, for reference. */
@@ -230,16 +334,20 @@ ccl_device void bssrdf_sample(ShaderClosure *sc, float xi, float *r, float *h)
 {
 	if(sc->type == CLOSURE_BSSRDF_CUBIC_ID)
 		bssrdf_cubic_sample(sc, xi, r, h);
-	else
+	else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID)
 		bssrdf_gaussian_sample(sc, xi, r, h);
+	else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID)*/
+		bssrdf_burley_sample(sc, xi, r, h);
 }
 
 ccl_device float bssrdf_pdf(ShaderClosure *sc, float r)
 {
 	if(sc->type == CLOSURE_BSSRDF_CUBIC_ID)
 		return bssrdf_cubic_pdf(sc, r);
-	else
+	else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID)
 		return bssrdf_gaussian_pdf(sc, r);
+	else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID)*/
+		return bssrdf_burley_pdf(sc, r);
 }
 
 CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp
index 7f286c7..da4afb1 100644
--- a/intern/cycles/kernel/osl/osl_bssrdf.cpp
+++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp
@@ -105,5 +105,34 @@ ClosureParam *closure_bssrdf_gaussian_params()
 
 CCLOSURE_PREPARE(closure_bssrdf_gaussian_prepare, GaussianBSSRDFClosure)
 
+/* Burley */
+
+class BurleyBSSRDFClosure : public CBSSRDFClosure {
+public:
+	BurleyBSSRDFClosure()
+	{}
+
+	void setup()
+	{
+		sc.type = CLOSURE_BSSRDF_BURLEY_ID;
+		sc.data0 = fabsf(average(radius));
+	}
+};
+
+ClosureParam *closure_bssrdf_burley_params()
+{
+	static ClosureParam params[] = {
+		CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, sc.N),
+		CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, radius),
+		CLOSURE_FLOAT_PARAM(BurleyBSSRDFClosure, sc.data1),
+		CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, albedo),
+		CLOSURE_STRING_KEYPARAM(BurleyBSSRDFClosure, label, "label"),
+		CLOSURE_FINISH_PARAM(BurleyBSSRDFClosure)
+	};
+	return params;
+}
+
+CCLOSURE_PREPARE(closure_bssrdf_burley_prepare, BurleyBSSRDFClosure)
+
 CCL_NAMESPACE_END
 
diff --git a/intern/cycles/kernel/osl/osl_bssrdf.h b/intern/cycles/kernel/osl/osl_bssrdf.h
index 6aee2c2..d81ecad 100644
--- a/intern/cycles/kernel/osl/osl_bssrdf.h
+++ b/intern/cycles/kernel/osl/osl_bssrdf.h
@@ -49,6 +49,7 @@ class CBSSRDFClosure : public CClosurePrimitive {
 public:
 	ShaderClosure sc;
 	float3 radius;
+	float3 albedo;
 
 	CBSSRDFClosure() : CClosurePrimitive(BSSRDF) { }
 	int scattering() const { return LABEL_DIFFUSE; }
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index 461ce8f..95b8cea 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -236,6 +236,8 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
 		closure_bssrdf_cubic_params(), closure_bssrdf_cubic_prepare);
 	register_closure(ss, "bssrdf_gaussian", id++,
 		closure_bssrdf_gaussian_params(), closure_bssrdf_gaussian_prepare);
+	register_closure(ss, "bssrdf_burley", id++,
+		closure_bssrdf_burley_params(), closure_bssrdf_burley_prepare);
 
 	register_closure(ss, "hair_reflection", id++,
 		bsdf_hair_reflection_params(), bsdf_hair_reflection_prepare);
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
index d8a3f77..526c035 100644
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -50,6 +50,7 @@ OSL::ClosureParam *closure_bsdf_diffuse_ramp_params();
 OSL::ClosureParam *closure_bsdf_phong_ramp_params();
 OSL::ClosureParam *closure_bssrdf_cubic_params();
 OSL::ClosureParam *closure_bssrdf_gaussian_params();
+OSL::ClosureParam *closure_bssrdf_burley_params();
 OSL::ClosureParam *closure_henyey_greenstein_volume_params();
 
 void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
@@ -60,6 +61,7 @@ void closure_bsdf_diffuse_ramp_prepare(OSL::RendererServices *, int id, void *da
 void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data);
 void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data);
 void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data);
 void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data);
 
 #define CCLOSURE_PREPARE(name, classname)          \
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 8f459c8..8acc042 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -281,11 +281,17 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
 							if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
 								bssrdf->radius = make_float3(0.0f, 0.0f, 0.0f);
 
+							float3 albedo =
+							        (bssrdf->sc.type == CLOSURE_BSSRDF_BURLEY_ID)
+							                ? bssrdf->albedo
+							                : make_float3(0.0f, 0.0f, 0.0f);
+
 							/* create one closure for each color channel */
 							if(fabsf(weight.x) > 0.0f) {
 								sc.weight = make_float3(weight.x, 0.0f, 0.0f);
 								sc.data0 = bssrdf->radius.x;
 								sc.data1 = 0.0f;
+								sc.data2 = albedo.x;
 								sd->flag |= bssrdf_setup(&sc, sc.type);
 								sd->closure[sd->num_closure++] = sc;
 							}
@@ -294,6 +300,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
 								sc.weight = make_float3(0.0f, weight.y, 0.0f);
 								sc.data0 = bssrdf->radius.y;
 								sc.data1 = 0.0f;
+								sc.data2 = albedo.y;
 								sd->flag |= bssrdf_setup(&sc, sc.type);
 								sd->closure[sd->num_closure++] = sc;
 							}
@@ -302,6 +309,7 @@ static void flatten_s

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list