Blender  V2.93
bsdf_hair.h
Go to the documentation of this file.
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 
37 
38 typedef ccl_addr_space struct HairBsdf {
40 
42  float roughness1;
43  float roughness2;
44  float offset;
46 
47 static_assert(sizeof(ShaderClosure) >= sizeof(HairBsdf), "HairBsdf is too large!");
48 
50 {
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 
58 {
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 
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 
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 
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 
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 
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 
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 
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 
312 
313 #endif /* __BSDF_HAIR_H__ */
MINLINE float safe_asinf(float a)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
ccl_device bool bsdf_hair_merge(const ShaderClosure *a, const ShaderClosure *b)
Definition: bsdf_hair.h:65
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)
Definition: bsdf_hair.h:183
ccl_device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
Definition: bsdf_hair.h:129
ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
Definition: bsdf_hair.h:137
CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct HairBsdf HairBsdf
ccl_device float3 bsdf_hair_transmission_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
Definition: bsdf_hair.h:121
ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf)
Definition: bsdf_hair.h:49
ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
Definition: bsdf_hair.h:74
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)
Definition: bsdf_hair.h:244
ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf)
Definition: bsdf_hair.h:57
#define kernel_assert(cond)
#define ccl_addr_space
#define ccl_device
#define tanf(x)
#define CCL_NAMESPACE_END
#define fabsf(x)
#define make_float3(x, y, z)
@ SD_BSDF_HAS_EVAL
Definition: kernel_types.h:849
@ SD_BSDF
Definition: kernel_types.h:847
@ LABEL_TRANSMIT
Definition: kernel_types.h:328
@ LABEL_GLOSSY
Definition: kernel_types.h:331
@ LABEL_REFLECT
Definition: kernel_types.h:329
ShaderClosure
Definition: kernel_types.h:831
static unsigned a[3]
Definition: RandGen.cpp:92
#define I
float roughness1
Definition: bsdf_hair.h:42
float offset
Definition: bsdf_hair.h:44
float roughness2
Definition: bsdf_hair.h:43
SHADER_CLOSURE_BASE
Definition: bsdf_hair.h:39
float3 T
Definition: bsdf_hair.h:41
@ CLOSURE_BSDF_HAIR_TRANSMISSION_ID
Definition: svm_types.h:566
@ CLOSURE_BSDF_HAIR_REFLECTION_ID
Definition: svm_types.h:554
__forceinline avxf cross(const avxf &a, const avxf &b)
Definition: util_avxf.h:119
#define M_PI_2_F
Definition: util_math.h:46
#define M_PI_F
Definition: util_math.h:43
ccl_device_inline int clamp(int a, int mn, int mx)
Definition: util_math.h:283
ccl_device void fast_sincosf(float x, float *sine, float *cosine)
ccl_device float fast_acosf(float x)
ccl_device float fast_atan2f(float y, float x)
ccl_device float fast_cosf(float x)
ccl_device_inline float2 normalize(const float2 &a)
ccl_device_inline float dot(const float2 &a, const float2 &b)
ccl_device_inline bool isequal_float3(const float3 a, const float3 b)