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
