Blender V4.3
bsdf_oren_nayar.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
8
17
18static_assert(sizeof(ShaderClosure) >= sizeof(OrenNayarBsdf), "OrenNayarBsdf is too large!");
19
20/* NOTE: This implements the improved Oren-Nayar model by Yasuhiro Fujii
21 * (https://mimosa-pudica.net/improved-oren-nayar.html), plus an
22 * energy-preserving multi-scattering term based on the OpenPBR specification
23 * (https://academysoftwarefoundation.github.io/OpenPBR). */
24
25ccl_device_inline float bsdf_oren_nayar_G(const float cosTheta)
26{
27 if (cosTheta < 1e-6f) {
28 /* The tan(theta) term starts to act up at low cosTheta, so fall back to Taylor expansion. */
29 return (M_PI_2_F - 2.0f / 3.0f) - cosTheta;
30 }
31 const float sinTheta = sin_from_cos(cosTheta);
32 const float theta = safe_acosf(cosTheta);
33 return sinTheta * (theta - 2.0f / 3.0f - sinTheta * cosTheta) +
34 2.0f / 3.0f * (sinTheta / cosTheta) * (1.0f - sqr(sinTheta) * sinTheta);
35}
36
38 float3 n,
39 float3 v,
40 float3 l)
41{
42 ccl_private const OrenNayarBsdf *bsdf = (ccl_private const OrenNayarBsdf *)sc;
43 float nl = max(dot(n, l), 0.0f);
44 float nv = max(dot(n, v), 0.0f);
45 float t = dot(l, v) - nl * nv;
46
47 if (t > 0.0f)
48 t /= max(nl, nv) + FLT_MIN;
49
50 const float single_scatter = bsdf->a + bsdf->b * t;
51
52 const float El = bsdf->a * M_PI_F + bsdf->b * bsdf_oren_nayar_G(nl);
53 const Spectrum multi_scatter = bsdf->multiscatter_term * (1.0f - El);
54
55 return nl * (make_spectrum(single_scatter) + multi_scatter);
56}
57
60 const Spectrum color)
61{
62 bsdf->type = CLOSURE_BSDF_OREN_NAYAR_ID;
63
64 const float sigma = saturatef(bsdf->roughness);
65 bsdf->a = 1.0f / (M_PI_F + sigma * (M_PI_2_F - 2.0f / 3.0f));
66 bsdf->b = sigma * bsdf->a;
67
68 /* Compute energy compensation term (except for (1.0f - El) factor since it depends on wo). */
69 const Spectrum albedo = saturate(color);
70 const float Eavg = bsdf->a * M_PI_F + ((M_2PI_F - 5.6f) / 3.0f) * bsdf->b;
71 const Spectrum Ems = M_1_PI_F * sqr(albedo) * (Eavg / (1.0f - Eavg)) /
72 (one_spectrum() - albedo * (1.0f - Eavg));
73 const float nv = max(dot(bsdf->N, sd->wi), 0.0f);
74 const float Ev = bsdf->a * M_PI_F + bsdf->b * bsdf_oren_nayar_G(nv);
75 bsdf->multiscatter_term = Ems * (1.0f - Ev);
76
78}
79
81 const float3 wi,
82 const float3 wo,
83 ccl_private float *pdf)
84{
85 ccl_private const OrenNayarBsdf *bsdf = (ccl_private const OrenNayarBsdf *)sc;
86 const float cosNO = dot(bsdf->N, wo);
87 if (cosNO > 0.0f) {
88 *pdf = cosNO * M_1_PI_F;
89 return bsdf_oren_nayar_get_intensity(sc, bsdf->N, wi, wo);
90 }
91 else {
92 *pdf = 0.0f;
93 return zero_spectrum();
94 }
95}
96
98 float3 Ng,
99 float3 wi,
100 float2 rand,
101 ccl_private Spectrum *eval,
103 ccl_private float *pdf)
104{
105 ccl_private const OrenNayarBsdf *bsdf = (ccl_private const OrenNayarBsdf *)sc;
106
107 sample_cos_hemisphere(bsdf->N, rand, wo, pdf);
108
109 if (dot(Ng, *wo) > 0.0f) {
110 *eval = bsdf_oren_nayar_get_intensity(sc, bsdf->N, wi, *wo);
111 }
112 else {
113 *pdf = 0.0f;
114 *eval = zero_spectrum();
115 }
116
118}
119
MINLINE float safe_acosf(float a)
#define saturate(a)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
CCL_NAMESPACE_BEGIN struct OrenNayarBsdf OrenNayarBsdf
ccl_device Spectrum bsdf_oren_nayar_get_intensity(ccl_private const ShaderClosure *sc, float3 n, float3 v, float3 l)
ccl_device int bsdf_oren_nayar_setup(ccl_private const ShaderData *sd, ccl_private OrenNayarBsdf *bsdf, const Spectrum color)
ccl_device int bsdf_oren_nayar_sample(ccl_private const ShaderClosure *sc, float3 Ng, float3 wi, float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf)
ccl_device Spectrum bsdf_oren_nayar_eval(ccl_private const ShaderClosure *sc, const float3 wi, const float3 wo, ccl_private float *pdf)
ccl_device_inline float bsdf_oren_nayar_G(const float cosTheta)
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define CCL_NAMESPACE_END
#define saturatef(x)
@ CLOSURE_BSDF_OREN_NAYAR_ID
@ SD_BSDF_HAS_EVAL
@ SD_BSDF
ShaderData
@ LABEL_DIFFUSE
@ LABEL_REFLECT
ShaderClosure
#define M_PI_F
Definition mikk_util.hh:15
ccl_device_inline void sample_cos_hemisphere(const float3 N, float2 rand_in, ccl_private float3 *wo, ccl_private float *pdf)
#define M_PI_2_F
Definition sky_float3.h:20
#define M_2PI_F
Definition sky_float3.h:23
Spectrum multiscatter_term
float max
#define one_spectrum
#define zero_spectrum
#define make_spectrum(f)
SPECTRUM_DATA_TYPE Spectrum
ccl_device_inline float sqr(float a)
Definition util/math.h:782
ccl_device_inline float sin_from_cos(const float c)
Definition util/math.h:787