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

gpu_shader_material_principled.glsl « material « shaders « gpu « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: bba84c2be52ca08b8414336952266dbc416329a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#ifndef VOLUMETRICS
vec3 tint_from_color(vec3 color)
{
  float lum = dot(color, vec3(0.3, 0.6, 0.1));  /* luminance approx. */
  return (lum > 0.0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
}

float principled_sheen(float NV)
{
  float f = 1.0 - NV;
  /* Empirical approximation (manual curve fitting). Can be refined. */
  float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
  return sheen;
}

CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction)

void node_bsdf_principled(vec4 base_color,
                          float subsurface,
                          vec3 subsurface_radius,
                          vec4 subsurface_color,
                          float subsurface_ior,
                          float subsurface_anisotropy,
                          float metallic,
                          float specular,
                          float specular_tint,
                          float roughness,
                          float anisotropic,
                          float anisotropic_rotation,
                          float sheen,
                          float sheen_tint,
                          float clearcoat,
                          float clearcoat_roughness,
                          float ior,
                          float transmission,
                          float transmission_roughness,
                          vec4 emission,
                          float emission_strength,
                          float alpha,
                          vec3 N,
                          vec3 CN,
                          vec3 T,
                          const float do_diffuse,
                          const float do_clearcoat,
                          const float do_refraction,
                          const float do_multiscatter,
                          float ssr_id,
                          float sss_id,
                          vec3 sss_scale,
                          out Closure result)
{
  /* Match cycles. */
  metallic = saturate(metallic);
  transmission = saturate(transmission);
  float diffuse_weight = (1.0 - transmission) * (1.0 - metallic);
  transmission *= (1.0 - metallic);
  float specular_weight = (1.0 - transmission);
  clearcoat = max(clearcoat, 0.0);
  transmission_roughness = 1.0 - (1.0 - roughness) * (1.0 - transmission_roughness);
  specular = max(0.0, specular);

  CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);

  in_Diffuse_0.N = N; /* Normalized during eval. */
  in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface);

  in_Glossy_1.N = N; /* Normalized during eval. */
  in_Glossy_1.roughness = roughness;

  in_Glossy_2.N = CN; /* Normalized during eval. */
  in_Glossy_2.roughness = clearcoat_roughness;

  in_Refraction_3.N = N; /* Normalized during eval. */
  in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness;
  in_Refraction_3.ior = ior;

  CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction);

  result = CLOSURE_DEFAULT;

  /* This will tag the whole eval for optimisation. */
  if (do_diffuse == 0.0) {
    out_Diffuse_0.radiance = vec3(0);
  }
  if (do_clearcoat == 0.0) {
    out_Glossy_2.radiance = vec3(0);
  }
  if (do_refraction == 0.0) {
    out_Refraction_3.radiance = vec3(0);
  }

  vec3 V = cameraVec(worldPosition);

  /* Glossy_1 will always be evaluated. */
  float NV = dot(in_Glossy_1.N, V);

  vec3 base_color_tint = tint_from_color(base_color.rgb);

  float fresnel = (do_multiscatter != 0.0) ?
                      btdf_lut(NV, in_Glossy_1.roughness, in_Refraction_3.ior).y :
                      F_eta(in_Refraction_3.ior, NV);

  {
    /* Glossy reflections.
     * Separate Glass reflections and main specular reflections to match Cycles renderpasses. */
    out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);

    vec2 split_sum = brdf_lut(NV, roughness);

    vec3 glossy_radiance_final = vec3(0.0);
    if (transmission > 1e-5) {
      /* Glass Reflection: Reuse radiance from Glossy1. */
      vec3 out_glass_refl_radiance = out_Glossy_1.radiance;

      /* Poor approximation since we baked the LUT using a fixed IOR. */
      vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
      vec3 f90 = vec3(1);

      vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
                                             F_brdf_single_scatter(f0, f90, split_sum);

      out_glass_refl_radiance *= brdf;
      out_glass_refl_radiance = render_pass_glossy_mask(vec3(1), out_glass_refl_radiance);
      out_glass_refl_radiance *= fresnel * transmission;
      glossy_radiance_final += out_glass_refl_radiance;
    }
    if (specular_weight > 1e-5) {
      vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint);
      vec3 metallic_f0_color = base_color.rgb;
      vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic);
      /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel
       * is already baked inside the split sum LUT. We approximate using by modifying the
       * changing the f90 color directly in a non linear fashion. */
      vec3 f90 = mix(f0, vec3(1), fast_sqrt(specular));

      vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
                                             F_brdf_single_scatter(f0, f90, split_sum);

      out_Glossy_1.radiance *= brdf;
      out_Glossy_1.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_1.radiance);
      out_Glossy_1.radiance *= specular_weight;
      glossy_radiance_final += out_Glossy_1.radiance;
    }

    closure_load_ssr_data(
        glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
  }

  if (diffuse_weight > 1e-5) {
    /* Mask over all diffuse radiance. */
    out_Diffuse_0.radiance *= diffuse_weight;

    /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
    vec3 sheen_color = mix(vec3(1), base_color_tint, sheen_tint);
    vec3 out_sheen_radiance = out_Diffuse_0.radiance * principled_sheen(NV);
    out_sheen_radiance = render_pass_diffuse_mask(vec3(1), out_sheen_radiance);
    out_sheen_radiance *= sheen * sheen_color;
    result.radiance += out_sheen_radiance;

    /* Diffuse / Subsurface. */
    float scale = avg(sss_scale) * subsurface;
    closure_load_sss_data(scale, out_Diffuse_0.radiance, in_Diffuse_0.albedo, int(sss_id), result);
  }

  if (transmission > 1e-5) {
    float btdf = (do_multiscatter != 0.0) ?
                     1.0 :
                     btdf_lut(NV, in_Refraction_3.roughness, in_Refraction_3.ior).x;
    /* TODO(fclem) This could be going to a transmission render pass instead. */
    out_Refraction_3.radiance *= btdf;
    out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance);
    out_Refraction_3.radiance *= base_color.rgb;
    /* Simulate 2nd transmission event. */
    out_Refraction_3.radiance *= (refractionDepth > 0.0) ? base_color.rgb : vec3(1);
    out_Refraction_3.radiance *= (1.0 - fresnel) * transmission;
    result.radiance += out_Refraction_3.radiance;
  }

  if (clearcoat > 1e-5) {
    float NV = dot(in_Glossy_2.N, V);
    vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
    vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);

    out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
    out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
    result.radiance += out_Glossy_2.radiance;
  }

  {
    vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
    out_emission_radiance *= emission_strength;
    result.radiance += out_emission_radiance;
  }

  result.transmittance = vec3(1.0 - alpha);
  result.radiance *= alpha;
  result.ssr_data.rgb *= alpha;
#  ifdef USE_SSS
  result.sss_albedo *= alpha;
#  endif
}

#else
/* clang-format off */
/* Stub principled because it is not compatible with volumetrics. */
#  define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, cc, dd, ee, ff, result) (result = CLOSURE_DEFAULT)
/* clang-format on */
#endif