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