2 * Adapted from Open Shading Language with this license:
4 * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
7 * Modifications Copyright 2011, Blender Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
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.
33 #ifndef __BSDF_HAIR_H__
34 #define __BSDF_HAIR_H__
38 typedef ccl_addr_space struct HairBsdf {
47 ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf)
49 bsdf->type = CLOSURE_BSDF_HAIR_REFLECTION_ID;
50 bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
51 bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
52 return SD_BSDF|SD_BSDF_HAS_EVAL;
55 ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf)
57 bsdf->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
58 bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
59 bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
60 return SD_BSDF|SD_BSDF_HAS_EVAL;
63 ccl_device bool bsdf_hair_merge(const ShaderClosure *a, const ShaderClosure *b)
65 const HairBsdf *bsdf_a = (const HairBsdf*)a;
66 const HairBsdf *bsdf_b = (const HairBsdf*)b;
68 return (isequal_float3(bsdf_a->T, bsdf_b->T)) &&
69 (bsdf_a->roughness1 == bsdf_b->roughness1) &&
70 (bsdf_a->roughness2 == bsdf_b->roughness2) &&
71 (bsdf_a->offset == bsdf_b->offset);
74 ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
76 const HairBsdf *bsdf = (const HairBsdf*)sc;
77 float offset = bsdf->offset;
79 float roughness1 = bsdf->roughness1;
80 float roughness2 = bsdf->roughness2;
82 float Iz = dot(Tg, I);
83 float3 locy = normalize(I - Tg * Iz);
85 float theta_r = M_PI_2_F - fast_acosf(Iz);
87 float omega_in_z = dot(Tg, omega_in);
88 float3 omega_in_y = normalize(omega_in - Tg * omega_in_z);
90 float theta_i = M_PI_2_F - fast_acosf(omega_in_z);
91 float cosphi_i = dot(omega_in_y, locy);
93 if(M_PI_2_F - fabsf(theta_i) < 0.001f || cosphi_i < 0.0f) {
95 return make_float3(*pdf, *pdf, *pdf);
98 float roughness1_inv = 1.0f / roughness1;
99 float roughness2_inv = 1.0f / roughness2;
100 float phi_i = fast_acosf(cosphi_i) * roughness2_inv;
101 phi_i = fabsf(phi_i) < M_PI_F ? phi_i : M_PI_F;
102 float costheta_i = fast_cosf(theta_i);
104 float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
105 float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
107 float theta_h = (theta_i + theta_r) * 0.5f;
108 float t = theta_h - offset;
110 float phi_pdf = fast_cosf(phi_i * 0.5f) * 0.25f * roughness2_inv;
111 float theta_pdf = roughness1 / (2 * (t*t + roughness1*roughness1) * (a_R - b_R)* costheta_i);
112 *pdf = phi_pdf * theta_pdf;
114 return make_float3(*pdf, *pdf, *pdf);
117 ccl_device float3 bsdf_hair_transmission_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
119 return make_float3(0.0f, 0.0f, 0.0f);
123 ccl_device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
125 return make_float3(0.0f, 0.0f, 0.0f);
128 ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
130 const HairBsdf *bsdf = (const HairBsdf*)sc;
131 float offset = bsdf->offset;
133 float roughness1 = bsdf->roughness1;
134 float roughness2 = bsdf->roughness2;
135 float Iz = dot(Tg, I);
136 float3 locy = normalize(I - Tg * Iz);
138 float theta_r = M_PI_2_F - fast_acosf(Iz);
140 float omega_in_z = dot(Tg, omega_in);
141 float3 omega_in_y = normalize(omega_in - Tg * omega_in_z);
143 float theta_i = M_PI_2_F - fast_acosf(omega_in_z);
144 float phi_i = fast_acosf(dot(omega_in_y, locy));
146 if(M_PI_2_F - fabsf(theta_i) < 0.001f) {
148 return make_float3(*pdf, *pdf, *pdf);
151 float costheta_i = fast_cosf(theta_i);
153 float roughness1_inv = 1.0f / roughness1;
154 float a_TT = fast_atan2f(((M_PI_2_F + theta_r)/2 - offset) * roughness1_inv, 1.0f);
155 float b_TT = fast_atan2f(((-M_PI_2_F + theta_r)/2 - offset) * roughness1_inv, 1.0f);
156 float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f);
158 float theta_h = (theta_i + theta_r) / 2;
159 float t = theta_h - offset;
160 float phi = fabsf(phi_i);
162 float p = M_PI_F - phi;
163 float theta_pdf = roughness1 / (2 * (t*t + roughness1 * roughness1) * (a_TT - b_TT)*costheta_i);
164 float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
166 *pdf = phi_pdf * theta_pdf;
167 return make_float3(*pdf, *pdf, *pdf);
170 ccl_device int 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)
172 const HairBsdf *bsdf = (const HairBsdf*)sc;
173 float offset = bsdf->offset;
175 float roughness1 = bsdf->roughness1;
176 float roughness2 = bsdf->roughness2;
177 float Iz = dot(Tg, I);
178 float3 locy = normalize(I - Tg * Iz);
179 float3 locx = cross(locy, Tg);
180 float theta_r = M_PI_2_F - fast_acosf(Iz);
182 float roughness1_inv = 1.0f / roughness1;
183 float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
184 float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
186 float t = roughness1 * tanf(randu * (a_R - b_R) + b_R);
188 float theta_h = t + offset;
189 float theta_i = 2 * theta_h - theta_r;
191 float costheta_i, sintheta_i;
192 fast_sincosf(theta_i, &sintheta_i, &costheta_i);
194 float phi = 2 * safe_asinf(1 - 2 * randv) * roughness2;
196 float phi_pdf = fast_cosf(phi * 0.5f) * 0.25f / roughness2;
198 float theta_pdf = roughness1 / (2 * (t*t + roughness1*roughness1) * (a_R - b_R)*costheta_i);
200 float sinphi, cosphi;
201 fast_sincosf(phi, &sinphi, &cosphi);
202 *omega_in =(cosphi * costheta_i) * locy -
203 (sinphi * costheta_i) * locx +
206 //differentials - TODO: find a better approximation for the reflective bounce
207 #ifdef __RAY_DIFFERENTIALS__
208 *domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
209 *domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
212 *pdf = fabsf(phi_pdf * theta_pdf);
213 if(M_PI_2_F - fabsf(theta_i) < 0.001f)
216 *eval = make_float3(*pdf, *pdf, *pdf);
218 return LABEL_REFLECT|LABEL_GLOSSY;
221 ccl_device int 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)
223 const HairBsdf *bsdf = (const HairBsdf*)sc;
224 float offset = bsdf->offset;
226 float roughness1 = bsdf->roughness1;
227 float roughness2 = bsdf->roughness2;
228 float Iz = dot(Tg, I);
229 float3 locy = normalize(I - Tg * Iz);
230 float3 locx = cross(locy, Tg);
231 float theta_r = M_PI_2_F - fast_acosf(Iz);
233 float roughness1_inv = 1.0f / roughness1;
234 float a_TT = fast_atan2f(((M_PI_2_F + theta_r)/2 - offset) * roughness1_inv, 1.0f);
235 float b_TT = fast_atan2f(((-M_PI_2_F + theta_r)/2 - offset) * roughness1_inv, 1.0f);
236 float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f);
238 float t = roughness1 * tanf(randu * (a_TT - b_TT) + b_TT);
240 float theta_h = t + offset;
241 float theta_i = 2 * theta_h - theta_r;
243 float costheta_i, sintheta_i;
244 fast_sincosf(theta_i, &sintheta_i, &costheta_i);
246 float p = roughness2 * tanf(c_TT * (randv - 0.5f));
247 float phi = p + M_PI_F;
248 float theta_pdf = roughness1 / (2 * (t*t + roughness1*roughness1) * (a_TT - b_TT) * costheta_i);
249 float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
251 float sinphi, cosphi;
252 fast_sincosf(phi, &sinphi, &cosphi);
253 *omega_in =(cosphi * costheta_i) * locy -
254 (sinphi * costheta_i) * locx +
257 //differentials - TODO: find a better approximation for the transmission bounce
258 #ifdef __RAY_DIFFERENTIALS__
259 *domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
260 *domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
263 *pdf = fabsf(phi_pdf * theta_pdf);
264 if(M_PI_2_F - fabsf(theta_i) < 0.001f) {
268 *eval = make_float3(*pdf, *pdf, *pdf);
270 /* TODO(sergey): Should always be negative, but seems some precision issue
273 kernel_assert(dot(locy, *omega_in) < 1e-4f);
275 return LABEL_TRANSMIT|LABEL_GLOSSY;
280 #endif /* __BSDF_HAIR_H__ */