1 /*
2 * Adapted from Open Shading Language with this license:
3 *
4 * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
5 * All Rights Reserved.
6 *
7 * Modifications Copyright 2011, Blender Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * * Neither the name of Sony Pictures Imageworks nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #ifndef __BSDF_HAIR_H__
34 #define __BSDF_HAIR_H__
35
36 CCL_NAMESPACE_BEGIN
37
38 typedef ccl_addr_space struct HairBsdf {
39 SHADER_CLOSURE_BASE;
40
41 float3 T;
42 float roughness1;
43 float roughness2;
44 float offset;
45 } HairBsdf;
46
47 static_assert(sizeof(ShaderClosure) >= sizeof(HairBsdf), "HairBsdf is too large!");
48
bsdf_hair_reflection_setup(HairBsdf * bsdf)49 ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf)
50 {
51 bsdf->type = CLOSURE_BSDF_HAIR_REFLECTION_ID;
52 bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
53 bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
54 return SD_BSDF | SD_BSDF_HAS_EVAL;
55 }
56
bsdf_hair_transmission_setup(HairBsdf * bsdf)57 ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf)
58 {
59 bsdf->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
60 bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
61 bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
62 return SD_BSDF | SD_BSDF_HAS_EVAL;
63 }
64
bsdf_hair_merge(const ShaderClosure * a,const ShaderClosure * b)65 ccl_device bool bsdf_hair_merge(const ShaderClosure *a, const ShaderClosure *b)
66 {
67 const HairBsdf *bsdf_a = (const HairBsdf *)a;
68 const HairBsdf *bsdf_b = (const HairBsdf *)b;
69
70 return (isequal_float3(bsdf_a->T, bsdf_b->T)) && (bsdf_a->roughness1 == bsdf_b->roughness1) &&
71 (bsdf_a->roughness2 == bsdf_b->roughness2) && (bsdf_a->offset == bsdf_b->offset);
72 }
73
bsdf_hair_reflection_eval_reflect(const ShaderClosure * sc,const float3 I,const float3 omega_in,float * pdf)74 ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc,
75 const float3 I,
76 const float3 omega_in,
77 float *pdf)
78 {
79 const HairBsdf *bsdf = (const HairBsdf *)sc;
80 float offset = bsdf->offset;
81 float3 Tg = bsdf->T;
82 float roughness1 = bsdf->roughness1;
83 float roughness2 = bsdf->roughness2;
84
85 float Iz = dot(Tg, I);
86 float3 locy = normalize(I - Tg * Iz);
87
88 float theta_r = M_PI_2_F - fast_acosf(Iz);
89
90 float omega_in_z = dot(Tg, omega_in);
91 float3 omega_in_y = normalize(omega_in - Tg * omega_in_z);
92
93 float theta_i = M_PI_2_F - fast_acosf(omega_in_z);
94 float cosphi_i = dot(omega_in_y, locy);
95
96 if (M_PI_2_F - fabsf(theta_i) < 0.001f || cosphi_i < 0.0f) {
97 *pdf = 0.0f;
98 return make_float3(*pdf, *pdf, *pdf);
99 }
100
101 float roughness1_inv = 1.0f / roughness1;
102 float roughness2_inv = 1.0f / roughness2;
103 float phi_i = fast_acosf(cosphi_i) * roughness2_inv;
104 phi_i = fabsf(phi_i) < M_PI_F ? phi_i : M_PI_F;
105 float costheta_i = fast_cosf(theta_i);
106
107 float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
108 float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
109
110 float theta_h = (theta_i + theta_r) * 0.5f;
111 float t = theta_h - offset;
112
113 float phi_pdf = fast_cosf(phi_i * 0.5f) * 0.25f * roughness2_inv;
114 float theta_pdf = roughness1 /
115 (2 * (t * t + roughness1 * roughness1) * (a_R - b_R) * costheta_i);
116 *pdf = phi_pdf * theta_pdf;
117
118 return make_float3(*pdf, *pdf, *pdf);
119 }
120
bsdf_hair_transmission_eval_reflect(const ShaderClosure * sc,const float3 I,const float3 omega_in,float * pdf)121 ccl_device float3 bsdf_hair_transmission_eval_reflect(const ShaderClosure *sc,
122 const float3 I,
123 const float3 omega_in,
124 float *pdf)
125 {
126 return make_float3(0.0f, 0.0f, 0.0f);
127 }
128
bsdf_hair_reflection_eval_transmit(const ShaderClosure * sc,const float3 I,const float3 omega_in,float * pdf)129 ccl_device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc,
130 const float3 I,
131 const float3 omega_in,
132 float *pdf)
133 {
134 return make_float3(0.0f, 0.0f, 0.0f);
135 }
136
bsdf_hair_transmission_eval_transmit(const ShaderClosure * sc,const float3 I,const float3 omega_in,float * pdf)137 ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc,
138 const float3 I,
139 const float3 omega_in,
140 float *pdf)
141 {
142 const HairBsdf *bsdf = (const HairBsdf *)sc;
143 float offset = bsdf->offset;
144 float3 Tg = bsdf->T;
145 float roughness1 = bsdf->roughness1;
146 float roughness2 = bsdf->roughness2;
147 float Iz = dot(Tg, I);
148 float3 locy = normalize(I - Tg * Iz);
149
150 float theta_r = M_PI_2_F - fast_acosf(Iz);
151
152 float omega_in_z = dot(Tg, omega_in);
153 float3 omega_in_y = normalize(omega_in - Tg * omega_in_z);
154
155 float theta_i = M_PI_2_F - fast_acosf(omega_in_z);
156 float phi_i = fast_acosf(dot(omega_in_y, locy));
157
158 if (M_PI_2_F - fabsf(theta_i) < 0.001f) {
159 *pdf = 0.0f;
160 return make_float3(*pdf, *pdf, *pdf);
161 }
162
163 float costheta_i = fast_cosf(theta_i);
164
165 float roughness1_inv = 1.0f / roughness1;
166 float a_TT = fast_atan2f(((M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
167 float b_TT = fast_atan2f(((-M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
168 float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f);
169
170 float theta_h = (theta_i + theta_r) / 2;
171 float t = theta_h - offset;
172 float phi = fabsf(phi_i);
173
174 float p = M_PI_F - phi;
175 float theta_pdf = roughness1 /
176 (2 * (t * t + roughness1 * roughness1) * (a_TT - b_TT) * costheta_i);
177 float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
178
179 *pdf = phi_pdf * theta_pdf;
180 return make_float3(*pdf, *pdf, *pdf);
181 }
182
bsdf_hair_reflection_sample(const ShaderClosure * sc,float3 Ng,float3 I,float3 dIdx,float3 dIdy,float randu,float randv,float3 * eval,float3 * omega_in,float3 * domega_in_dx,float3 * domega_in_dy,float * pdf)183 ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc,
184 float3 Ng,
185 float3 I,
186 float3 dIdx,
187 float3 dIdy,
188 float randu,
189 float randv,
190 float3 *eval,
191 float3 *omega_in,
192 float3 *domega_in_dx,
193 float3 *domega_in_dy,
194 float *pdf)
195 {
196 const HairBsdf *bsdf = (const HairBsdf *)sc;
197 float offset = bsdf->offset;
198 float3 Tg = bsdf->T;
199 float roughness1 = bsdf->roughness1;
200 float roughness2 = bsdf->roughness2;
201 float Iz = dot(Tg, I);
202 float3 locy = normalize(I - Tg * Iz);
203 float3 locx = cross(locy, Tg);
204 float theta_r = M_PI_2_F - fast_acosf(Iz);
205
206 float roughness1_inv = 1.0f / roughness1;
207 float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
208 float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
209
210 float t = roughness1 * tanf(randu * (a_R - b_R) + b_R);
211
212 float theta_h = t + offset;
213 float theta_i = 2 * theta_h - theta_r;
214
215 float costheta_i, sintheta_i;
216 fast_sincosf(theta_i, &sintheta_i, &costheta_i);
217
218 float phi = 2 * safe_asinf(1 - 2 * randv) * roughness2;
219
220 float phi_pdf = fast_cosf(phi * 0.5f) * 0.25f / roughness2;
221
222 float theta_pdf = roughness1 /
223 (2 * (t * t + roughness1 * roughness1) * (a_R - b_R) * costheta_i);
224
225 float sinphi, cosphi;
226 fast_sincosf(phi, &sinphi, &cosphi);
227 *omega_in = (cosphi * costheta_i) * locy - (sinphi * costheta_i) * locx + (sintheta_i)*Tg;
228
229 // differentials - TODO: find a better approximation for the reflective bounce
230 #ifdef __RAY_DIFFERENTIALS__
231 *domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
232 *domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
233 #endif
234
235 *pdf = fabsf(phi_pdf * theta_pdf);
236 if (M_PI_2_F - fabsf(theta_i) < 0.001f)
237 *pdf = 0.0f;
238
239 *eval = make_float3(*pdf, *pdf, *pdf);
240
241 return LABEL_REFLECT | LABEL_GLOSSY;
242 }
243
bsdf_hair_transmission_sample(const ShaderClosure * sc,float3 Ng,float3 I,float3 dIdx,float3 dIdy,float randu,float randv,float3 * eval,float3 * omega_in,float3 * domega_in_dx,float3 * domega_in_dy,float * pdf)244 ccl_device int bsdf_hair_transmission_sample(const ShaderClosure *sc,
245 float3 Ng,
246 float3 I,
247 float3 dIdx,
248 float3 dIdy,
249 float randu,
250 float randv,
251 float3 *eval,
252 float3 *omega_in,
253 float3 *domega_in_dx,
254 float3 *domega_in_dy,
255 float *pdf)
256 {
257 const HairBsdf *bsdf = (const HairBsdf *)sc;
258 float offset = bsdf->offset;
259 float3 Tg = bsdf->T;
260 float roughness1 = bsdf->roughness1;
261 float roughness2 = bsdf->roughness2;
262 float Iz = dot(Tg, I);
263 float3 locy = normalize(I - Tg * Iz);
264 float3 locx = cross(locy, Tg);
265 float theta_r = M_PI_2_F - fast_acosf(Iz);
266
267 float roughness1_inv = 1.0f / roughness1;
268 float a_TT = fast_atan2f(((M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
269 float b_TT = fast_atan2f(((-M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
270 float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f);
271
272 float t = roughness1 * tanf(randu * (a_TT - b_TT) + b_TT);
273
274 float theta_h = t + offset;
275 float theta_i = 2 * theta_h - theta_r;
276
277 float costheta_i, sintheta_i;
278 fast_sincosf(theta_i, &sintheta_i, &costheta_i);
279
280 float p = roughness2 * tanf(c_TT * (randv - 0.5f));
281 float phi = p + M_PI_F;
282 float theta_pdf = roughness1 /
283 (2 * (t * t + roughness1 * roughness1) * (a_TT - b_TT) * costheta_i);
284 float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
285
286 float sinphi, cosphi;
287 fast_sincosf(phi, &sinphi, &cosphi);
288 *omega_in = (cosphi * costheta_i) * locy - (sinphi * costheta_i) * locx + (sintheta_i)*Tg;
289
290 // differentials - TODO: find a better approximation for the transmission bounce
291 #ifdef __RAY_DIFFERENTIALS__
292 *domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
293 *domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
294 #endif
295
296 *pdf = fabsf(phi_pdf * theta_pdf);
297 if (M_PI_2_F - fabsf(theta_i) < 0.001f) {
298 *pdf = 0.0f;
299 }
300
301 *eval = make_float3(*pdf, *pdf, *pdf);
302
303 /* TODO(sergey): Should always be negative, but seems some precision issue
304 * is involved here.
305 */
306 kernel_assert(dot(locy, *omega_in) < 1e-4f);
307
308 return LABEL_TRANSMIT | LABEL_GLOSSY;
309 }
310
311 CCL_NAMESPACE_END
312
313 #endif /* __BSDF_HAIR_H__ */
314