Blender V5.0
bsdf_hair.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
2 * SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Adapted code from Open Shading Language. */
7
8#pragma once
9
10#include "kernel/types.h"
11
12#include "util/math_fast.h"
13
15
24
25static_assert(sizeof(ShaderClosure) >= sizeof(HairBsdf), "HairBsdf is too large!");
26
28{
30 bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
31 bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
33}
34
36{
38 bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
39 bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
41}
42
44 const float3 wi,
45 const float3 wo,
46 ccl_private float *pdf)
47{
48 const ccl_private HairBsdf *bsdf = (const ccl_private HairBsdf *)sc;
49 if (dot(bsdf->N, wo) < 0.0f) {
50 *pdf = 0.0f;
51 return zero_spectrum();
52 }
53
54 const float offset = bsdf->offset;
55 const float3 Tg = bsdf->T;
56 const float roughness1 = bsdf->roughness1;
57 const float roughness2 = bsdf->roughness2;
58
59 const float Iz = dot(Tg, wi);
60 const float3 locy = normalize(wi - Tg * Iz);
61
62 const float theta_r = M_PI_2_F - fast_acosf(Iz);
63
64 const float wo_z = dot(Tg, wo);
65 const float3 wo_y = normalize(wo - Tg * wo_z);
66
67 const float theta_i = M_PI_2_F - fast_acosf(wo_z);
68 const float cosphi_i = dot(wo_y, locy);
69
70 if (M_PI_2_F - fabsf(theta_i) < 0.001f || cosphi_i < 0.0f) {
71 *pdf = 0.0f;
72 return zero_spectrum();
73 }
74
75 const float roughness1_inv = 1.0f / roughness1;
76 const float roughness2_inv = 1.0f / roughness2;
77 float phi_i = fast_acosf(cosphi_i) * roughness2_inv;
78 phi_i = fabsf(phi_i) < M_PI_F ? phi_i : M_PI_F;
79 const float costheta_i = fast_cosf(theta_i);
80
81 const float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
82 const float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
83
84 const float theta_h = (theta_i + theta_r) * 0.5f;
85 const float t = theta_h - offset;
86
87 const float phi_pdf = fast_cosf(phi_i * 0.5f) * 0.25f * roughness2_inv;
88 const float theta_pdf = roughness1 /
89 (2 * (t * t + roughness1 * roughness1) * (a_R - b_R) * costheta_i);
90 *pdf = phi_pdf * theta_pdf;
91
92 return make_spectrum(*pdf);
93}
94
96 const float3 wi,
97 const float3 wo,
98 ccl_private float *pdf)
99{
100 const ccl_private HairBsdf *bsdf = (const ccl_private HairBsdf *)sc;
101 if (dot(bsdf->N, wo) >= 0.0f) {
102 *pdf = 0.0f;
103 return zero_spectrum();
104 }
105
106 const float offset = bsdf->offset;
107 const float3 Tg = bsdf->T;
108 const float roughness1 = bsdf->roughness1;
109 const float roughness2 = bsdf->roughness2;
110 const float Iz = dot(Tg, wi);
111 const float3 locy = normalize(wi - Tg * Iz);
112
113 const float theta_r = M_PI_2_F - fast_acosf(Iz);
114
115 const float wo_z = dot(Tg, wo);
116 const float3 wo_y = normalize(wo - Tg * wo_z);
117
118 const float theta_i = M_PI_2_F - fast_acosf(wo_z);
119 const float phi_i = fast_acosf(dot(wo_y, locy));
120
121 if (M_PI_2_F - fabsf(theta_i) < 0.001f) {
122 *pdf = 0.0f;
123 return zero_spectrum();
124 }
125
126 const float costheta_i = fast_cosf(theta_i);
127
128 const float roughness1_inv = 1.0f / roughness1;
129 const float a_TT = fast_atan2f(((M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
130 const float b_TT = fast_atan2f(((-M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
131 const float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f);
132
133 const float theta_h = (theta_i + theta_r) / 2;
134 const float t = theta_h - offset;
135 const float phi = fabsf(phi_i);
136
137 const float p = M_PI_F - phi;
138 const float theta_pdf = roughness1 /
139 (2 * (t * t + roughness1 * roughness1) * (a_TT - b_TT) * costheta_i);
140 const float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
141
142 *pdf = phi_pdf * theta_pdf;
143 return make_spectrum(*pdf);
144}
145
147 const float3 /*Ng*/,
148 const float3 wi,
149 const float2 rand,
150 ccl_private Spectrum *eval,
152 ccl_private float *pdf,
153 ccl_private float2 *sampled_roughness)
154{
155 const ccl_private HairBsdf *bsdf = (const ccl_private HairBsdf *)sc;
156 const float offset = bsdf->offset;
157 const float3 Tg = bsdf->T;
158 const float roughness1 = bsdf->roughness1;
159 const float roughness2 = bsdf->roughness2;
160 *sampled_roughness = make_float2(roughness1, roughness2);
161 const float Iz = dot(Tg, wi);
162 const float3 locy = normalize(wi - Tg * Iz);
163 const float3 locx = cross(locy, Tg);
164 const float theta_r = M_PI_2_F - fast_acosf(Iz);
165
166 const float roughness1_inv = 1.0f / roughness1;
167 const float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
168 const float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
169
170 const float t = roughness1 * tanf(rand.x * (a_R - b_R) + b_R);
171
172 const float theta_h = t + offset;
173 const float theta_i = 2 * theta_h - theta_r;
174
175 float costheta_i;
176 float sintheta_i;
177 fast_sincosf(theta_i, &sintheta_i, &costheta_i);
178
179 const float phi = 2 * safe_asinf(1 - 2 * rand.y) * roughness2;
180
181 const float phi_pdf = fast_cosf(phi * 0.5f) * 0.25f / roughness2;
182
183 const float theta_pdf = roughness1 /
184 (2 * (t * t + roughness1 * roughness1) * (a_R - b_R) * costheta_i);
185
186 float sinphi;
187 float cosphi;
188 fast_sincosf(phi, &sinphi, &cosphi);
189 *wo = (cosphi * costheta_i) * locy - (sinphi * costheta_i) * locx + (sintheta_i)*Tg;
190
191 *pdf = fabsf(phi_pdf * theta_pdf);
192 if (M_PI_2_F - fabsf(theta_i) < 0.001f) {
193 *pdf = 0.0f;
194 }
195
196 *eval = make_spectrum(*pdf);
197
199}
200
202 const float3 /*Ng*/,
203 const float3 wi,
204 const float2 rand,
205 ccl_private Spectrum *eval,
207 ccl_private float *pdf,
208 ccl_private float2 *sampled_roughness)
209{
210 const ccl_private HairBsdf *bsdf = (const ccl_private HairBsdf *)sc;
211 const float offset = bsdf->offset;
212 const float3 Tg = bsdf->T;
213 const float roughness1 = bsdf->roughness1;
214 const float roughness2 = bsdf->roughness2;
215 *sampled_roughness = make_float2(roughness1, roughness2);
216 const float Iz = dot(Tg, wi);
217 const float3 locy = normalize(wi - Tg * Iz);
218 const float3 locx = cross(locy, Tg);
219 const float theta_r = M_PI_2_F - fast_acosf(Iz);
220
221 const float roughness1_inv = 1.0f / roughness1;
222 const float a_TT = fast_atan2f(((M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
223 const float b_TT = fast_atan2f(((-M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
224 const float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f);
225
226 const float t = roughness1 * tanf(rand.x * (a_TT - b_TT) + b_TT);
227
228 const float theta_h = t + offset;
229 const float theta_i = 2 * theta_h - theta_r;
230
231 float costheta_i;
232 float sintheta_i;
233 fast_sincosf(theta_i, &sintheta_i, &costheta_i);
234
235 const float p = roughness2 * tanf(c_TT * (rand.y - 0.5f));
236 const float phi = p + M_PI_F;
237 const float theta_pdf = roughness1 /
238 (2 * (t * t + roughness1 * roughness1) * (a_TT - b_TT) * costheta_i);
239 const float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
240
241 float sinphi;
242 float cosphi;
243 fast_sincosf(phi, &sinphi, &cosphi);
244 *wo = (cosphi * costheta_i) * locy - (sinphi * costheta_i) * locx + (sintheta_i)*Tg;
245
246 *pdf = fabsf(phi_pdf * theta_pdf);
247 if (M_PI_2_F - fabsf(theta_i) < 0.001f) {
248 *pdf = 0.0f;
249 }
250
251 *eval = make_spectrum(*pdf);
252
253 /* TODO(sergey): Should always be negative, but seems some precision issue
254 * is involved here.
255 */
256 kernel_assert(dot(locy, *wo) < 1e-4f);
257
259}
260
MINLINE float safe_asinf(float a)
ccl_device Spectrum bsdf_hair_reflection_eval(const ccl_private ShaderClosure *sc, const float3 wi, const float3 wo, ccl_private float *pdf)
Definition bsdf_hair.h:43
ccl_device int bsdf_hair_reflection_setup(ccl_private HairBsdf *bsdf)
Definition bsdf_hair.h:27
ccl_device int bsdf_hair_reflection_sample(const ccl_private ShaderClosure *sc, const float3, const float3 wi, const float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, ccl_private float2 *sampled_roughness)
Definition bsdf_hair.h:146
ccl_device int bsdf_hair_transmission_setup(ccl_private HairBsdf *bsdf)
Definition bsdf_hair.h:35
ccl_device Spectrum bsdf_hair_transmission_eval(const ccl_private ShaderClosure *sc, const float3 wi, const float3 wo, ccl_private float *pdf)
Definition bsdf_hair.h:95
ccl_device int bsdf_hair_transmission_sample(const ccl_private ShaderClosure *sc, const float3, const float3 wi, const float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, ccl_private float2 *sampled_roughness)
Definition bsdf_hair.h:201
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define kernel_assert(cond)
#define M_PI_2_F
#define zero_spectrum
#define make_spectrum(f)
#define ccl_private
#define CCL_NAMESPACE_END
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
constexpr T clamp(T, U, U) RET
@ CLOSURE_BSDF_HAIR_TRANSMISSION_ID
@ CLOSURE_BSDF_HAIR_REFLECTION_ID
@ SD_BSDF_HAS_EVAL
@ SD_BSDF
@ SD_BSDF_HAS_TRANSMISSION
@ LABEL_TRANSMIT
@ LABEL_GLOSSY
@ LABEL_REFLECT
ccl_device float fast_atan2f(const float y, const float x)
Definition math_fast.h:309
ccl_device float fast_acosf(const float x)
Definition math_fast.h:259
ccl_device void fast_sincosf(float x, ccl_private float *sine, ccl_private float *cosine)
Definition math_fast.h:144
ccl_device float fast_cosf(float x)
Definition math_fast.h:118
#define fabsf
#define ccl_device
#define make_float2
#define tanf
#define M_PI_F
float roughness1
Definition bsdf_hair.h:20
float offset
Definition bsdf_hair.h:22
float roughness2
Definition bsdf_hair.h:21
SHADER_CLOSURE_BASE
Definition bsdf_hair.h:17
float3 T
Definition bsdf_hair.h:19
float x
float y
float3 Spectrum