Blender V5.0
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
7#include "kernel/types.h"
8
10
12
21
22static_assert(sizeof(ShaderClosure) >= sizeof(OrenNayarBsdf), "OrenNayarBsdf is too large!");
23
24/* NOTE: This implements the improved Oren-Nayar model by Yasuhiro Fujii
25 * (https://mimosa-pudica.net/improved-oren-nayar.html), plus an
26 * energy-preserving multi-scattering term based on the OpenPBR specification
27 * (https://academysoftwarefoundation.github.io/OpenPBR). */
28
29ccl_device_inline float bsdf_oren_nayar_G(const float cosTheta)
30{
31 if (cosTheta < 1e-6f) {
32 /* The tan(theta) term starts to act up at low cosTheta, so fall back to Taylor expansion. */
33 return (M_PI_2_F - 2.0f / 3.0f) - cosTheta;
34 }
35 const float sinTheta = sin_from_cos(cosTheta);
36 const float theta = safe_acosf(cosTheta);
37 return sinTheta * (theta - 2.0f / 3.0f - sinTheta * cosTheta) +
38 2.0f / 3.0f * (sinTheta / cosTheta) * (1.0f - sqr(sinTheta) * sinTheta);
39}
40
42 const float3 n,
43 const float3 v,
44 const float3 l)
45{
46 const ccl_private OrenNayarBsdf *bsdf = (const ccl_private OrenNayarBsdf *)sc;
47 const float nl = max(dot(n, l), 0.0f);
48 if (bsdf->b <= 0.0f) {
49 return make_spectrum(nl * M_1_PI_F);
50 }
51 const float nv = max(dot(n, v), 0.0f);
52 float t = dot(l, v) - nl * nv;
53
54 if (t > 0.0f) {
55 t /= max(nl, nv) + FLT_MIN;
56 }
57
58 const float single_scatter = bsdf->a + bsdf->b * t;
59
60 const float El = bsdf->a * M_PI_F + bsdf->b * bsdf_oren_nayar_G(nl);
61 const Spectrum multi_scatter = bsdf->multiscatter_term * (1.0f - El);
62
63 return nl * (make_spectrum(single_scatter) + multi_scatter);
64}
65
68 const Spectrum color)
69{
70 bsdf->type = CLOSURE_BSDF_OREN_NAYAR_ID;
71
72 const float sigma = saturatef(bsdf->roughness);
73 bsdf->a = 1.0f / (M_PI_F + sigma * (M_PI_2_F - 2.0f / 3.0f));
74 bsdf->b = sigma * bsdf->a;
75
76 /* Compute energy compensation term (except for (1.0f - El) factor since it depends on wo). */
77 const Spectrum albedo = saturate(color);
78 const float Eavg = bsdf->a * M_PI_F + ((M_2PI_F - 5.6f) / 3.0f) * bsdf->b;
79 const Spectrum Ems = M_1_PI_F * sqr(albedo) * (Eavg / (1.0f - Eavg)) /
80 (one_spectrum() - albedo * (1.0f - Eavg));
81 const float nv = max(dot(bsdf->N, sd->wi), 0.0f);
82 const float Ev = bsdf->a * M_PI_F + bsdf->b * bsdf_oren_nayar_G(nv);
83 bsdf->multiscatter_term = Ems * (1.0f - Ev);
84
86}
87
89 const float3 wi,
90 const float3 wo,
91 ccl_private float *pdf)
92{
93 const ccl_private OrenNayarBsdf *bsdf = (const ccl_private OrenNayarBsdf *)sc;
94 const float cosNO = dot(bsdf->N, wo);
95 if (cosNO > 0.0f) {
96 *pdf = cosNO * M_1_PI_F;
97 return bsdf_oren_nayar_get_intensity(sc, bsdf->N, wi, wo);
98 }
99 *pdf = 0.0f;
100 return zero_spectrum();
101}
102
104 const float3 Ng,
105 const float3 wi,
106 const float2 rand,
107 ccl_private Spectrum *eval,
109 ccl_private float *pdf)
110{
111 const ccl_private OrenNayarBsdf *bsdf = (const ccl_private OrenNayarBsdf *)sc;
112
113 sample_cos_hemisphere(bsdf->N, rand, wo, pdf);
114
115 if (dot(Ng, *wo) > 0.0f) {
116 *eval = bsdf_oren_nayar_get_intensity(sc, bsdf->N, wi, *wo);
117 }
118 else {
119 *pdf = 0.0f;
120 *eval = zero_spectrum();
121 }
122
124}
125
MINLINE float safe_acosf(float a)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device int bsdf_oren_nayar_sample(const ccl_private ShaderClosure *sc, const float3 Ng, const float3 wi, const float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf)
ccl_device Spectrum bsdf_oren_nayar_eval(const ccl_private ShaderClosure *sc, const float3 wi, const float3 wo, ccl_private float *pdf)
ccl_device Spectrum bsdf_oren_nayar_get_intensity(const ccl_private ShaderClosure *sc, const float3 n, const float3 v, const float3 l)
ccl_device_inline float bsdf_oren_nayar_G(const float cosTheta)
ccl_device int bsdf_oren_nayar_setup(const ccl_private ShaderData *sd, ccl_private OrenNayarBsdf *bsdf, const Spectrum color)
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define M_PI_2_F
#define one_spectrum
#define zero_spectrum
#define make_spectrum(f)
#define ccl_private
#define ccl_device_inline
#define M_1_PI_F
#define CCL_NAMESPACE_END
#define saturatef(x)
@ CLOSURE_BSDF_OREN_NAYAR_ID
@ SD_BSDF_HAS_EVAL
@ SD_BSDF
@ LABEL_DIFFUSE
@ LABEL_REFLECT
ccl_device_inline float sin_from_cos(const float c)
Definition math_base.h:609
#define sqr
#define ccl_device
#define M_2PI_F
#define M_PI_F
ccl_device_inline void sample_cos_hemisphere(const float3 N, const float2 rand_in, ccl_private float3 *wo, ccl_private float *pdf)
#define saturate(a)
Definition smaa.cc:315
Spectrum multiscatter_term
max
Definition text_draw.cc:251
float3 Spectrum