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

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

Reply via email to