diff options
Diffstat (limited to 'intern')
22 files changed, 1632 insertions, 37 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 3f04f11aab4..bdbab1006c0 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -521,6 +521,19 @@ static ShaderNode *add_node(Scene *scene, } node = hair; } + else if(b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) { + BL::ShaderNodeBsdfPrincipled b_principled_node(b_node); + PrincipledBsdfNode *principled = new PrincipledBsdfNode(); + switch (b_principled_node.distribution()) { + case BL::ShaderNodeBsdfPrincipled::distribution_GGX: + principled->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; + break; + case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX: + principled->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + break; + } + node = principled; + } else if(b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) { node = new TranslucentBsdfNode(); } diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index dbc2ba2503a..c3772dfa2d8 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -120,6 +120,8 @@ set(SRC_CLOSURE_HEADERS closure/bssrdf.h closure/emissive.h closure/volume.h + closure/bsdf_principled_diffuse.h + closure/bsdf_principled_sheen.h ) set(SRC_SVM_HEADERS diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index 9139b99353a..0302fa9b43e 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -27,6 +27,8 @@ #include "kernel/closure/bsdf_ashikhmin_shirley.h" #include "kernel/closure/bsdf_toon.h" #include "kernel/closure/bsdf_hair.h" +#include "kernel/closure/bsdf_principled_diffuse.h" +#include "kernel/closure/bsdf_principled_sheen.h" #ifdef __SUBSURFACE__ # include "kernel/closure/bssrdf.h" #endif @@ -86,16 +88,21 @@ ccl_device_forceinline int bsdf_sample(KernelGlobals *kg, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: label = bsdf_microfacet_ggx_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: label = bsdf_microfacet_multi_ggx_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &sd->lcg_state); break; case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &sd->lcg_state); break; @@ -130,6 +137,15 @@ ccl_device_forceinline int bsdf_sample(KernelGlobals *kg, label = bsdf_hair_transmission_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; + case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: + case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID: + label = bsdf_principled_diffuse_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: + label = bsdf_principled_sheen_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; #endif #ifdef __VOLUME__ case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID: @@ -188,14 +204,19 @@ float3 bsdf_eval(KernelGlobals *kg, eval = bsdf_transparent_eval_reflect(sc, sd->I, omega_in, pdf); break; case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_reflect(sc, sd->I, omega_in, pdf); break; case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, sd->I, omega_in, pdf, &sd->lcg_state); break; case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, sd->I, omega_in, pdf, &sd->lcg_state); break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: @@ -222,6 +243,13 @@ float3 bsdf_eval(KernelGlobals *kg, case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: eval = bsdf_hair_transmission_eval_reflect(sc, sd->I, omega_in, pdf); break; + case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: + case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID: + eval = bsdf_principled_diffuse_eval_reflect(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: + eval = bsdf_principled_sheen_eval_reflect(sc, sd->I, omega_in, pdf); + break; #endif #ifdef __VOLUME__ case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID: @@ -256,14 +284,19 @@ float3 bsdf_eval(KernelGlobals *kg, eval = bsdf_transparent_eval_transmit(sc, sd->I, omega_in, pdf); break; case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_transmit(sc, sd->I, omega_in, pdf); break; case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, sd->I, omega_in, pdf, &sd->lcg_state); break; case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, sd->I, omega_in, pdf, &sd->lcg_state); break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: @@ -290,6 +323,13 @@ float3 bsdf_eval(KernelGlobals *kg, case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: eval = bsdf_hair_transmission_eval_transmit(sc, sd->I, omega_in, pdf); break; + case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: + case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID: + eval = bsdf_principled_diffuse_eval_transmit(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: + eval = bsdf_principled_sheen_eval_transmit(sc, sd->I, omega_in, pdf); + break; #endif #ifdef __VOLUME__ case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID: @@ -311,11 +351,16 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness) #ifdef __SVM__ switch(sc->type) { case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: bsdf_microfacet_multi_ggx_blur(sc, roughness); break; case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: bsdf_microfacet_ggx_blur(sc, roughness); break; @@ -349,10 +394,15 @@ ccl_device bool bsdf_merge(ShaderClosure *a, ShaderClosure *b) case CLOSURE_BSDF_REFLECTION_ID: case CLOSURE_BSDF_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 1c7b3eb9ddd..58f6140970d 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -36,7 +36,8 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct MicrofacetExtra { - float3 color; + float3 color, cspec0; + float clearcoat; } MicrofacetExtra; typedef ccl_addr_space struct MicrofacetBsdf { @@ -233,6 +234,36 @@ ccl_device_forceinline float3 microfacet_sample_stretched( return normalize(make_float3(-slope_x, -slope_y, 1.0f)); } +/* Calculate the reflection color + * + * If fresnel is used, the color is an interpolation of the F0 color and white + * with respect to the fresnel + * + * Else it is simply white + */ +ccl_device_forceinline float3 reflection_color(const MicrofacetBsdf *bsdf, float3 L, float3 H) { + float3 F = make_float3(1.0f, 1.0f, 1.0f); + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID + || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID + || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID); + + if(use_fresnel) { + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + + F = interpolate_fresnel_color(L, H, bsdf->ior, F0, bsdf->extra->cspec0); + } + + return F; +} + +ccl_device_forceinline float D_GTR1(float NdotH, float alpha) +{ + if (alpha >= 1.0f) return M_1_PI_F; + float alpha2 = alpha*alpha; + float t = 1.0f + (alpha2 - 1.0f) * NdotH*NdotH; + return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); +} + /* GGX microfacet with Smith shadow-masking from: * * Microfacet Models for Refraction through Rough Surfaces @@ -248,14 +279,44 @@ ccl_device_forceinline float3 microfacet_sample_stretched( ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf) { + bsdf->extra = NULL; + bsdf->alpha_x = saturate(bsdf->alpha_x); bsdf->alpha_y = bsdf->alpha_x; - + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } +ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf) +{ + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; + + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL; +} + +ccl_device int bsdf_microfacet_ggx_clearcoat_setup(MicrofacetBsdf *bsdf) +{ + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; + + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL; +} + ccl_device bool bsdf_microfacet_merge(const ShaderClosure *a, const ShaderClosure *b) { const MicrofacetBsdf *bsdf_a = (const MicrofacetBsdf*)a; @@ -273,16 +334,34 @@ ccl_device bool bsdf_microfacet_merge(const ShaderClosure *a, const ShaderClosur ccl_device int bsdf_microfacet_ggx_aniso_setup(MicrofacetBsdf *bsdf) { + bsdf->extra = NULL; + bsdf->alpha_x = saturate(bsdf->alpha_x); bsdf->alpha_y = saturate(bsdf->alpha_y); - + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } +ccl_device int bsdf_microfacet_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf) +{ + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = saturate(bsdf->alpha_y); + + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL; +} + ccl_device int bsdf_microfacet_ggx_refraction_setup(MicrofacetBsdf *bsdf) { + bsdf->extra = NULL; + bsdf->alpha_x = saturate(bsdf->alpha_x); bsdf->alpha_y = bsdf->alpha_x; @@ -319,6 +398,8 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons float alpha2 = alpha_x * alpha_y; float D, G1o, G1i; + bool is_principled_clearcoat = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID); + if(alpha_x == alpha_y) { /* isotropic * eq. 20: (F*G*D)/(4*in*on) @@ -327,7 +408,18 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons float cosThetaM2 = cosThetaM * cosThetaM; float cosThetaM4 = cosThetaM2 * cosThetaM2; float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; - D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + + if(is_principled_clearcoat) { + /* use GTR1 for clearcoat */ + D = D_GTR1(cosThetaM, bsdf->alpha_x); + + /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ + alpha2 = 0.0625f; + } + else { + /* use GTR2 otherwise */ + D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + } /* eq. 34: now calculate G1(i,m) and G1(o,m) */ G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); @@ -374,7 +466,13 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons /* eq. 20 */ float common = D * 0.25f / cosNO; - float out = G * common; + + float3 F = reflection_color(bsdf, omega_in, m); + if(is_principled_clearcoat) { + F *= 0.25f * bsdf->extra->clearcoat; + } + + float3 out = F * G * common; /* eq. 2 in distribution of visible normals sampling * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ @@ -384,7 +482,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons * pdf = pm * 0.25 / dot(m, I); */ *pdf = G1o * common; - return make_float3(out, out, out); + return out; } return make_float3(0.0f, 0.0f, 0.0f); @@ -489,6 +587,17 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID + || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID + || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID); + + /* if fresnel is used, calculate the color with reflection_color(...) */ + if(use_fresnel) { + *pdf = 1.0f; + *eval = reflection_color(bsdf, *omega_in, m); + } + label = LABEL_REFLECT | LABEL_SINGULAR; } else { @@ -497,16 +606,32 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure float alpha2 = alpha_x * alpha_y; float D, G1i; + bool is_principled_clearcoat = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID); + if(alpha_x == alpha_y) { /* isotropic */ float cosThetaM2 = cosThetaM * cosThetaM; float cosThetaM4 = cosThetaM2 * cosThetaM2; float tanThetaM2 = 1/(cosThetaM2) - 1; - D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); /* eval BRDF*cosNI */ float cosNI = dot(N, *omega_in); + if(is_principled_clearcoat) { + /* use GTR1 for clearcoat */ + D = D_GTR1(cosThetaM, bsdf->alpha_x); + + /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ + alpha2 = 0.0625f; + + /* recalculate G1o */ + G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + } + else { + /* use GTR2 otherwise */ + D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + } + /* eq. 34: now calculate G1(i,m) */ G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); } @@ -538,10 +663,14 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure /* see eval function for derivation */ float common = (G1o * D) * 0.25f / cosNO; - float out = G1i * common; *pdf = common; - *eval = make_float3(out, out, out); + float3 F = reflection_color(bsdf, *omega_in, m); + if(is_principled_clearcoat) { + F *= 0.25f * bsdf->extra->clearcoat; + } + + *eval = G1i * common * F; } #ifdef __RAY_DIFFERENTIALS__ diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h index 7d87727004f..57f1e733ee7 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -345,8 +345,9 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf) bsdf->extra->color.x = saturate(bsdf->extra->color.x); bsdf->extra->color.y = saturate(bsdf->extra->color.y); bsdf->extra->color.z = saturate(bsdf->extra->color.z); - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; } @@ -356,6 +357,18 @@ ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(MicrofacetBsdf *bsdf) if(is_zero(bsdf->T)) bsdf->T = make_float3(1.0f, 0.0f, 0.0f); + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + + return bsdf_microfacet_multi_ggx_common_setup(bsdf); +} + +ccl_device int bsdf_microfacet_multi_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf) +{ + if(is_zero(bsdf->T)) + bsdf->T = make_float3(1.0f, 0.0f, 0.0f); + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } @@ -363,6 +376,26 @@ ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf) { bsdf->alpha_y = bsdf->alpha_x; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + + return bsdf_microfacet_multi_ggx_common_setup(bsdf); +} + +ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(MicrofacetBsdf *bsdf) +{ + bsdf->alpha_y = bsdf->alpha_x; + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; + + return bsdf_microfacet_multi_ggx_common_setup(bsdf); +} + +ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(MicrofacetBsdf *bsdf) +{ + bsdf->alpha_y = bsdf->alpha_x; + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } @@ -378,6 +411,8 @@ ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc return make_float3(0.0f, 0.0f, 0.0f); } + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); + bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); float3 X, Y, Z; Z = bsdf->N; @@ -393,7 +428,7 @@ ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); else *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); - return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL); + return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL, bsdf->ior, use_fresnel, bsdf->extra->cspec0); } ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) @@ -410,6 +445,8 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC return LABEL_REFLECT|LABEL_SINGULAR; } + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); + bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); if(is_aniso) make_orthonormals_tangent(Z, bsdf->T, &X, &Y); @@ -419,7 +456,7 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); float3 localO; - *eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL); + *eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL, bsdf->ior, use_fresnel, bsdf->extra->cspec0); if(is_aniso) *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); else @@ -450,6 +487,23 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf) return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; } +ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsdf) +{ + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = bsdf->alpha_x; + bsdf->ior = max(0.0f, bsdf->ior); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; +} + ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; @@ -465,7 +519,7 @@ ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClos float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - return mf_eval_glass(localI, localO, false, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior); + return mf_eval_glass(localI, localO, false, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, false, bsdf->extra->color); } ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { @@ -475,6 +529,8 @@ ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosu return make_float3(0.0f, 0.0f, 0.0f); } + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); + float3 X, Y, Z; Z = bsdf->N; make_orthonormals(Z, &X, &Y); @@ -483,7 +539,7 @@ ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosu float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - return mf_eval_glass(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior); + return mf_eval_glass(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); } ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) @@ -525,12 +581,14 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const S } } + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); + make_orthonormals(Z, &X, &Y); float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); float3 localO; - *eval = mf_sample_glass(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior); + *eval = mf_sample_glass(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); *eval *= *pdf; diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h index 8054fa8e849..16d900088cb 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h @@ -35,8 +35,13 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( ccl_addr_space uint *lcg_state #ifdef MF_MULTI_GLASS , const float eta + , bool use_fresnel + , const float3 cspec0 #elif defined(MF_MULTI_GLOSSY) - , float3 *n, float3 *k + , float3 *n, float3 *k + , const float eta + , bool use_fresnel + , const float3 cspec0 #endif ) { @@ -71,12 +76,20 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( /* Analytically compute single scattering for lower noise. */ float3 eval; + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); #ifdef MF_MULTI_GLASS eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta); if(wo_outside) eval *= -lambda_r / (shadowing_lambda - lambda_r); else eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f); + + float F0 = fresnel_dielectric_cos(1.0f, eta); + if(use_fresnel) { + throughput = interpolate_fresnel_color(wi, normalize(wi + wo), eta, F0, cspec0); + + eval *= throughput; + } #elif defined(MF_MULTI_DIFFUSE) /* Diffuse has no special closed form for the single scattering bounce */ eval = make_float3(0.0f, 0.0f, 0.0f); @@ -94,6 +107,13 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( else { eval = make_float3(val, val, val); } + + float F0 = fresnel_dielectric_cos(1.0f, eta); + if(use_fresnel) { + throughput = interpolate_fresnel_color(wi, wh, eta, F0, cspec0); + + eval = throughput * val; + } #endif float3 wr = -wi; @@ -101,7 +121,6 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( float C1_r = 1.0f; float G1_r = 0.0f; bool outside = true; - float3 throughput = make_float3(1.0f, 1.0f, 1.0f); for(int order = 0; order < 10; order++) { /* Sample microfacet height and normal */ @@ -117,6 +136,18 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm); } #endif +#ifdef MF_MULTI_GLASS + if(order == 0 && use_fresnel) { + /* Evaluate amount of scattering towards wo on this microfacet. */ + float3 phase; + if(outside) + phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); + else + phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta); + + eval = throughput * phase * mf_G1(wo_outside ? wo : -wo, mf_C1((outside == wo_outside) ? hr : -hr), shadowing_lambda); + } +#endif if(order > 0) { /* Evaluate amount of scattering towards wo on this microfacet. */ float3 phase; @@ -136,23 +167,39 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( /* Bounce from the microfacet. */ #ifdef MF_MULTI_GLASS bool next_outside; + float3 wi_prev = -wr; wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); if(!next_outside) { outside = !outside; wr = -wr; hr = -hr; } + + if(use_fresnel && !next_outside) { + throughput *= color; + } + else if(use_fresnel && order > 0) { + throughput *= interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0); + } #elif defined(MF_MULTI_DIFFUSE) wr = mf_sample_phase_diffuse(wm, lcg_step_float_addrspace(lcg_state), lcg_step_float_addrspace(lcg_state)); #else /* MF_MULTI_GLOSSY */ + if(use_fresnel && order > 0) { + throughput *= interpolate_fresnel_color(-wr, wm, eta, F0, cspec0); + } wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); #endif lambda_r = mf_lambda(wr, alpha); +#if defined(MF_MULTI_GLOSSY) || defined(MF_MULTI_GLASS) + if(!use_fresnel) + throughput *= color; +#else throughput *= color; +#endif C1_r = mf_C1(hr); G1_r = mf_G1(wr, C1_r, lambda_r); @@ -171,8 +218,13 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state #ifdef MF_MULTI_GLASS , const float eta + , bool use_fresnel + , const float3 cspec0 #elif defined(MF_MULTI_GLOSSY) , float3 *n, float3 *k + , const float eta + , bool use_fresnel + , const float3 cspec0 #endif ) { @@ -185,6 +237,17 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 float C1_r = 1.0f; float G1_r = 0.0f; bool outside = true; +#ifdef MF_MULTI_GLASS + float F0 = fresnel_dielectric_cos(1.0f, eta); + if(use_fresnel) { + throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0); + } +#elif defined(MF_MULTI_GLOSSY) + float F0 = fresnel_dielectric_cos(1.0f, eta); + if(use_fresnel) { + throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0); + } +#endif int order; for(order = 0; order < 10; order++) { @@ -199,23 +262,51 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 lcg_step_float_addrspace(lcg_state))); /* First-bounce color is already accounted for in mix weight. */ +#if defined(MF_MULTI_GLASS) || defined(MF_MULTI_GLOSSY) + if(!use_fresnel && order > 0) + throughput *= color; +#else if(order > 0) throughput *= color; +#endif /* Bounce from the microfacet. */ #ifdef MF_MULTI_GLASS bool next_outside; + float3 wi_prev = -wr; wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); if(!next_outside) { hr = -hr; wr = -wr; outside = !outside; } + + if(use_fresnel) { + if(!next_outside) { + throughput *= color; + } + else { + float3 t_color = interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0); + + if(order == 0) + throughput = t_color; + else + throughput *= t_color; + } + } #elif defined(MF_MULTI_DIFFUSE) wr = mf_sample_phase_diffuse(wm, lcg_step_float_addrspace(lcg_state), lcg_step_float_addrspace(lcg_state)); #else /* MF_MULTI_GLOSSY */ + if(use_fresnel) { + float3 t_color = interpolate_fresnel_color(-wr, wm, eta, F0, cspec0); + + if(order == 0) + throughput = t_color; + else + throughput *= t_color; + } wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); #endif diff --git a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h new file mode 100644 index 00000000000..8a116693bdb --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h @@ -0,0 +1,120 @@ +/* + * Copyright 2011-2017 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BSDF_PRINCIPLED_DIFFUSE_H__ +#define __BSDF_PRINCIPLED_DIFFUSE_H__ + +/* DISNEY PRINCIPLED DIFFUSE BRDF + * + * Shading model by Brent Burley (Disney): "Physically Based Shading at Disney" (2012) + */ + +CCL_NAMESPACE_BEGIN + +typedef ccl_addr_space struct PrincipledDiffuseBsdf { + SHADER_CLOSURE_BASE; + + float roughness; + float3 N; +} PrincipledDiffuseBsdf; + +ccl_device float3 calculate_principled_diffuse_brdf(const PrincipledDiffuseBsdf *bsdf, + float3 N, float3 V, float3 L, float3 H, float *pdf) +{ + float NdotL = max(dot(N, L), 0.0f); + float NdotV = max(dot(N, V), 0.0f); + + if(NdotL < 0 || NdotV < 0) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + float LdotH = dot(L, H); + + float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV); + const float Fd90 = 0.5f + 2.0f * LdotH*LdotH * bsdf->roughness; + float Fd = (1.0f * (1.0f - FL) + Fd90 * FL) * (1.0f * (1.0f - FV) + Fd90 * FV); + + float value = M_1_PI_F * NdotL * Fd; + + return make_float3(value, value, value); +} + +ccl_device int bsdf_principled_diffuse_setup(PrincipledDiffuseBsdf *bsdf) +{ + bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID; + return SD_BSDF|SD_BSDF_HAS_EVAL; +} + +ccl_device float3 bsdf_principled_diffuse_eval_reflect(const ShaderClosure *sc, const float3 I, + const float3 omega_in, float *pdf) +{ + const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; + + float3 N = bsdf->N; + float3 V = I; // outgoing + float3 L = omega_in; // incoming + float3 H = normalize(L + V); + + if(dot(N, omega_in) > 0.0f) { + *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; + return calculate_principled_diffuse_brdf(bsdf, N, V, L, H, pdf); + } + else { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +ccl_device float3 bsdf_principled_diffuse_eval_transmit(const ShaderClosure *sc, const float3 I, + const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device int bsdf_principled_diffuse_sample(const ShaderClosure *sc, + float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, + float3 *eval, float3 *omega_in, float3 *domega_in_dx, + float3 *domega_in_dy, float *pdf) +{ + const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; + + float3 N = bsdf->N; + + sample_cos_hemisphere(N, randu, randv, omega_in, pdf); + + if(dot(Ng, *omega_in) > 0) { + float3 H = normalize(I + *omega_in); + + *eval = calculate_principled_diffuse_brdf(bsdf, N, I, *omega_in, H, pdf); + +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); + *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); +#endif + } + else { + *pdf = 0.0f; + } + return LABEL_REFLECT|LABEL_DIFFUSE; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_PRINCIPLED_DIFFUSE_H__ */ + + diff --git a/intern/cycles/kernel/closure/bsdf_principled_sheen.h b/intern/cycles/kernel/closure/bsdf_principled_sheen.h new file mode 100644 index 00000000000..58df4f7ddbb --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_principled_sheen.h @@ -0,0 +1,114 @@ +/* + * Copyright 2011-2017 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BSDF_PRINCIPLED_SHEEN_H__ +#define __BSDF_PRINCIPLED_SHEEN_H__ + +/* DISNEY PRINCIPLED SHEEN BRDF + * + * Shading model by Brent Burley (Disney): "Physically Based Shading at Disney" (2012) + */ + +CCL_NAMESPACE_BEGIN + +typedef ccl_addr_space struct PrincipledSheenBsdf { + SHADER_CLOSURE_BASE; + float3 N; +} PrincipledSheenBsdf; + +ccl_device float3 calculate_principled_sheen_brdf(const PrincipledSheenBsdf *bsdf, + float3 N, float3 V, float3 L, float3 H, float *pdf) +{ + float NdotL = dot(N, L); + float NdotV = dot(N, V); + + if(NdotL < 0 || NdotV < 0) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + float LdotH = dot(L, H); + + float value = schlick_fresnel(LdotH) * NdotL; + + return make_float3(value, value, value); +} + +ccl_device int bsdf_principled_sheen_setup(PrincipledSheenBsdf *bsdf) +{ + bsdf->type = CLOSURE_BSDF_PRINCIPLED_SHEEN_ID; + return SD_BSDF|SD_BSDF_HAS_EVAL; +} + +ccl_device float3 bsdf_principled_sheen_eval_reflect(const ShaderClosure *sc, const float3 I, + const float3 omega_in, float *pdf) +{ + const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc; + + float3 N = bsdf->N; + float3 V = I; // outgoing + float3 L = omega_in; // incoming + float3 H = normalize(L + V); + + if(dot(N, omega_in) > 0.0f) { + *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; + return calculate_principled_sheen_brdf(bsdf, N, V, L, H, pdf); + } + else { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +ccl_device float3 bsdf_principled_sheen_eval_transmit(const ShaderClosure *sc, const float3 I, + const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device int bsdf_principled_sheen_sample(const ShaderClosure *sc, + float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, + float3 *eval, float3 *omega_in, float3 *domega_in_dx, + float3 *domega_in_dy, float *pdf) +{ + const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc; + + float3 N = bsdf->N; + + sample_cos_hemisphere(N, randu, randv, omega_in, pdf); + + if(dot(Ng, *omega_in) > 0) { + float3 H = normalize(I + *omega_in); + + *eval = calculate_principled_sheen_brdf(bsdf, N, I, *omega_in, H, pdf); + +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); + *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); +#endif + } + else { + *pdf = 0.0f; + } + return LABEL_REFLECT|LABEL_DIFFUSE; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_PRINCIPLED_SHEEN_H__ */ + + diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index b0c5280b6cb..3dc15d5791c 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -124,6 +124,13 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k return(Rparl2 + Rperp2) * 0.5f; } +ccl_device float schlick_fresnel(float u) +{ + float m = clamp(1.0f - u, 0.0f, 1.0f); + float m2 = m * m; + return m2 * m2 * m; // pow(m, 5) +} + ccl_device float smooth_step(float edge0, float edge1, float x) { float result; @@ -136,6 +143,19 @@ ccl_device float smooth_step(float edge0, float edge1, float x) return result; } +/* Calculate the fresnel color which is a blend between white and the F0 color (cspec0) */ +ccl_device_forceinline float3 interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0) { + /* Calculate the fresnel interpolation factor + * The value from fresnel_dielectric_cos(...) has to be normalized because + * the cspec0 keeps the F0 color + */ + float F0_norm = 1.0f / (1.0f - F0); + float FH = (fresnel_dielectric_cos(dot(L, H), ior) - F0) * F0_norm; + + /* Blend between white and a specular color with respect to the fresnel */ + return cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; +} + CCL_NAMESPACE_END #endif /* __BSDF_UTIL_H__ */ diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index af0bbd861a9..8363cef53c8 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -27,6 +27,7 @@ typedef ccl_addr_space struct Bssrdf { float d; float texture_blur; float albedo; + float roughness; float3 N; } Bssrdf; @@ -360,10 +361,29 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) { if(bssrdf->radius < BSSRDF_MIN_RADIUS) { /* revert to diffuse BSDF if radius too small */ - DiffuseBsdf *bsdf = (DiffuseBsdf*)bssrdf; - bsdf->N = bssrdf->N; - int flag = bsdf_diffuse_setup(bsdf); - bsdf->type = CLOSURE_BSDF_BSSRDF_ID; + int flag; + if(type == CLOSURE_BSSRDF_PRINCIPLED_ID) { + float roughness = bssrdf->roughness; + float3 N = bssrdf->N; + float3 weight = bssrdf->weight; + float sample_weight = bssrdf->sample_weight; + + PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bssrdf; + + bsdf->N = N; + bsdf->roughness = roughness; + bsdf->weight = weight; + bsdf->sample_weight = sample_weight; + flag = bsdf_principled_diffuse_setup(bsdf); + bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID; + } + else { + DiffuseBsdf *bsdf = (DiffuseBsdf*)bssrdf; + bsdf->N = bssrdf->N; + flag = bsdf_diffuse_setup(bsdf); + bsdf->type = CLOSURE_BSDF_BSSRDF_ID; + } + return flag; } else { @@ -371,7 +391,7 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) bssrdf->sharpness = saturate(bssrdf->sharpness); bssrdf->type = type; - if(type == CLOSURE_BSSRDF_BURLEY_ID) { + if(type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_PRINCIPLED_ID) { bssrdf_burley_setup(bssrdf); } @@ -385,7 +405,7 @@ ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float bssrdf_cubic_sample(sc, xi, r, h); else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID) bssrdf_gaussian_sample(sc, xi, r, h); - else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID)*/ + else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ bssrdf_burley_sample(sc, xi, r, h); } @@ -395,7 +415,7 @@ ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r) return bssrdf_cubic_pdf(sc, r); else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID) return bssrdf_gaussian_pdf(sc, r); - else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID)*/ + else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ return bssrdf_burley_pdf(sc, r); } diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index f75e9337bdb..6c8b7cca4ce 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -140,7 +140,7 @@ ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, } /* replace closures with a single diffuse bsdf closure after scatter step */ -ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 weight, bool hit, float3 N) +ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, ShaderClosure *sc, float3 weight, bool hit, float3 N) { sd->flag &= ~SD_CLOSURE_FLAGS; sd->randb_closure = 0.0f; @@ -148,15 +148,31 @@ ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 wei sd->num_closure_extra = 0; if(hit) { - DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight); + Bssrdf *bssrdf = (Bssrdf *)sc; + if(bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID) { + PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), weight); + + if(bsdf) { + bsdf->N = N; + bsdf->roughness = bssrdf->roughness; + sd->flag |= bsdf_principled_diffuse_setup(bsdf); + + /* replace CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID with this special ID so render passes + * can recognize it as not being a regular Disney principled diffuse closure */ + bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID; + } + } + else if(CLOSURE_IS_BSSRDF(bssrdf->type)) { + DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight); - if(bsdf) { - bsdf->N = N; - sd->flag |= bsdf_diffuse_setup(bsdf); + if(bsdf) { + bsdf->N = N; + sd->flag |= bsdf_diffuse_setup(bsdf); - /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes - * can recognize it as not being a regular diffuse closure */ - bsdf->type = CLOSURE_BSDF_BSSRDF_ID; + /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes + * can recognize it as not being a regular diffuse closure */ + bsdf->type = CLOSURE_BSDF_BSSRDF_ID; + } } } } @@ -388,7 +404,7 @@ ccl_device_noinline void subsurface_scatter_multi_setup( subsurface_color_bump_blur(kg, sd, state, state_flag, &weight, &N); /* Setup diffuse BSDF. */ - subsurface_scatter_setup_diffuse_bsdf(sd, weight, true, N); + subsurface_scatter_setup_diffuse_bsdf(sd, sc, weight, true, N); } #ifndef __SPLIT_KERNEL__ @@ -479,7 +495,7 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, PathS subsurface_color_bump_blur(kg, sd, state, state_flag, &eval, &N); /* setup diffuse bsdf */ - subsurface_scatter_setup_diffuse_bsdf(sd, eval, (ss_isect.num_hits > 0), N); + subsurface_scatter_setup_diffuse_bsdf(sd, sc, eval, (ss_isect.num_hits > 0), N); } #endif /* ! __SPLIT_KERNEL__ */ diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp index 95beea01d25..188c3960a5f 100644 --- a/intern/cycles/kernel/osl/osl_bssrdf.cpp +++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp @@ -39,7 +39,9 @@ #include "kernel/kernel_montecarlo.h" #include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf_util.h" #include "kernel/closure/bsdf_diffuse.h" +#include "kernel/closure/bsdf_principled_diffuse.h" #include "kernel/closure/bssrdf.h" CCL_NAMESPACE_BEGIN @@ -78,6 +80,7 @@ public: bssrdf->albedo = albedo.x; bssrdf->sharpness = sharpness; bssrdf->N = params.N; + bssrdf->roughness = params.roughness; sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); } @@ -89,6 +92,7 @@ public: bssrdf->albedo = albedo.y; bssrdf->sharpness = sharpness; bssrdf->N = params.N; + bssrdf->roughness = params.roughness; sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); } @@ -100,6 +104,7 @@ public: bssrdf->albedo = albedo.z; bssrdf->sharpness = sharpness; bssrdf->N = params.N; + bssrdf->roughness = params.roughness; sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); } } @@ -180,5 +185,31 @@ ClosureParam *closure_bssrdf_burley_params() CCLOSURE_PREPARE(closure_bssrdf_burley_prepare, BurleyBSSRDFClosure) +/* Disney principled */ + +class PrincipledBSSRDFClosure : public CBSSRDFClosure { +public: + void setup(ShaderData *sd, int path_flag, float3 weight) + { + alloc(sd, path_flag, weight * albedo, CLOSURE_BSSRDF_PRINCIPLED_ID); + } +}; + +ClosureParam *closure_bssrdf_principled_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, params.N), + CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, radius), + CLOSURE_FLOAT_PARAM(PrincipledBSSRDFClosure, params.texture_blur), + CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, albedo), + CLOSURE_FLOAT_PARAM(PrincipledBSSRDFClosure, params.roughness), + CLOSURE_STRING_KEYPARAM(PrincipledBSSRDFClosure, label, "label"), + CLOSURE_FINISH_PARAM(PrincipledBSSRDFClosure) + }; + return params; +} + +CCLOSURE_PREPARE(closure_bssrdf_principled_prepare, PrincipledBSSRDFClosure) + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index f44714c2150..5b66793a05d 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -60,6 +60,8 @@ #include "kernel/closure/bsdf_ashikhmin_shirley.h" #include "kernel/closure/bsdf_toon.h" #include "kernel/closure/bsdf_hair.h" +#include "kernel/closure/bsdf_principled_diffuse.h" +#include "kernel/closure/bsdf_principled_sheen.h" #include "kernel/closure/volume.h" CCL_NAMESPACE_BEGIN @@ -176,6 +178,63 @@ VOLUME_CLOSURE_CLASS_END(VolumeHenyeyGreenstein, henyey_greenstein) VOLUME_CLOSURE_CLASS_BEGIN(VolumeAbsorption, absorption, ShaderClosure, LABEL_SINGULAR) VOLUME_CLOSURE_CLASS_END(VolumeAbsorption, absorption) +BSDF_CLOSURE_CLASS_BEGIN(PrincipledDiffuse, principled_diffuse, PrincipledDiffuseBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(PrincipledDiffuseClosure, params.N), + CLOSURE_FLOAT_PARAM(PrincipledDiffuseClosure, params.roughness), +BSDF_CLOSURE_CLASS_END(PrincipledDiffuse, principled_diffuse) + +BSDF_CLOSURE_CLASS_BEGIN(PrincipledSheen, principled_sheen, PrincipledSheenBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(PrincipledSheenClosure, params.N), +BSDF_CLOSURE_CLASS_END(PrincipledSheen, principled_sheen) + +/* DISNEY PRINCIPLED CLEARCOAT */ +class PrincipledClearcoatClosure : public CBSDFClosure { +public: + MicrofacetBsdf params; + float clearcoat, clearcoat_gloss; + + MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc_osl(sd, sizeof(MicrofacetBsdf), weight, ¶ms); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + if(bsdf && extra) { + bsdf->extra = extra; + + bsdf->ior = 1.5f; + + bsdf->alpha_x = 0.1f * (1.0f - clearcoat_gloss) + 0.001f * clearcoat_gloss; + bsdf->alpha_y = 0.1f * (1.0f - clearcoat_gloss) + 0.001f * clearcoat_gloss; + + bsdf->extra->cspec0 = make_float3(0.04f, 0.04f, 0.04f); + bsdf->extra->clearcoat = clearcoat; + + return bsdf; + } + + return NULL; + } + + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_ggx_clearcoat_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_principled_clearcoat_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(PrincipledClearcoatClosure, params.N), + CLOSURE_FLOAT_PARAM(PrincipledClearcoatClosure, clearcoat), + CLOSURE_FLOAT_PARAM(PrincipledClearcoatClosure, clearcoat_gloss), + CLOSURE_STRING_KEYPARAM(PrincipledClearcoatClosure, label, "label"), + CLOSURE_FINISH_PARAM(PrincipledClearcoatClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_principled_clearcoat_prepare, PrincipledClearcoatClosure) + + /* Registration */ static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, OSL::ClosureParam *params, OSL::PrepareClosureFunc prepare) @@ -215,6 +274,16 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) closure_bsdf_microfacet_multi_ggx_glass_params(), closure_bsdf_microfacet_multi_ggx_glass_prepare); register_closure(ss, "microfacet_multi_ggx_aniso", id++, closure_bsdf_microfacet_multi_ggx_aniso_params(), closure_bsdf_microfacet_multi_ggx_aniso_prepare); + register_closure(ss, "microfacet_ggx_fresnel", id++, + closure_bsdf_microfacet_ggx_fresnel_params(), closure_bsdf_microfacet_ggx_fresnel_prepare); + register_closure(ss, "microfacet_ggx_aniso_fresnel", id++, + closure_bsdf_microfacet_ggx_aniso_fresnel_params(), closure_bsdf_microfacet_ggx_aniso_fresnel_prepare); + register_closure(ss, "microfacet_multi_ggx_fresnel", id++, + closure_bsdf_microfacet_multi_ggx_fresnel_params(), closure_bsdf_microfacet_multi_ggx_fresnel_prepare); + register_closure(ss, "microfacet_multi_ggx_glass_fresnel", id++, + closure_bsdf_microfacet_multi_ggx_glass_fresnel_params(), closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare); + register_closure(ss, "microfacet_multi_ggx_aniso_fresnel", id++, + closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params(), closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare); register_closure(ss, "microfacet_beckmann", id++, bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare); register_closure(ss, "microfacet_beckmann_aniso", id++, @@ -229,6 +298,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) bsdf_diffuse_toon_params(), bsdf_diffuse_toon_prepare); register_closure(ss, "glossy_toon", id++, bsdf_glossy_toon_params(), bsdf_glossy_toon_prepare); + register_closure(ss, "principled_diffuse", id++, + bsdf_principled_diffuse_params(), bsdf_principled_diffuse_prepare); + register_closure(ss, "principled_sheen", id++, + bsdf_principled_sheen_params(), bsdf_principled_sheen_prepare); + register_closure(ss, "principled_clearcoat", id++, + closure_bsdf_principled_clearcoat_params(), closure_bsdf_principled_clearcoat_prepare); register_closure(ss, "emission", id++, closure_emission_params(), closure_emission_prepare); @@ -248,6 +323,8 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) 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, "bssrdf_principled", id++, + closure_bssrdf_principled_params(), closure_bssrdf_principled_prepare); register_closure(ss, "hair_reflection", id++, bsdf_hair_reflection_params(), bsdf_hair_reflection_prepare); @@ -278,6 +355,86 @@ bool CBSDFClosure::skip(const ShaderData *sd, int path_flag, int scattering) return false; } + +/* GGX closures with Fresnel */ + +class MicrofacetFresnelClosure : public CBSDFClosure { +public: + MicrofacetBsdf params; + float3 color; + float3 cspec0; + + MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight) + { + /* Technically, the MultiGGX Glass closure may also transmit. However, + * since this is set statically and only used for caustic flags, this + * is probably as good as it gets. */ + if(!skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc_osl(sd, sizeof(MicrofacetBsdf), weight, ¶ms); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + if(bsdf && extra) { + bsdf->extra = extra; + bsdf->extra->color = color; + bsdf->extra->cspec0 = cspec0; + return bsdf; + } + } + + return NULL; + } +}; + +class MicrofacetGGXFresnelClosure : public MicrofacetFresnelClosure { +public: + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_ggx_fresnel_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_microfacet_ggx_fresnel_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.ior), + CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, color), + CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, cspec0), + CLOSURE_STRING_KEYPARAM(MicrofacetGGXFresnelClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetGGXFresnelClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_ggx_fresnel_prepare, MicrofacetGGXFresnelClosure); + +class MicrofacetGGXAnisoFresnelClosure : public MicrofacetFresnelClosure { +public: + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_ggx_aniso_fresnel_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_microfacet_ggx_aniso_fresnel_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.N), + CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.T), + CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_y), + CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.ior), + CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, color), + CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, cspec0), + CLOSURE_STRING_KEYPARAM(MicrofacetGGXFresnelClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetGGXFresnelClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_ggx_aniso_fresnel_prepare, MicrofacetGGXAnisoFresnelClosure); + + /* Multiscattering GGX closures */ class MicrofacetMultiClosure : public CBSDFClosure { @@ -287,7 +444,7 @@ public: MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight) { - /* Technically, the MultiGGX Glass closure may also transmit. However, + /* Technically, the MultiGGX closure may also transmit. However, * since this is set statically and only used for caustic flags, this * is probably as good as it gets. */ if(!skip(sd, path_flag, LABEL_GLOSSY|LABEL_REFLECT)) { @@ -375,5 +532,110 @@ ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params() } CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure); + +/* Multiscattering GGX closures with Fresnel */ + +class MicrofacetMultiFresnelClosure : public CBSDFClosure { +public: + MicrofacetBsdf params; + float3 color; + float3 cspec0; + + MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight) + { + /* Technically, the MultiGGX closure may also transmit. However, + * since this is set statically and only used for caustic flags, this + * is probably as good as it gets. */ + if(!skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc_osl(sd, sizeof(MicrofacetBsdf), weight, ¶ms); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + if(bsdf && extra) { + bsdf->extra = extra; + bsdf->extra->color = color; + bsdf->extra->cspec0 = cspec0; + return bsdf; + } + } + + return NULL; + } +}; + +class MicrofacetMultiGGXFresnelClosure : public MicrofacetMultiFresnelClosure { +public: + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_fresnel_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_fresnel_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_fresnel_prepare, MicrofacetMultiGGXFresnelClosure); + +class MicrofacetMultiGGXAnisoFresnelClosure : public MicrofacetMultiFresnelClosure { +public: + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_aniso_fresnel_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.T), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_y), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare, MicrofacetMultiGGXAnisoFresnelClosure); + +class MicrofacetMultiGGXGlassFresnelClosure : public MicrofacetMultiFresnelClosure { +public: + MicrofacetMultiGGXGlassFresnelClosure() : MicrofacetMultiFresnelClosure() {} + + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_fresnel_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare, MicrofacetMultiGGXGlassFresnelClosure); + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 929cf00a7e6..ff5fd9cc905 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -51,10 +51,17 @@ 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_bssrdf_principled_params(); OSL::ClosureParam *closure_henyey_greenstein_volume_params(); OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params(); OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params(); OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params(); +OSL::ClosureParam *closure_bsdf_microfacet_ggx_fresnel_params(); +OSL::ClosureParam *closure_bsdf_microfacet_ggx_aniso_fresnel_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_fresnel_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_fresnel_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params(); +OSL::ClosureParam *closure_bsdf_principled_clearcoat_params(); void closure_emission_prepare(OSL::RendererServices *, int id, void *data); void closure_background_prepare(OSL::RendererServices *, int id, void *data); @@ -65,10 +72,17 @@ 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_bssrdf_principled_prepare(OSL::RendererServices *, int id, void *data); void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_ggx_fresnel_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_ggx_aniso_fresnel_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_fresnel_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_principled_clearcoat_prepare(OSL::RendererServices *, int id, void *data); #define CCLOSURE_PREPARE(name, classname) \ void name(RendererServices *, int id, void *data) \ diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index b43f8402d42..ef1f405e34e 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -81,6 +81,7 @@ set(SRC_OSL node_wireframe.osl node_hair_bsdf.osl node_uv_map.osl + node_principled_bsdf.osl node_rgb_to_bw.osl ) diff --git a/intern/cycles/kernel/shaders/node_principled_bsdf.osl b/intern/cycles/kernel/shaders/node_principled_bsdf.osl new file mode 100644 index 00000000000..39c6c7e5fd9 --- /dev/null +++ b/intern/cycles/kernel/shaders/node_principled_bsdf.osl @@ -0,0 +1,120 @@ +/* + * Copyright 2011-2017 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stdosl.h" +#include "node_fresnel.h" + +shader node_principled_bsdf( + string distribution = "Multiscatter GGX", + color BaseColor = color(0.8, 0.8, 0.8), + float Subsurface = 0.0, + vector SubsurfaceRadius = vector(1.0, 1.0, 1.0), + color SubsurfaceColor = color(0.7, 0.1, 0.1), + float Metallic = 0.0, + float Specular = 0.5, + float SpecularTint = 0.0, + float Roughness = 0.5, + float Anisotropic = 0.0, + float AnisotropicRotation = 0.0, + float Sheen = 0.0, + float SheenTint = 0.5, + float Clearcoat = 0.0, + float ClearcoatGloss = 1.0, + float IOR = 1.45, + float Transparency = 0.0, + float RefractionRoughness = 0.0, + normal Normal = N, + normal ClearcoatNormal = N, + normal Tangent = normalize(dPdu), + output closure color BSDF = 0) +{ + float f = max(IOR, 1e-5); + float diffuse_weight = (1.0 - clamp(Metallic, 0.0, 1.0)) * (1.0 - clamp(Transparency, 0.0, 1.0)); + float transp = clamp(Transparency, 0.0, 1.0) * (1.0 - clamp(Metallic, 0.0, 1.0)); + float specular_weight = (1.0 - transp); + + vector T = Tangent; + + float m_cdlum = luminance(BaseColor); + color m_ctint = m_cdlum > 0.0 ? BaseColor / m_cdlum : color(0.0, 0.0, 0.0); // normalize lum. to isolate hue+sat + + /* rotate tangent */ + if (AnisotropicRotation != 0.0) + T = rotate(T, AnisotropicRotation * M_2PI, point(0.0, 0.0, 0.0), Normal); + + if (diffuse_weight > 1e-5) { + if (Subsurface > 1e-5) { + color Albedo = SubsurfaceColor * Subsurface + BaseColor * (1.0 - Subsurface); + BSDF = bssrdf_principled(Normal, Subsurface * SubsurfaceRadius, 0.0, Albedo, Roughness); + } else { + BSDF = BaseColor * principled_diffuse(Normal, Roughness); + } + + if (Sheen > 1e-5) { + color sheen_color = color(1.0, 1.0, 1.0) * (1.0 - SheenTint) + m_ctint * SheenTint; + + BSDF = BSDF + sheen_color * Sheen * principled_sheen(Normal); + } + + BSDF = BSDF * diffuse_weight; + } + + if (specular_weight > 1e-5) { + float aspect = sqrt(1.0 - Anisotropic * 0.9); + float r2 = Roughness * Roughness; + + float alpha_x = max(0.001, r2 / aspect); + float alpha_y = max(0.001, r2 * aspect); + + color tmp_col = color(1.0, 1.0, 1.0) * (1.0 - SpecularTint) + m_ctint * SpecularTint; + + color Cspec0 = (Specular * 0.08 * tmp_col) * (1.0 - Metallic) + BaseColor * Metallic; + + if (distribution == "GGX" || Roughness <= 0.075) { + BSDF = BSDF + specular_weight * microfacet_ggx_aniso_fresnel(Normal, T, alpha_x, alpha_y, (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, BaseColor, Cspec0); + } else { + BSDF = BSDF + specular_weight * microfacet_multi_ggx_aniso_fresnel(Normal, T, alpha_x, alpha_y, (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, BaseColor, Cspec0); + } + } + + if (transp > 1e-5) { + color Cspec0 = BaseColor * SpecularTint + color(1.0, 1.0, 1.0) * (1.0 - SpecularTint); + float eta = backfacing() ? 1.0 / f : f; + + if (distribution == "GGX" || Roughness <= 5e-2) { + float cosNO = dot(Normal, I); + float Fr = fresnel_dielectric_cos(cosNO, eta); + + float refl_roughness = Roughness; + if (Roughness <= 1e-2) + refl_roughness = 0.0; + + float refraction_roughness = refl_roughness; + if (distribution == "GGX") + refraction_roughness = 1.0 - (1.0 - refl_roughness) * (1.0 - RefractionRoughness); + + BSDF = BSDF + transp * (Fr * microfacet_ggx_fresnel(Normal, refl_roughness * refl_roughness, eta, BaseColor, Cspec0) + + (1.0 - Fr) * BaseColor * microfacet_ggx_refraction(Normal, refraction_roughness * refraction_roughness, eta)); + } else { + BSDF = BSDF + transp * microfacet_multi_ggx_glass_fresnel(Normal, Roughness * Roughness, eta, BaseColor, Cspec0); + } + } + + if (Clearcoat > 1e-5) { + BSDF = BSDF + principled_clearcoat(ClearcoatNormal, Clearcoat, ClearcoatGloss); + } +} + diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index a8dda8a12c9..289d1091b0a 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -530,6 +530,11 @@ closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN; closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; +closure color microfacet_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; +closure color microfacet_ggx_aniso_fresnel(normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN; +closure color microfacet_multi_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; +closure color microfacet_multi_ggx_aniso_fresnel(normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN; +closure color microfacet_multi_ggx_glass_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; closure color microfacet_beckmann(normal N, float ab) BUILTIN; closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; @@ -539,11 +544,15 @@ closure color emission() BUILTIN; closure color background() BUILTIN; closure color holdout() BUILTIN; closure color ambient_occlusion() BUILTIN; +closure color principled_diffuse(normal N, float roughness) BUILTIN; +closure color principled_sheen(normal N) BUILTIN; +closure color principled_clearcoat(normal N, float clearcoat, float clearcoat_gloss) BUILTIN; // BSSRDF closure color bssrdf_cubic(normal N, vector radius, float texture_blur, float sharpness) BUILTIN; closure color bssrdf_gaussian(normal N, vector radius, float texture_blur) BUILTIN; closure color bssrdf_burley(normal N, vector radius, float texture_blur, color albedo) BUILTIN; +closure color bssrdf_principled(normal N, vector radius, float texture_blur, color subsurface_color, float roughness) BUILTIN; // Hair closure color hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN; diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 1885e1af851..9a3689a94f4 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -76,6 +76,338 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __uint_as_float(node.w); switch(type) { + case CLOSURE_BSDF_PRINCIPLED_ID: { + uint specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset, sheen_offset, + sheen_tint_offset, clearcoat_offset, clearcoat_gloss_offset, eta_offset, transparency_offset, + anisotropic_rotation_offset, refraction_roughness_offset; + uint4 data_node2 = read_node(kg, offset); + + float3 T = stack_load_float3(stack, data_node.y); + decode_node_uchar4(data_node.z, &specular_offset, &roughness_offset, &specular_tint_offset, &anisotropic_offset); + decode_node_uchar4(data_node.w, &sheen_offset, &sheen_tint_offset, &clearcoat_offset, &clearcoat_gloss_offset); + decode_node_uchar4(data_node2.x, &eta_offset, &transparency_offset, &anisotropic_rotation_offset, &refraction_roughness_offset); + + // get Disney principled parameters + float metallic = param1; + float subsurface = param2; + float specular = stack_load_float(stack, specular_offset); + float roughness = stack_load_float(stack, roughness_offset); + float specular_tint = stack_load_float(stack, specular_tint_offset); + float anisotropic = stack_load_float(stack, anisotropic_offset); + float sheen = stack_load_float(stack, sheen_offset); + float sheen_tint = stack_load_float(stack, sheen_tint_offset); + float clearcoat = stack_load_float(stack, clearcoat_offset); + float clearcoat_gloss = stack_load_float(stack, clearcoat_gloss_offset); + float transparency = stack_load_float(stack, transparency_offset); + float anisotropic_rotation = stack_load_float(stack, anisotropic_rotation_offset); + float refraction_roughness = stack_load_float(stack, refraction_roughness_offset); + float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f); + + ClosureType distribution = stack_valid(data_node2.y) ? (ClosureType) data_node2.y : CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + + /* rotate tangent */ + if(anisotropic_rotation != 0.0f) + T = rotate_around_axis(T, N, anisotropic_rotation * M_2PI_F); + + /* calculate ior */ + float ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; + + // calculate fresnel for refraction + float cosNO = dot(N, sd->I); + float fresnel = fresnel_dielectric_cos(cosNO, ior); + + // calculate weights of the diffuse and specular part + float diffuse_weight = (1.0f - saturate(metallic)) * (1.0f - saturate(transparency)); + + float transp = saturate(transparency) * (1.0f - saturate(metallic)); + float specular_weight = (1.0f - transp); + + // get the base color + uint4 data_base_color = read_node(kg, offset); + float3 base_color = stack_valid(data_base_color.x) ? stack_load_float3(stack, data_base_color.x) : + make_float3(__uint_as_float(data_base_color.y), __uint_as_float(data_base_color.z), __uint_as_float(data_base_color.w)); + + // get the additional clearcoat normal and subsurface scattering radius + uint4 data_cn_ssr = read_node(kg, offset); + float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ? stack_load_float3(stack, data_cn_ssr.x) : sd->N; + float3 subsurface_radius = stack_valid(data_cn_ssr.y) ? stack_load_float3(stack, data_cn_ssr.y) : make_float3(1.0f, 1.0f, 1.0f); + + // get the subsurface color + uint4 data_subsurface_color = read_node(kg, offset); + float3 subsurface_color = stack_valid(data_subsurface_color.x) ? stack_load_float3(stack, data_subsurface_color.x) : + make_float3(__uint_as_float(data_subsurface_color.y), __uint_as_float(data_subsurface_color.z), __uint_as_float(data_subsurface_color.w)); + + float3 weight = sd->svm_closure_weight * mix_weight; + +#ifdef __SUBSURFACE__ + float3 albedo = subsurface_color * subsurface + base_color * (1.0f - subsurface); + float3 subsurf_weight = weight * albedo * diffuse_weight; + float subsurf_sample_weight = fabsf(average(subsurf_weight)); + + /* disable in case of diffuse ancestor, can't see it well then and + * adds considerably noise due to probabilities of continuing path + * getting lower and lower */ + if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) { + subsurface = 0.0f; + } + + /* diffuse */ + if(fabsf(average(base_color)) > CLOSURE_WEIGHT_CUTOFF) { + if(subsurface < CLOSURE_WEIGHT_CUTOFF && diffuse_weight > CLOSURE_WEIGHT_CUTOFF) { + float3 diff_weight = weight * base_color * diffuse_weight; + + PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diff_weight); + + if(bsdf) { + bsdf->N = N; + bsdf->roughness = roughness; + + /* setup bsdf */ + sd->flag |= bsdf_principled_diffuse_setup(bsdf); + } + } + else if(subsurface > CLOSURE_WEIGHT_CUTOFF && subsurf_sample_weight > CLOSURE_WEIGHT_CUTOFF) { + /* radius * scale */ + float3 radius = subsurface_radius * subsurface; + /* sharpness */ + float sharpness = 0.0f; + /* texture color blur */ + float texture_blur = 0.0f; + + /* create one closure per color channel */ + Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(subsurf_weight.x, 0.0f, 0.0f)); + if(bssrdf) { + bssrdf->sample_weight = subsurf_sample_weight; + bssrdf->radius = radius.x; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.x; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + bssrdf->roughness = roughness; + + /* setup bsdf */ + sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID); + } + + bssrdf = bssrdf_alloc(sd, make_float3(0.0f, subsurf_weight.y, 0.0f)); + if(bssrdf) { + bssrdf->sample_weight = subsurf_sample_weight; + bssrdf->radius = radius.y; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.y; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + bssrdf->roughness = roughness; + + /* setup bsdf */ + sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID); + } + + bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, subsurf_weight.z)); + if(bssrdf) { + bssrdf->sample_weight = subsurf_sample_weight; + bssrdf->radius = radius.z; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.z; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + bssrdf->roughness = roughness; + + /* setup bsdf */ + sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID); + } + } + } +#else + /* diffuse */ + if(diffuse_weight > CLOSURE_WEIGHT_CUTOFF) { + float3 diff_weight = weight * base_color * diffuse_weight; + + PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diff_weight); + + if(bsdf) { + bsdf->N = N; + bsdf->roughness = roughness; + + /* setup bsdf */ + sd->flag |= bsdf_principled_diffuse_setup(bsdf); + } + } +#endif + + /* sheen */ + if(diffuse_weight > CLOSURE_WEIGHT_CUTOFF && sheen > CLOSURE_WEIGHT_CUTOFF) { + float m_cdlum = linear_rgb_to_gray(base_color); + float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat + + /* color of the sheen component */ + float3 sheen_color = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - sheen_tint) + m_ctint * sheen_tint; + + float3 sheen_weight = weight * sheen * sheen_color * diffuse_weight; + + PrincipledSheenBsdf *bsdf = (PrincipledSheenBsdf*)bsdf_alloc(sd, sizeof(PrincipledSheenBsdf), sheen_weight); + + if(bsdf) { + bsdf->N = N; + + /* setup bsdf */ + sd->flag |= bsdf_principled_sheen_setup(bsdf); + } + } + + /* specular reflection */ +#ifdef __CAUSTICS_TRICKS__ + if(kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) { +#endif + if(specular_weight > CLOSURE_WEIGHT_CUTOFF && (specular > CLOSURE_WEIGHT_CUTOFF || metallic > CLOSURE_WEIGHT_CUTOFF)) { + float3 spec_weight = weight * specular_weight; + + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), spec_weight); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + + if(bsdf && extra) { + bsdf->N = N; + bsdf->ior = (2.0f / (1.0f - safe_sqrtf(0.08f * specular))) - 1.0f; + bsdf->T = T; + bsdf->extra = extra; + + float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f); + float r2 = roughness * roughness; + + bsdf->alpha_x = fmaxf(0.001f, r2 / aspect); + bsdf->alpha_y = fmaxf(0.001f, r2 * aspect); + + float m_cdlum = 0.3f * base_color.x + 0.6f * base_color.y + 0.1f * base_color.z; // luminance approx. + float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : make_float3(0.0f, 0.0f, 0.0f); // normalize lum. to isolate hue+sat + float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specular_tint) + m_ctint * specular_tint; + + bsdf->extra->cspec0 = (specular * 0.08f * tmp_col) * (1.0f - metallic) + base_color * metallic; + bsdf->extra->color = base_color; + + /* setup bsdf */ + if(distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID || roughness <= 0.075f) /* use single-scatter GGX */ + sd->flag |= bsdf_microfacet_ggx_aniso_fresnel_setup(bsdf); + else /* use multi-scatter GGX */ + sd->flag |= bsdf_microfacet_multi_ggx_aniso_fresnel_setup(bsdf); + } + } +#ifdef __CAUSTICS_TRICKS__ + } +#endif + + /* BSDF */ +#ifdef __CAUSTICS_TRICKS__ + if(kernel_data.integrator.caustics_reflective || kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) { +#endif + if(transp > CLOSURE_WEIGHT_CUTOFF) { + float3 glass_weight = weight * transp; + float3 cspec0 = base_color * specular_tint + make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specular_tint); + + if(roughness <= 5e-2f || distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) { /* use single-scatter GGX */ + float refl_roughness = roughness; + + /* reflection */ +#ifdef __CAUSTICS_TRICKS__ + if(kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) +#endif + { + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), glass_weight*fresnel); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + + if(bsdf && extra) { + bsdf->N = N; + bsdf->extra = extra; + + bsdf->alpha_x = refl_roughness * refl_roughness; + bsdf->alpha_y = refl_roughness * refl_roughness; + bsdf->ior = ior; + + bsdf->extra->color = base_color; + bsdf->extra->cspec0 = cspec0; + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf); + } + } + + /* refraction */ +#ifdef __CAUSTICS_TRICKS__ + if(kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) +#endif + { + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), base_color*glass_weight*(1.0f - fresnel)); + + if(bsdf) { + bsdf->N = N; + + if(distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) + refraction_roughness = 1.0f - (1.0f - refl_roughness) * (1.0f - refraction_roughness); + else + refraction_roughness = refl_roughness; + + bsdf->alpha_x = refraction_roughness * refraction_roughness; + bsdf->alpha_y = refraction_roughness * refraction_roughness; + bsdf->ior = ior; + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); + } + } + } + else { /* use multi-scatter GGX */ + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), glass_weight); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + + if(bsdf && extra) { + bsdf->N = N; + bsdf->extra = extra; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); + + bsdf->alpha_x = roughness * roughness; + bsdf->alpha_y = roughness * roughness; + bsdf->ior = ior; + + bsdf->extra->color = base_color; + bsdf->extra->cspec0 = cspec0; + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf); + } + } + } +#ifdef __CAUSTICS_TRICKS__ + } +#endif + + /* clearcoat */ +#ifdef __CAUSTICS_TRICKS__ + if(kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) { +#endif + if(clearcoat > CLOSURE_WEIGHT_CUTOFF) { + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + + if(bsdf && extra) { + bsdf->N = clearcoat_normal; + bsdf->ior = 1.5f; + bsdf->extra = extra; + + bsdf->alpha_x = 0.1f * (1.0f - clearcoat_gloss) + 0.001f * clearcoat_gloss; + bsdf->alpha_y = 0.1f * (1.0f - clearcoat_gloss) + 0.001f * clearcoat_gloss; + + bsdf->extra->cspec0 = make_float3(0.04f, 0.04f, 0.04f); + bsdf->extra->clearcoat = clearcoat; + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf); + } + } +#ifdef __CAUSTICS_TRICKS__ + } +#endif + + break; + } case CLOSURE_BSDF_DIFFUSE_ID: { float3 weight = sd->svm_closure_weight * mix_weight; OrenNayarBsdf *bsdf = (OrenNayarBsdf*)bsdf_alloc(sd, sizeof(OrenNayarBsdf), weight); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 47209ddfbab..4a8cdb60952 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -397,17 +397,24 @@ typedef enum ClosureType { CLOSURE_BSDF_DIFFUSE_ID, CLOSURE_BSDF_OREN_NAYAR_ID, CLOSURE_BSDF_DIFFUSE_RAMP_ID, + CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID, + CLOSURE_BSDF_PRINCIPLED_SHEEN_ID, CLOSURE_BSDF_DIFFUSE_TOON_ID, /* Glossy */ CLOSURE_BSDF_GLOSSY_ID, CLOSURE_BSDF_REFLECTION_ID, CLOSURE_BSDF_MICROFACET_GGX_ID, + CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID, + CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ID, CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID, + CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID, CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_FRESNEL_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, @@ -424,16 +431,19 @@ typedef enum ClosureType { CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID, CLOSURE_BSDF_SHARP_GLASS_ID, CLOSURE_BSDF_HAIR_TRANSMISSION_ID, /* Special cases */ CLOSURE_BSDF_BSSRDF_ID, + CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID, CLOSURE_BSDF_TRANSPARENT_ID, /* BSSRDF */ CLOSURE_BSSRDF_CUBIC_ID, CLOSURE_BSSRDF_GAUSSIAN_ID, + CLOSURE_BSSRDF_PRINCIPLED_ID, CLOSURE_BSSRDF_BURLEY_ID, /* Other */ @@ -447,6 +457,8 @@ typedef enum ClosureType { CLOSURE_VOLUME_ABSORPTION_ID, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, + CLOSURE_BSDF_PRINCIPLED_ID, + NBUILTIN_CLOSURES } ClosureType; @@ -455,7 +467,7 @@ typedef enum ClosureType { #define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_DIFFUSE_TOON_ID) #define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID) #define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID) -#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID) +#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID || type == CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID) #define CLOSURE_IS_BSDF_ANISOTROPIC(type) (type >= CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID) #define CLOSURE_IS_BSDF_MULTISCATTER(type) (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID ||\ type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID || \ @@ -469,6 +481,7 @@ typedef enum ClosureType { #define CLOSURE_IS_AMBIENT_OCCLUSION(type) (type == CLOSURE_AMBIENT_OCCLUSION_ID) #define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) #define CLOSURE_IS_GLASS(type) (type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID) +#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID) #define CLOSURE_WEIGHT_CUTOFF 1e-5f diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 4dac078e151..2d810ff664f 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -1037,6 +1037,9 @@ int ShaderGraph::get_num_closures() else if(CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) { num_closures += 2; } + else if(CLOSURE_IS_PRINCIPLED(closure_type)) { + num_closures += 8; + } else { ++num_closures; } diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 1070e05a03b..3f56690d0c1 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2286,6 +2286,150 @@ void DiffuseBsdfNode::compile(OSLCompiler& compiler) compiler.add(this, "node_diffuse_bsdf"); } +/* Disney principled BSDF Closure */ +NODE_DEFINE(PrincipledBsdfNode) +{ + NodeType* type = NodeType::add("principled_bsdf", create, NodeType::SHADER); + + static NodeEnum distribution_enum; + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f); + SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f); + SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f)); + SOCKET_IN_FLOAT(specular, "Specular", 0.0f); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f); + SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f); + SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f); + SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f); + SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f); + SOCKET_IN_FLOAT(clearcoat_gloss, "Clearcoat Gloss", 0.0f); + SOCKET_IN_FLOAT(ior, "IOR", 0.0f); + SOCKET_IN_FLOAT(transparency, "Transparency", 0.0f); + SOCKET_IN_FLOAT(refraction_roughness, "Refraction Roughness", 0.0f); + SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_NORMAL(clearcoat_normal, "Clearcoat Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_NORMAL(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + +PrincipledBsdfNode::PrincipledBsdfNode() + : ShaderNode(node_type) +{ + special_type = SHADER_SPECIAL_TYPE_CLOSURE; + closure = CLOSURE_BSDF_PRINCIPLED_ID; + distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + distribution_orig = NBUILTIN_CLOSURES; +} + +void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) +{ + if(shader->has_surface) { + ShaderInput *tangent_in = input("Tangent"); + + if(!tangent_in->link) + attributes->add(ATTR_STD_GENERATED); + } + + ShaderNode::attributes(shader, attributes); +} + +void PrincipledBsdfNode::compile(SVMCompiler& compiler, ShaderInput *p_metallic, ShaderInput *p_subsurface, ShaderInput *p_subsurface_radius, + ShaderInput *p_specular, ShaderInput *p_roughness, ShaderInput *p_specular_tint, ShaderInput *p_anisotropic, + ShaderInput *p_sheen, ShaderInput *p_sheen_tint, ShaderInput *p_clearcoat, ShaderInput *p_clearcoat_gloss, + ShaderInput *p_ior, ShaderInput *p_transparency, ShaderInput *p_anisotropic_rotation, ShaderInput *p_refraction_roughness) +{ + ShaderInput *base_color_in = input("Base Color"); + ShaderInput *subsurface_color_in = input("Subsurface Color"); + ShaderInput *normal_in = input("Normal"); + ShaderInput *clearcoat_normal_in = input("Clearcoat Normal"); + ShaderInput *tangent_in = input("Tangent"); + + float3 weight = make_float3(1.0f, 1.0f, 1.0f); + + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight); + + int normal_offset = compiler.stack_assign_if_linked(normal_in); + int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in); + int tangent_offset = compiler.stack_assign_if_linked(tangent_in); + int specular_offset = compiler.stack_assign(p_specular); + int roughness_offset = compiler.stack_assign(p_roughness); + int specular_tint_offset = compiler.stack_assign(p_specular_tint); + int anisotropic_offset = compiler.stack_assign(p_anisotropic); + int sheen_offset = compiler.stack_assign(p_sheen); + int sheen_tint_offset = compiler.stack_assign(p_sheen_tint); + int clearcoat_offset = compiler.stack_assign(p_clearcoat); + int clearcoat_gloss_offset = compiler.stack_assign(p_clearcoat_gloss); + int ior_offset = compiler.stack_assign(p_ior); + int transparency_offset = compiler.stack_assign(p_transparency); + int refraction_roughness_offset = compiler.stack_assign(p_refraction_roughness); + int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation); + int subsurface_radius_offset = compiler.stack_assign(p_subsurface_radius); + + compiler.add_node(NODE_CLOSURE_BSDF, + compiler.encode_uchar4(closure, + compiler.stack_assign(p_metallic), + compiler.stack_assign(p_subsurface), + compiler.closure_mix_weight_offset()), + __float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f), + __float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f)); + + compiler.add_node(normal_offset, tangent_offset, + compiler.encode_uchar4(specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset), + compiler.encode_uchar4(sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_gloss_offset)); + + compiler.add_node(compiler.encode_uchar4(ior_offset, transparency_offset, anisotropic_rotation_offset, refraction_roughness_offset), + distribution, SVM_STACK_INVALID, SVM_STACK_INVALID); + + float3 bc_default = get_float3(base_color_in->socket_type); + + compiler.add_node(((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID), + __float_as_int(bc_default.x), __float_as_int(bc_default.y), __float_as_int(bc_default.z)); + + compiler.add_node(clearcoat_normal_offset, subsurface_radius_offset, SVM_STACK_INVALID, SVM_STACK_INVALID); + + float3 ss_default = get_float3(subsurface_color_in->socket_type); + + compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) : SVM_STACK_INVALID), + __float_as_int(ss_default.x), __float_as_int(ss_default.y), __float_as_int(ss_default.z)); +} + +bool PrincipledBsdfNode::has_integrator_dependency() +{ + ShaderInput *roughness_input = input("Roughness"); + return !roughness_input->link && roughness <= 1e-4f; +} + +void PrincipledBsdfNode::compile(SVMCompiler& compiler) +{ + compile(compiler, input("Metallic"), input("Subsurface"), input("Subsurface Radius"), input("Specular"), + input("Roughness"), input("Specular Tint"), input("Anisotropic"), input("Sheen"), input("Sheen Tint"), + input("Clearcoat"), input("Clearcoat Gloss"), input("IOR"), input("Transparency"), + input("Anisotropic Rotation"), input("Refraction Roughness")); +} + +void PrincipledBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.parameter(this, "distribution"); + compiler.add(this, "node_principled_bsdf"); +} + +bool PrincipledBsdfNode::has_bssrdf_bump() +{ + /* detect if anything is plugged into the normal input besides the default */ + ShaderInput *normal_in = input("Normal"); + return (normal_in->link && normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY); +} + /* Translucent BSDF Closure */ NODE_DEFINE(TranslucentBsdfNode) diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index cf68bd80458..bc488161e3b 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -361,6 +361,39 @@ public: float roughness; }; +/* Disney principled BRDF */ +class PrincipledBsdfNode : public ShaderNode { +public: + SHADER_NODE_CLASS(PrincipledBsdfNode) + + bool has_spatial_varying() { return true; } + bool has_surface_bssrdf() { return true; } + bool has_bssrdf_bump(); + void compile(SVMCompiler& compiler, ShaderInput *metallic, ShaderInput *subsurface, ShaderInput *subsurface_radius, + ShaderInput *specular, ShaderInput *roughness, ShaderInput *specular_tint, ShaderInput *anisotropic, + ShaderInput *sheen, ShaderInput *sheen_tint, ShaderInput *clearcoat, ShaderInput *clearcoat_gloss, + ShaderInput *ior, ShaderInput *transparency, ShaderInput *anisotropic_rotation, ShaderInput *refraction_roughness); + + float3 base_color; + float3 subsurface_color, subsurface_radius; + float metallic, subsurface, specular, roughness, specular_tint, anisotropic, + sheen, sheen_tint, clearcoat, clearcoat_gloss, ior, transparency, + anisotropic_rotation, refraction_roughness; + float3 normal, clearcoat_normal, tangent; + float surface_mix_weight; + ClosureType closure, distribution, distribution_orig; + + virtual bool equals(const ShaderNode * /*other*/) + { + /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */ + return false; + } + + ClosureType get_closure_type() { return closure; } + bool has_integrator_dependency(); + void attributes(Shader *shader, AttributeRequestSet *attributes); +}; + class TranslucentBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(TranslucentBsdfNode) |