Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <eiseljulian@gmail.com>2017-04-18 14:18:49 +0300
committerJulian Eisel <eiseljulian@gmail.com>2017-04-18 14:18:49 +0300
commit792f0aaad54631712de02df6b301e58ae3b59575 (patch)
tree92fa5d6638072faa60da1b6490091f57abf81b12
parentbc6f68944885da097d20e94812bbac58ade5f985 (diff)
parent8825a8e951c193ff855a1bbfb5a34ea93b8ccc55 (diff)
Merge branch 'master' into HMD_viewportHMD_viewport
Conflicts: source/blender/editors/gpencil/gpencil_paint.c
-rw-r--r--intern/cycles/blender/blender_shader.cpp13
-rw-r--r--intern/cycles/device/opencl/opencl_util.cpp2
-rw-r--r--intern/cycles/kernel/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/closure/bsdf.h50
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h147
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h72
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h95
-rw-r--r--intern/cycles/kernel/closure/bsdf_principled_diffuse.h120
-rw-r--r--intern/cycles/kernel/closure/bsdf_principled_sheen.h114
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h20
-rw-r--r--intern/cycles/kernel/closure/bssrdf.h34
-rw-r--r--intern/cycles/kernel/kernel_shadow.h2
-rw-r--r--intern/cycles/kernel/kernel_subsurface.h36
-rw-r--r--intern/cycles/kernel/osl/osl_bssrdf.cpp31
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp264
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h14
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_principled_bsdf.osl120
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h9
-rw-r--r--intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h2
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h332
-rw-r--r--intern/cycles/kernel/svm/svm_types.h15
-rw-r--r--intern/cycles/render/graph.cpp64
-rw-r--r--intern/cycles/render/graph.h3
-rw-r--r--intern/cycles/render/nodes.cpp144
-rw-r--r--intern/cycles/render/nodes.h35
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py11
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/intern/armature_update.c2
-rw-r--r--source/blender/blenkernel/intern/node.c1
-rw-r--r--source/blender/blenlib/BLI_hash.h6
-rw-r--r--source/blender/blenlib/BLI_path_util.h2
-rw-r--r--source/blender/blenlib/intern/path_util.c6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc7
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c12
-rw-r--r--source/blender/editors/physics/physics_fluid.c112
-rw-r--r--source/blender/editors/space_node/drawnode.c1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl190
-rw-r--r--source/blender/makesdna/DNA_object_fluidsim.h1
-rw-r--r--source/blender/makesrna/intern/rna_ID.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c26
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c63
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c28
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c114
51 files changed, 2144 insertions, 190 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/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp
index fe1c65a2224..38003dd1e1e 100644
--- a/intern/cycles/device/opencl/opencl_util.cpp
+++ b/intern/cycles/device/opencl/opencl_util.cpp
@@ -902,7 +902,7 @@ bool OpenCLInfo::get_platform_name(cl_platform_id platform_id,
string OpenCLInfo::get_platform_name(cl_platform_id platform_id)
{
string platform_name;
- if (!get_platform_name(platform_id, &platform_name)) {
+ if(!get_platform_name(platform_id, &platform_name)) {
return "";
}
return platform_name;
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_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index db6f839d9ed..fab5946970d 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -379,7 +379,7 @@ ccl_device bool shadow_blocked_transparent_stepped(
float3 *shadow)
{
bool blocked, is_transparent_isect;
- if (skip_object == OBJECT_NONE) {
+ if(skip_object == OBJECT_NONE) {
blocked = scene_intersect(kg,
*ray,
PATH_RAY_SHADOW_OPAQUE,
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, &params);
+ 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, &params);
+ 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, &params);
+ 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/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
index 9fc853a84bf..89adeb64c8a 100644
--- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
+++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
@@ -122,7 +122,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
#ifdef __SHADOW_TRICKS__
if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) {
- if (state->flag & PATH_RAY_CAMERA) {
+ if(state->flag & PATH_RAY_CAMERA) {
state->flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY);
state->catcher_object = sd->object;
if(!kernel_data.background.transparent) {
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 12fff8e5587..2d810ff664f 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -423,7 +423,8 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
/* Graph simplification */
/* ******************** */
-/* Step 1: Remove proxy nodes.
+/* Remove proxy nodes.
+ *
* These only exists temporarily when exporting groups, and we must remove them
* early so that node->attributes() and default links do not see them.
*/
@@ -493,7 +494,8 @@ void ShaderGraph::remove_proxy_nodes()
}
}
-/* Step 2: Constant folding.
+/* Constant folding.
+ *
* Try to constant fold some nodes, and pipe result directly to
* the input socket of connected nodes.
*/
@@ -554,7 +556,7 @@ void ShaderGraph::constant_fold()
}
}
-/* Step 3: Simplification. */
+/* Simplification. */
void ShaderGraph::simplify_settings(Scene *scene)
{
foreach(ShaderNode *node, nodes) {
@@ -562,7 +564,7 @@ void ShaderGraph::simplify_settings(Scene *scene)
}
}
-/* Step 4: Deduplicate nodes with same settings. */
+/* Deduplicate nodes with same settings. */
void ShaderGraph::deduplicate_nodes()
{
/* NOTES:
@@ -638,6 +640,48 @@ void ShaderGraph::deduplicate_nodes()
}
}
+/* Check whether volume output has meaningful nodes, otherwise
+ * disconnect the output.
+ */
+void ShaderGraph::verify_volume_output()
+{
+ /* Check whether we can optimize the whole volume graph out. */
+ ShaderInput *volume_in = output()->input("Volume");
+ if(volume_in->link == NULL) {
+ return;
+ }
+ bool has_valid_volume = false;
+ ShaderNodeSet scheduled;
+ queue<ShaderNode*> traverse_queue;
+ /* Schedule volume output. */
+ traverse_queue.push(volume_in->link->parent);
+ scheduled.insert(volume_in->link->parent);
+ /* Traverse down the tree. */
+ while(!traverse_queue.empty()) {
+ ShaderNode *node = traverse_queue.front();
+ traverse_queue.pop();
+ /* Node is fully valid for volume, can't optimize anything out. */
+ if(node->has_volume_support()) {
+ has_valid_volume = true;
+ break;
+ }
+ foreach(ShaderInput *input, node->inputs) {
+ if(input->link == NULL) {
+ continue;
+ }
+ if(scheduled.find(input->link->parent) != scheduled.end()) {
+ continue;
+ }
+ traverse_queue.push(input->link->parent);
+ scheduled.insert(input->link->parent);
+ }
+ }
+ if(!has_valid_volume) {
+ VLOG(1) << "Disconnect meaningless volume output.";
+ disconnect(volume_in->link);
+ }
+}
+
void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack)
{
visited[node->id] = true;
@@ -666,16 +710,11 @@ void ShaderGraph::clean(Scene *scene)
{
/* Graph simplification */
- /* 1: Remove proxy nodes was already done. */
-
- /* 2: Constant folding. */
+ /* NOTE: Remove proxy nodes was already done. */
constant_fold();
-
- /* 3: Simplification. */
simplify_settings(scene);
-
- /* 4: De-duplication. */
deduplicate_nodes();
+ verify_volume_output();
/* we do two things here: find cycles and break them, and remove unused
* nodes that don't feed into the output. how cycles are broken is
@@ -998,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/graph.h b/intern/cycles/render/graph.h
index 09932695d1f..72e391991a7 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -155,7 +155,7 @@ public:
virtual bool has_spatial_varying() { return false; }
virtual bool has_object_dependency() { return false; }
virtual bool has_integrator_dependency() { return false; }
-
+ virtual bool has_volume_support() { return false; }
vector<ShaderInput*> inputs;
vector<ShaderOutput*> outputs;
@@ -284,6 +284,7 @@ protected:
void constant_fold();
void simplify_settings(Scene *scene);
void deduplicate_nodes();
+ void verify_volume_output();
};
CCL_NAMESPACE_END
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 a755b653a5b..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)
@@ -445,6 +478,7 @@ public:
virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; }
bool has_surface_emission() { return true; }
+ bool has_volume_support() { return true; }
float3 color;
float strength;
@@ -496,6 +530,7 @@ public:
return ShaderNode::get_feature() | NODE_FEATURE_VOLUME;
}
virtual ClosureType get_closure_type() { return closure; }
+ virtual bool has_volume_support() { return true; }
float3 color;
float density;
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 3f05620fcf6..43679727992 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -1238,7 +1238,6 @@ class CLIP_MT_view(Menu):
layout.prop(sc, "show_seconds")
layout.prop(sc, "show_locked_time")
- layout.separator()
layout.separator()
layout.operator("screen.area_dupli")
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index fd071c506ad..d7d20bda016 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1699,7 +1699,7 @@ class VIEW3D_MT_brush(Menu):
layout = self.layout
settings = UnifiedPaintPanel.paint_settings(context)
- brush = settings.brush
+ brush = getattr(settings, "brush", None)
ups = context.tool_settings.unified_paint_settings
layout.prop(ups, "use_unified_size", text="Unified Size")
@@ -1708,6 +1708,11 @@ class VIEW3D_MT_brush(Menu):
layout.prop(ups, "use_unified_color", text="Unified Color")
layout.separator()
+ # skip if no active brush
+ if not brush:
+ layout.label(text="No Brushes currently available", icon="INFO")
+ return
+
# brush paint modes
layout.menu("VIEW3D_MT_brush_paint_modes")
@@ -1720,10 +1725,6 @@ class VIEW3D_MT_brush(Menu):
elif context.vertex_paint_object or context.weight_paint_object:
layout.prop_menu_enum(brush, "vertex_tool")
- # skip if no active brush
- if not brush:
- return
-
# TODO: still missing a lot of brush options here
# sculpt options
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 517a0738b44..bee6ae80590 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -226,6 +226,7 @@ shader_node_categories = [
NodeItem("ShaderNodeMixShader"),
NodeItem("ShaderNodeAddShader"),
NodeItem("ShaderNodeBsdfDiffuse", poll=object_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfPrincipled", poll=object_shader_nodes_poll),
NodeItem("ShaderNodeBsdfGlossy", poll=object_shader_nodes_poll),
NodeItem("ShaderNodeBsdfTransparent", poll=object_shader_nodes_poll),
NodeItem("ShaderNodeBsdfRefraction", poll=object_shader_nodes_poll),
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 78d6f6c7cb9..23bb526073b 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -177,6 +177,7 @@ void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
struct bPoseChannel *pchan);
void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 193f1154c54..7544e8f5b3e 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -785,6 +785,7 @@ struct ShadeResult;
#define SH_NODE_OUTPUT_LINESTYLE 190
#define SH_NODE_UVALONGSTROKE 191
#define SH_NODE_TEX_POINTDENSITY 192
+#define SH_NODE_BSDF_PRINCIPLED 193
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 3bc81a69c86..df0bddede3b 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -628,10 +628,10 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
}
void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
Object *ob,
bPoseChannel *pchan)
{
- Scene *scene = G.main->scene.first;
DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index f3223e31b17..63da1b5f9e7 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -3568,6 +3568,7 @@ static void registerShaderNodes(void)
register_node_type_sh_background();
register_node_type_sh_bsdf_anisotropic();
register_node_type_sh_bsdf_diffuse();
+ register_node_type_sh_bsdf_principled();
register_node_type_sh_bsdf_glossy();
register_node_type_sh_bsdf_glass();
register_node_type_sh_bsdf_translucent();
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
index 551143f5d72..50c7a7f9f0f 100644
--- a/source/blender/blenlib/BLI_hash.h
+++ b/source/blender/blenlib/BLI_hash.h
@@ -25,7 +25,7 @@
* \ingroup bli
*/
-static inline unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
+BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
{
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
@@ -48,7 +48,7 @@ static inline unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
#undef rot
}
-static inline unsigned int BLI_hash_string(const char *str)
+BLI_INLINE unsigned int BLI_hash_string(const char *str)
{
unsigned int i = 0, c;
@@ -58,7 +58,7 @@ static inline unsigned int BLI_hash_string(const char *str)
return i;
}
-static inline unsigned int BLI_hash_int(unsigned int k)
+BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
{
return BLI_hash_int_2d(k, 0);
}
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index b6a55d34d14..b59e7f99d59 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -44,7 +44,7 @@ void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
void BLI_make_exist(char *dir);
-void BLI_make_existing_file(const char *name);
+bool BLI_make_existing_file(const char *name);
void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
void BLI_split_file_part(const char *string, char *file, const size_t filelen);
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 7b765cfa939..40b6aaa18c1 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -1234,14 +1234,16 @@ void BLI_make_exist(char *dir)
/**
* Ensures that the parent directory of *name exists.
+ *
+ * \return true on success (i.e. given path now exists on FS), false otherwise.
*/
-void BLI_make_existing_file(const char *name)
+bool BLI_make_existing_file(const char *name)
{
char di[FILE_MAX];
BLI_split_dir_part(name, di, sizeof(di));
/* make if the dir doesn't exist */
- BLI_dir_create_recursive(di);
+ return BLI_dir_create_recursive(di);
}
/**
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 10b586342dd..745f8283328 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -130,7 +130,7 @@ struct DepsgraphNodeBuilder {
void build_object(Scene *scene, Base *base, Object *ob);
void build_object_transform(Scene *scene, Object *ob);
void build_object_constraints(Scene *scene, Object *ob);
- void build_pose_constraints(Object *ob, bPoseChannel *pchan);
+ void build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
void build_cloth(Scene *scene, Object *object);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index f2437ce1fac..e307909cb11 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -64,11 +64,12 @@ extern "C" {
namespace DEG {
-void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
+void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan)
{
/* create node for constraint stack */
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
+ DEPSOP_TYPE_EXEC,
+ function_bind(BKE_pose_constraints_evaluate, _1, scene, ob, pchan),
DEG_OPCODE_BONE_CONSTRAINTS);
}
@@ -201,7 +202,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
/* constraints */
if (pchan->constraints.first != NULL) {
- build_pose_constraints(ob, pchan);
+ build_pose_constraints(scene, ob, pchan);
}
/**
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 4f1ff1eb013..3897fe8630b 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -485,7 +485,8 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
bGPdata *gpd = p->gpd;
bGPDbrush *brush = p->brush;
tGPspoint *pt;
-
+ ToolSettings *ts = p->scene->toolsettings;
+
/* check painting mode */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only - i.e. only store start and end point in buffer */
@@ -638,7 +639,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(p->scene, p->wm, p->win, p->ar, v3d,
- (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
+ (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
@@ -758,7 +759,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
- int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0;
+ int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
/* get total number of points to allocate space for
* - drawing straight-lines only requires the endpoints
@@ -912,7 +913,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
depth_arr[i] = 0.9999f;
}
else {
- if (p->gpd->flag & GP_DATA_DEPTH_STROKE_ENDPOINTS) {
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
/* remove all info between the valid endpoints */
int first_valid = 0;
int last_valid = 0;
@@ -1797,6 +1798,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
static void gp_paint_strokeend(tGPsdata *p)
{
+ ToolSettings *ts = p->scene->toolsettings;
/* for surface sketching, need to set the right OpenGL context stuff so that
* the conversions will project the values correctly...
*/
@@ -1806,7 +1808,7 @@ static void gp_paint_strokeend(tGPsdata *p)
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(p->scene, p->wm, p->win, p->ar, v3d,
- (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
+ (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* check if doing eraser or not */
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index b5adf38527b..6460e83e2a0 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -631,71 +631,63 @@ static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDom
#define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp")
#define FLUID_SUFFIX_SURFACE "fluidsurface"
-static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer)
+static bool fluid_init_filepaths(
+ ReportList *reports, FluidsimSettings *domainSettings, Object *fsDomain,
+ char *targetDir, char *targetFile)
{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
- FluidsimSettings *domainSettings= fluidmd->fss;
- FILE *fileCfg;
- int dirExist = 0;
- char newSurfdataPath[FILE_MAX]; /* modified output settings */
const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
- int outStringsChanged = 0;
/* prepare names... */
- const char *relbase= modifier_path_relbase(fsDomain);
+ const char *relbase = modifier_path_relbase(fsDomain);
+
+ /* We do not accept empty paths, they can end in random places silently, see T51176. */
+ if (domainSettings->surfdataPath[0] == '\0') {
+ modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath),
+ OB_FLUIDSIM_SURF_DIR_DEFAULT);
+ BKE_reportf(reports, RPT_WARNING, "Fluidsim: empty cache path, reset to default '%s'",
+ domainSettings->surfdataPath);
+ }
BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); /* if 0'd out below, this value is never used! */
- BLI_path_abs(targetDir, relbase); /* fixed #frame-no */
+ BLI_path_abs(targetDir, relbase);
/* .tmp: don't overwrite/delete original file */
BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
- // make sure all directories exist
- // as the bobjs use the same dir, this only needs to be checked
- // for the cfg output
- BLI_make_existing_file(targetFile);
-
- // check selected directory
- // simply try to open cfg file for writing to test validity of settings
- fileCfg = BLI_fopen(targetFile, "w");
- if (fileCfg) {
- dirExist = 1; fclose(fileCfg);
- // remove cfg dummy from directory test
- BLI_delete(targetFile, false, false);
- }
-
- if (targetDir[0] == '\0' || (!dirExist)) {
- char blendFile[FILE_MAX];
-
- // invalid dir, reset to current/previous
- BLI_split_file_part(G.main->name, blendFile, sizeof(blendFile));
- BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */
- BLI_snprintf(newSurfdataPath, FILE_MAX, "//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
-
- BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
- elbeemDebugOut(debugStrBuffer);
- outStringsChanged=1;
- }
-
- /* check if modified output dir is ok */
-#if 0
- if (outStringsChanged) {
- char dispmsg[FILE_MAX+256];
- int selection=0;
- BLI_strncpy(dispmsg, "Output settings set to: '", sizeof(dispmsg));
- strcat(dispmsg, newSurfdataPath);
- strcat(dispmsg, "'%t|Continue with changed settings %x1|Discard and abort %x0");
-
- /* ask user if thats what he/she wants... */
- selection = pupmenu(dispmsg);
- if (selection < 1) return 0; /* 0 from menu, or -1 aborted */
- BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir));
- strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, G.main->name); /* fixed #frame-no */
+ /* Ensure whole path exists and is wirtable. */
+ const bool dir_exists = BLI_dir_create_recursive(targetDir);
+ const bool is_writable = BLI_file_is_writable(targetFile);
+
+ /* We change path to some presumably valid default value, but do not allow bake process to continue,
+ * this gives user chance to set manually another path. */
+ if (!dir_exists || !is_writable) {
+ modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath),
+ OB_FLUIDSIM_SURF_DIR_DEFAULT);
+
+ if (!dir_exists) {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not create cache directory '%s', reset to default '%s'",
+ targetDir, domainSettings->surfdataPath);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: cache directory '%s' is not writable, reset to default '%s'",
+ targetDir, domainSettings->surfdataPath);
+ }
+
+ BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
+ BLI_path_abs(targetDir, relbase);
+
+ /* .tmp: don't overwrite/delete original file */
+ BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
+
+ /* Ensure whole path exists and is wirtable. */
+ if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not use default cache directory '%s', "
+ "please define a valid cache path manually", targetDir);
+ }
+ return false;
}
-#endif
- return outStringsChanged;
+
+ return true;
}
/* ******************************************************************************** */
@@ -857,7 +849,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
char targetDir[FILE_MAX]; // store & modify output settings
char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
- int outStringsChanged = 0; // modified? copy back before baking
float domainMat[4][4];
float invDomMat[4][4];
@@ -943,7 +934,11 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* ******** prepare output file paths ******** */
- outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer);
+ if (!fluid_init_filepaths(reports, domainSettings, fsDomain, targetDir, targetFile)) {
+ fluidbake_free_data(channels, fobjects, fsset, fb);
+ return false;
+ }
+
channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra)
channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames;
@@ -968,11 +963,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* ******** start writing / exporting ******** */
// use .tmp, don't overwrite/delete original file
BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
-
- // make sure these directories exist as well
- if (outStringsChanged) {
- BLI_make_existing_file(targetFile);
- }
/* ******** export domain to elbeem ******** */
elbeemResetSettings(fsset);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index e4f5802a395..8dba0e39524 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1234,6 +1234,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_BSDF_GLOSSY:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_REFRACTION:
+ case SH_NODE_BSDF_PRINCIPLED:
ntype->draw_buttons = node_shader_buts_glossy;
break;
case SH_NODE_BSDF_ANISOTROPIC:
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index c354b274f00..b88fba12f55 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -2378,11 +2378,19 @@ void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
/*********** NEW SHADER UTILITIES **************/
-float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
+float fresnel_dielectric_0(float eta)
+{
+ /* compute fresnel reflactance at normal incidence => cosi = 1.0 */
+ float A = (eta - 1.0) / (eta + 1.0);
+
+ return A * A;
+}
+
+float fresnel_dielectric_cos(float cosi, float eta)
{
/* compute fresnel reflectance without explicitly computing
* the refracted direction */
- float c = abs(dot(Incoming, Normal));
+ float c = abs(cosi);
float g = eta * eta - 1.0 + c * c;
float result;
@@ -2399,6 +2407,13 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
return result;
}
+float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
+}
+
float hypot(float x, float y)
{
return sqrt(x * x + y * y);
@@ -2492,6 +2507,57 @@ float floorfrac(float x, out int i)
return x - i;
}
+
+/* Principled BSDF operations */
+
+float sqr(float a)
+{
+ return a*a;
+}
+
+float schlick_fresnel(float u)
+{
+ float m = clamp(1.0 - u, 0.0, 1.0);
+ float m2 = m * m;
+ return m2 * m2 * m; // pow(m,5)
+}
+
+float GTR1(float NdotH, float a)
+{
+ if (a >= 1.0) return M_1_PI;
+ float a2 = a*a;
+ float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
+ return (a2 - 1.0) / (M_PI * log(a2) * t);
+}
+
+float GTR2(float NdotH, float a)
+{
+ float a2 = a*a;
+ float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
+ return a2 / (M_PI * t*t);
+}
+
+float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
+{
+ return 1.0 / (M_PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH));
+}
+
+float smithG_GGX(float NdotV, float alphaG)
+{
+ float a = alphaG*alphaG;
+ float b = NdotV*NdotV;
+ return 1.0 / (NdotV + sqrt(a + b - a * b));
+}
+
+vec3 rotate_vector(vec3 p, vec3 n, float theta) {
+ return (
+ p * cos(theta) + cross(n, p) *
+ sin(theta) + n * dot(p, n) *
+ (1.0 - cos(theta))
+ );
+}
+
+
/*********** NEW SHADER NODES ***************/
#define NUM_LIGHTS 3
@@ -2553,6 +2619,126 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 resu
node_bsdf_diffuse(color, 0.0, N, result);
}
+void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+ float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+ float clearcoat_gloss, float ior, float transparency, float refraction_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
+{
+ /* ambient light */
+ // TODO: set ambient light to an appropriate value
+ vec3 L = vec3(mix(0.1, 0.03, metallic)) * base_color.rgb;
+
+ float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
+
+ /* set the viewing vector */
+ vec3 V = -normalize(I);
+
+ /* get the tangent */
+ vec3 Tangent = T;
+ if (T == vec3(0.0)) {
+ // if no tangent is set, use a default tangent
+ Tangent = vec3(1.0, 0.0, 0.0);
+ if (N.x != 0.0 || N.y != 0.0) {
+ vec3 N_xz = normalize(vec3(N.x, 0.0, N.z));
+
+ vec3 axis = normalize(cross(vec3(0.0, 0.0, 1.0), N_xz));
+ float angle = acos(dot(vec3(0.0, 0.0, 1.0), N_xz));
+
+ Tangent = normalize(rotate_vector(vec3(1.0, 0.0, 0.0), axis, angle));
+ }
+ }
+
+ /* rotate tangent */
+ if (anisotropic_rotation != 0.0) {
+ Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI);
+ }
+
+ /* calculate the tangent and bitangent */
+ vec3 Y = normalize(cross(N, Tangent));
+ vec3 X = cross(Y, N);
+
+ /* fresnel normalization parameters */
+ float F0 = fresnel_dielectric_0(eta);
+ float F0_norm = 1.0 / (1.0 - F0);
+
+ /* directional lights */
+ for (int i = 0; i < NUM_LIGHTS; i++) {
+ vec3 light_position_world = gl_LightSource[i].position.xyz;
+ vec3 light_position = normalize(gl_NormalMatrix * light_position_world);
+
+ vec3 H = normalize(light_position + V);
+
+ vec3 light_specular = gl_LightSource[i].specular.rgb;
+
+ float NdotL = dot(N, light_position);
+ float NdotV = dot(N, V);
+ float LdotH = dot(light_position, H);
+
+ vec3 diffuse_and_specular_bsdf = vec3(0.0);
+ if (NdotL >= 0.0 && NdotV >= 0.0) {
+ float NdotH = dot(N, H);
+
+ float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx.
+
+ vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat
+ vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic);
+ vec3 Csheen = mix(vec3(1.0), Ctint, sheen_tint);
+
+ // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
+ // and mix in diffuse retro-reflection based on roughness
+
+ float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV);
+ float Fd90 = 0.5 + 2.0 * LdotH*LdotH * roughness;
+ float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);
+
+ // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
+ // 1.25 scale is used to (roughly) preserve albedo
+ // Fss90 used to "flatten" retroreflection based on roughness
+ float Fss90 = LdotH*LdotH * roughness;
+ float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV);
+ float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5);
+
+ // specular
+ float aspect = sqrt(1.0 - anisotropic * 0.9);
+ float a = sqr(roughness);
+ float ax = max(0.001, a / aspect);
+ float ay = max(0.001, a * aspect);
+ float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a);
+ float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm;
+ vec3 Fs = mix(Cspec0, vec3(1.0), FH);
+ float roughg = sqr(roughness * 0.5 + 0.5);
+ float Gs = smithG_GGX(NdotL, roughg) * smithG_GGX(NdotV, roughg);
+
+ // sheen
+ vec3 Fsheen = schlick_fresnel(LdotH) * sheen * Csheen;
+
+ diffuse_and_specular_bsdf = (M_1_PI * mix(Fd, ss, subsurface) * base_color.rgb + Fsheen)
+ * (1.0 - metallic) + Gs * Fs * Ds;
+ }
+ diffuse_and_specular_bsdf *= max(NdotL, 0.0);
+
+ float CNdotL = dot(CN, light_position);
+ float CNdotV = dot(CN, V);
+
+ vec3 clearcoat_bsdf = vec3(0.0);
+ if (CNdotL >= 0.0 && CNdotV >= 0.0 && clearcoat > 0.0) {
+ float CNdotH = dot(CN, H);
+ //float FH = schlick_fresnel(LdotH);
+
+ // clearcoat (ior = 1.5 -> F0 = 0.04)
+ float Dr = GTR1(CNdotH, mix(0.1, 0.001, clearcoat_gloss));
+ float Fr = fresnel_dielectric_cos(LdotH, 1.5); //mix(0.04, 1.0, FH);
+ float Gr = smithG_GGX(CNdotL, 0.25) * smithG_GGX(CNdotV, 0.25);
+
+ clearcoat_bsdf = clearcoat * Gr * Fr * Dr * vec3(0.25);
+ }
+ clearcoat_bsdf *= max(CNdotL, 0.0);
+
+ L += light_specular * (diffuse_and_specular_bsdf + clearcoat_bsdf);
+ }
+
+ result = vec4(L, 1.0);
+}
+
void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h
index a714195dd5d..846d5788d63 100644
--- a/source/blender/makesdna/DNA_object_fluidsim.h
+++ b/source/blender/makesdna/DNA_object_fluidsim.h
@@ -179,6 +179,7 @@ typedef struct FluidsimSettings {
#define OB_FLUIDSIM_ACTIVE (1 << 1)
#define OB_FLUIDSIM_OVERRIDE_TIME (1 << 2)
+#define OB_FLUIDSIM_SURF_DIR_DEFAULT "cache_fluid"
#define OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME "fluidsurface_preview_####.bobj.gz"
#define OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME "fluidsurface_final_####.bobj.gz"
#define OB_FLUIDSIM_SURF_FINAL_VEL_FNAME "fluidsurface_final_####.bvel.gz"
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 6ed2c55138c..a74758a4f71 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -342,7 +342,7 @@ static void rna_ID_user_clear(ID *id)
static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
{
- if (GS(id->name) == GS(new_id->name)) {
+ if ((GS(id->name) == GS(new_id->name)) && (id != new_id)) {
/* For now, do not allow remapping data in linked data from here... */
BKE_libblock_remap(bmain, id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
}
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 8d42d746e1c..c3477644979 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2995,6 +2995,15 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
ED_node_tag_update_nodetree(bmain, ntree, node);
}
+static void rna_ShaderNodePrincipled_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNodeTree *ntree = (bNodeTree *)ptr->id.data;
+ bNode *node = (bNode *)ptr->data;
+
+ nodeUpdate(ntree, node);
+ rna_Node_update(bmain, scene, ptr);
+}
+
static void rna_ShaderNodeSubsurface_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
@@ -3254,6 +3263,12 @@ static EnumPropertyItem node_script_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static EnumPropertyItem node_principled_distribution_items[] = {
+ { SHD_GLOSSY_GGX, "GGX", 0, "GGX", "" },
+ { SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
/* -- Common nodes ---------------------------------------------------------- */
static void def_group_input(StructRNA *srna)
@@ -4188,6 +4203,17 @@ static void def_glass(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_principled(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_principled_distribution_items);
+ RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodePrincipled_update");
+}
+
static void def_refraction(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 55852139065..9b9f0705bb4 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -321,60 +321,51 @@ static void rna_Object_ray_cast(
float origin[3], float direction[3], float distance,
int *r_success, float r_location[3], float r_normal[3], int *r_index)
{
+ bool success = false;
+
if (ob->derivedFinal == NULL) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2);
return;
}
- *r_success = false;
-
/* Test BoundBox first (efficiency) */
BoundBox *bb = BKE_object_boundbox_get(ob);
- if (bb) {
- float distmin, distmax;
- if (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, &distmax)) {
- float dist = distmin >= 0 ? distmin : distmax;
- if (dist > distance) {
- goto finally;
- }
- }
- else {
- goto finally;
- }
- }
+ float distmin;
+ if (!bb || (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) {
- BVHTreeFromMesh treeData = {NULL};
+ BVHTreeFromMesh treeData = {NULL};
- /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
- bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
+ /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
+ bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
- /* may fail if the mesh has no faces, in that case the ray-cast misses */
- if (treeData.tree != NULL) {
- BVHTreeRayHit hit;
+ /* may fail if the mesh has no faces, in that case the ray-cast misses */
+ if (treeData.tree != NULL) {
+ BVHTreeRayHit hit;
- hit.index = -1;
- hit.dist = distance;
-
- normalize_v3(direction);
+ hit.index = -1;
+ hit.dist = distance;
+ normalize_v3(direction);
- if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
- treeData.raycast_callback, &treeData) != -1)
- {
- if (hit.dist <= distance) {
- *r_success = true;
- copy_v3_v3(r_location, hit.co);
- copy_v3_v3(r_normal, hit.no);
- *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
+ if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
+ treeData.raycast_callback, &treeData) != -1)
+ {
+ if (hit.dist <= distance) {
+ *r_success = success = true;
+
+ copy_v3_v3(r_location, hit.co);
+ copy_v3_v3(r_normal, hit.no);
+ *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
+ }
}
- }
- free_bvhtree_from_mesh(&treeData);
+ free_bvhtree_from_mesh(&treeData);
+ }
}
+ if (success == false) {
+ *r_success = false;
- if (*r_success == false) {
-finally:
zero_v3(r_location);
zero_v3(r_normal);
*r_index = -1;
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index ffbbb1b0745..2ecf06057db 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -78,8 +78,8 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
fss->resolutionxyz = 65;
fss->previewresxyz = 45;
fss->realsize = 0.5;
- fss->guiDisplayMode = 2; // preview
- fss->renderDisplayMode = 3; // render
+ fss->guiDisplayMode = OB_FSDOM_PREVIEW;
+ fss->renderDisplayMode = OB_FSDOM_FINAL;
fss->viscosityValue = 1.0;
fss->viscosityExponent = 6;
@@ -98,7 +98,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
/* fluid/inflow settings
* fss->iniVel --> automatically set to 0 */
- modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), "cache_fluid");
+ modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT);
/* first init of bounding box */
/* no bounding box needed */
@@ -423,8 +423,6 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *
static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
{
- int displaymode = 0;
-
int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */
/* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway. (See physics_fluid.c for that. - DG */
/* If we start with frame 0, we need to remap all animation channels, too, because they will all be 1 frame late if using frame-1! - DG */
@@ -435,25 +433,23 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
MPoly *mpoly;
MPoly mp_example = {0};
- if (!useRenderParams) {
- displaymode = fss->guiDisplayMode;
- }
- else {
- displaymode = fss->renderDisplayMode;
- }
+ const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode;
switch (displaymode) {
- case 1:
+ case OB_FSDOM_GEOM:
/* just display original object */
return NULL;
- case 2:
+ case OB_FSDOM_PREVIEW:
/* use preview mesh */
BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
break;
- default: /* 3 */
- /* 3. use final mesh */
+ case OB_FSDOM_FINAL:
+ /* use final mesh */
BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
break;
+ default:
+ BLI_assert(!"Wrong fluidsim display type");
+ return NULL;
}
/* offset baked frame */
@@ -494,7 +490,7 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
/* load vertex velocities, if they exist...
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */
- if (displaymode == 3) {
+ if (displaymode == OB_FSDOM_FINAL) {
fluidsim_read_vel_cache(fluidmd, dm, targetFile);
}
else {
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index d20881df150..3596a2aa12d 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -163,6 +163,7 @@ set(SRC
shader/nodes/node_shader_background.c
shader/nodes/node_shader_bsdf_anisotropic.c
shader/nodes/node_shader_bsdf_diffuse.c
+ shader/nodes/node_shader_bsdf_principled.c
shader/nodes/node_shader_bsdf_glass.c
shader/nodes/node_shader_bsdf_glossy.c
shader/nodes/node_shader_bsdf_toon.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 4c0047f1d58..804c1897a27 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -106,6 +106,7 @@ void register_node_type_sh_bsdf_transparent(void);
void register_node_type_sh_bsdf_velvet(void);
void register_node_type_sh_bsdf_toon(void);
void register_node_type_sh_bsdf_anisotropic(void);
+void register_node_type_sh_bsdf_principled(void);
void register_node_type_sh_emission(void);
void register_node_type_sh_holdout(void);
void register_node_type_sh_volume_absorption(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index a9c0df7d7e8..e754d063397 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -80,6 +80,7 @@ DefNode( ShaderNode, SH_NODE_BACKGROUND, 0, "BA
DefNode( ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" )
DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
new file mode 100644
index 00000000000..8b0bfa36324
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -0,0 +1,114 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
+ { SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f},
+ { SOCK_RGBA, 1, N_("Subsurface Color"), 0.7f, 0.1f, 0.1f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Specular Tint"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Anisotropic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Anisotropic Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Sheen"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Sheen Tint"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Clearcoat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Clearcoat Gloss"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_FLOAT, 1, N_("Transparency"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Refraction Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { SOCK_VECTOR, 1, N_("Clearcoat Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { SOCK_VECTOR, 1, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_bsdf_principled_out[] = {
+ { SOCK_SHADER, 0, N_("BSDF")},
+ { -1, 0, "" }
+};
+
+static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_MULTI_GGX;
+}
+
+static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ // normal
+ if (!in[17].link)
+ in[17].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link);
+
+ // clearcoat normal
+ if (!in[18].link)
+ in[18].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link);
+
+ return GPU_stack_link(mat, "node_bsdf_principled", in, out, GPU_builtin(GPU_VIEW_POSITION));
+}
+
+static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock;
+ int distribution = node->custom1;
+
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Refraction Roughness")) {
+ if (distribution == SHD_GLOSSY_GGX)
+ sock->flag &= ~SOCK_UNAVAIL;
+ else
+ sock->flag |= SOCK_UNAVAIL;
+
+ }
+ }
+}
+
+/* node type definition */
+void register_node_type_sh_bsdf_principled(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, node_shader_init_principled);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_bsdf_principled);
+ node_type_update(&ntype, node_shader_update_principled, NULL);
+
+ nodeRegisterType(&ntype);
+}