Fix random walk SSS issues with different base and subsurface color.
[blender-staging.git] / intern / cycles / kernel / shaders / node_principled_bsdf.osl
1 /*
2  * Copyright 2011-2017 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "stdosl.h"
18 #include "node_fresnel.h"
19
20 shader node_principled_bsdf(
21         string distribution = "Multiscatter GGX",
22         string subsurface_method = "burley",
23         color BaseColor = color(0.8, 0.8, 0.8),
24         float Subsurface = 0.0,
25         vector SubsurfaceRadius = vector(1.0, 1.0, 1.0),
26         color SubsurfaceColor = color(0.7, 0.1, 0.1),
27         float Metallic = 0.0,
28         float Specular = 0.5,
29         float SpecularTint = 0.0,
30         float Roughness = 0.5,
31         float Anisotropic = 0.0,
32         float AnisotropicRotation = 0.0,
33         float Sheen = 0.0,
34         float SheenTint = 0.5,
35         float Clearcoat = 0.0,
36         float ClearcoatRoughness = 0.03,
37         float IOR = 1.45,
38         float Transmission = 0.0,
39         float TransmissionRoughness = 0.0,
40         normal Normal = N,
41         normal ClearcoatNormal = N,
42         normal Tangent = normalize(dPdu),
43         output closure color BSDF = 0)
44 {
45         float f = max(IOR, 1e-5);
46         float diffuse_weight = (1.0 - clamp(Metallic, 0.0, 1.0)) * (1.0 - clamp(Transmission, 0.0, 1.0));
47         float final_transmission = clamp(Transmission, 0.0, 1.0) * (1.0 - clamp(Metallic, 0.0, 1.0));
48         float specular_weight = (1.0 - final_transmission);
49
50         vector T = Tangent;
51
52         float m_cdlum = luminance(BaseColor);
53         color m_ctint = m_cdlum > 0.0 ? BaseColor / m_cdlum : color(0.0, 0.0, 0.0); // normalize lum. to isolate hue+sat
54
55         /* rotate tangent */
56         if (AnisotropicRotation != 0.0)
57                 T = rotate(T, AnisotropicRotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
58
59         if (diffuse_weight > 1e-5) {
60                 if (Subsurface > 1e-5) {
61                         color mixed_ss_base_color = SubsurfaceColor * Subsurface + BaseColor * (1.0 - Subsurface);
62                         if (subsurface_method == "burley") {
63                                 BSDF = mixed_ss_base_color * bssrdf("principled", Normal, Subsurface * SubsurfaceRadius, SubsurfaceColor, "roughness", Roughness);
64                         }
65                         else {
66                                 BSDF = mixed_ss_base_color * bssrdf("principled_random_walk", Normal, Subsurface * SubsurfaceRadius, mixed_ss_base_color, "roughness", Roughness);
67                         }
68                 }
69                 else {
70                         BSDF = BaseColor * principled_diffuse(Normal, Roughness);
71                 }
72
73                 if (Sheen > 1e-5) {
74                         color sheen_color = color(1.0, 1.0, 1.0) * (1.0 - SheenTint) + m_ctint * SheenTint;
75
76                         BSDF = BSDF + sheen_color * Sheen * principled_sheen(Normal);
77                 }
78
79                 BSDF = BSDF * diffuse_weight;
80         }
81
82         if (specular_weight > 1e-5) {
83                 float aspect = sqrt(1.0 - Anisotropic * 0.9);
84                 float r2 = Roughness * Roughness;
85
86                 float alpha_x = r2 / aspect;
87                 float alpha_y = r2 * aspect;
88
89                 color tmp_col = color(1.0, 1.0, 1.0) * (1.0 - SpecularTint) + m_ctint * SpecularTint;
90
91                 color Cspec0 = (Specular * 0.08 * tmp_col) * (1.0 - Metallic) + BaseColor * Metallic;
92
93                 if (distribution == "GGX" || Roughness <= 0.075) {
94                         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);
95                 } else {
96                         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);
97                 }
98         }
99
100         if (final_transmission > 1e-5) {
101                 color Cspec0 = BaseColor * SpecularTint + color(1.0, 1.0, 1.0) * (1.0 - SpecularTint);
102                 float eta = backfacing() ? 1.0 / f : f;
103
104                 if (distribution == "GGX" || Roughness <= 5e-2) {
105                         float cosNO = dot(Normal, I);
106                         float Fr = fresnel_dielectric_cos(cosNO, eta);
107
108                         float refl_roughness = Roughness;
109                         if (Roughness <= 1e-2)
110                                 refl_roughness = 0.0;
111
112                         float transmission_roughness = refl_roughness;
113                         if (distribution == "GGX")
114                                 transmission_roughness = 1.0 - (1.0 - refl_roughness) * (1.0 - TransmissionRoughness);
115
116                         BSDF = BSDF + final_transmission * (Fr * microfacet_ggx_fresnel(Normal, refl_roughness * refl_roughness, eta, BaseColor, Cspec0) +
117                                (1.0 - Fr) * BaseColor * microfacet_ggx_refraction(Normal, transmission_roughness * transmission_roughness, eta));
118                 } else {
119                         BSDF = BSDF + final_transmission * microfacet_multi_ggx_glass_fresnel(Normal, Roughness * Roughness, eta, BaseColor, Cspec0);
120                 }
121         }
122
123         if (Clearcoat > 1e-5) {
124                 BSDF = BSDF + principled_clearcoat(ClearcoatNormal, Clearcoat, ClearcoatRoughness * ClearcoatRoughness);
125         }
126 }
127