Blender  V3.3
bsdf_hair.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Adapted from Open Shading Language
4  * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
5  * All Rights Reserved.
6  *
7  * Modifications Copyright 2011-2022 Blender Foundation. */
8 
9 #pragma once
10 
12 
13 typedef struct HairBsdf {
15 
17  float roughness1;
18  float roughness2;
19  float offset;
21 
22 static_assert(sizeof(ShaderClosure) >= sizeof(HairBsdf), "HairBsdf is too large!");
23 
25 {
27  bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
28  bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
29  return SD_BSDF | SD_BSDF_HAS_EVAL;
30 }
31 
33 {
35  bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
36  bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
37  return SD_BSDF | SD_BSDF_HAS_EVAL;
38 }
39 
41  const float3 I,
42  const float3 omega_in,
43  ccl_private float *pdf)
44 {
45  ccl_private const HairBsdf *bsdf = (ccl_private const HairBsdf *)sc;
46  float offset = bsdf->offset;
47  float3 Tg = bsdf->T;
48  float roughness1 = bsdf->roughness1;
49  float roughness2 = bsdf->roughness2;
50 
51  float Iz = dot(Tg, I);
52  float3 locy = normalize(I - Tg * Iz);
53 
54  float theta_r = M_PI_2_F - fast_acosf(Iz);
55 
56  float omega_in_z = dot(Tg, omega_in);
57  float3 omega_in_y = normalize(omega_in - Tg * omega_in_z);
58 
59  float theta_i = M_PI_2_F - fast_acosf(omega_in_z);
60  float cosphi_i = dot(omega_in_y, locy);
61 
62  if (M_PI_2_F - fabsf(theta_i) < 0.001f || cosphi_i < 0.0f) {
63  *pdf = 0.0f;
64  return make_float3(*pdf, *pdf, *pdf);
65  }
66 
67  float roughness1_inv = 1.0f / roughness1;
68  float roughness2_inv = 1.0f / roughness2;
69  float phi_i = fast_acosf(cosphi_i) * roughness2_inv;
70  phi_i = fabsf(phi_i) < M_PI_F ? phi_i : M_PI_F;
71  float costheta_i = fast_cosf(theta_i);
72 
73  float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
74  float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
75 
76  float theta_h = (theta_i + theta_r) * 0.5f;
77  float t = theta_h - offset;
78 
79  float phi_pdf = fast_cosf(phi_i * 0.5f) * 0.25f * roughness2_inv;
80  float theta_pdf = roughness1 /
81  (2 * (t * t + roughness1 * roughness1) * (a_R - b_R) * costheta_i);
82  *pdf = phi_pdf * theta_pdf;
83 
84  return make_float3(*pdf, *pdf, *pdf);
85 }
86 
88  const float3 I,
89  const float3 omega_in,
90  ccl_private float *pdf)
91 {
92  *pdf = 0.0f;
93  return make_float3(0.0f, 0.0f, 0.0f);
94 }
95 
97  const float3 I,
98  const float3 omega_in,
99  ccl_private float *pdf)
100 {
101  *pdf = 0.0f;
102  return make_float3(0.0f, 0.0f, 0.0f);
103 }
104 
106  const float3 I,
107  const float3 omega_in,
108  ccl_private float *pdf)
109 {
110  ccl_private const HairBsdf *bsdf = (ccl_private const HairBsdf *)sc;
111  float offset = bsdf->offset;
112  float3 Tg = bsdf->T;
113  float roughness1 = bsdf->roughness1;
114  float roughness2 = bsdf->roughness2;
115  float Iz = dot(Tg, I);
116  float3 locy = normalize(I - Tg * Iz);
117 
118  float theta_r = M_PI_2_F - fast_acosf(Iz);
119 
120  float omega_in_z = dot(Tg, omega_in);
121  float3 omega_in_y = normalize(omega_in - Tg * omega_in_z);
122 
123  float theta_i = M_PI_2_F - fast_acosf(omega_in_z);
124  float phi_i = fast_acosf(dot(omega_in_y, locy));
125 
126  if (M_PI_2_F - fabsf(theta_i) < 0.001f) {
127  *pdf = 0.0f;
128  return make_float3(*pdf, *pdf, *pdf);
129  }
130 
131  float costheta_i = fast_cosf(theta_i);
132 
133  float roughness1_inv = 1.0f / roughness1;
134  float a_TT = fast_atan2f(((M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
135  float b_TT = fast_atan2f(((-M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
136  float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f);
137 
138  float theta_h = (theta_i + theta_r) / 2;
139  float t = theta_h - offset;
140  float phi = fabsf(phi_i);
141 
142  float p = M_PI_F - phi;
143  float theta_pdf = roughness1 /
144  (2 * (t * t + roughness1 * roughness1) * (a_TT - b_TT) * costheta_i);
145  float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
146 
147  *pdf = phi_pdf * theta_pdf;
148  return make_float3(*pdf, *pdf, *pdf);
149 }
150 
152  float3 Ng,
153  float3 I,
154  float3 dIdx,
155  float3 dIdy,
156  float randu,
157  float randv,
158  ccl_private float3 *eval,
159  ccl_private float3 *omega_in,
160  ccl_private float3 *domega_in_dx,
161  ccl_private float3 *domega_in_dy,
162  ccl_private float *pdf)
163 {
164  ccl_private const HairBsdf *bsdf = (ccl_private const HairBsdf *)sc;
165  float offset = bsdf->offset;
166  float3 Tg = bsdf->T;
167  float roughness1 = bsdf->roughness1;
168  float roughness2 = bsdf->roughness2;
169  float Iz = dot(Tg, I);
170  float3 locy = normalize(I - Tg * Iz);
171  float3 locx = cross(locy, Tg);
172  float theta_r = M_PI_2_F - fast_acosf(Iz);
173 
174  float roughness1_inv = 1.0f / roughness1;
175  float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
176  float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f);
177 
178  float t = roughness1 * tanf(randu * (a_R - b_R) + b_R);
179 
180  float theta_h = t + offset;
181  float theta_i = 2 * theta_h - theta_r;
182 
183  float costheta_i, sintheta_i;
184  fast_sincosf(theta_i, &sintheta_i, &costheta_i);
185 
186  float phi = 2 * safe_asinf(1 - 2 * randv) * roughness2;
187 
188  float phi_pdf = fast_cosf(phi * 0.5f) * 0.25f / roughness2;
189 
190  float theta_pdf = roughness1 /
191  (2 * (t * t + roughness1 * roughness1) * (a_R - b_R) * costheta_i);
192 
193  float sinphi, cosphi;
194  fast_sincosf(phi, &sinphi, &cosphi);
195  *omega_in = (cosphi * costheta_i) * locy - (sinphi * costheta_i) * locx + (sintheta_i)*Tg;
196 
197  // differentials - TODO: find a better approximation for the reflective bounce
198 #ifdef __RAY_DIFFERENTIALS__
199  *domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
200  *domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
201 #endif
202 
203  *pdf = fabsf(phi_pdf * theta_pdf);
204  if (M_PI_2_F - fabsf(theta_i) < 0.001f)
205  *pdf = 0.0f;
206 
207  *eval = make_float3(*pdf, *pdf, *pdf);
208 
209  return LABEL_REFLECT | LABEL_GLOSSY;
210 }
211 
213  float3 Ng,
214  float3 I,
215  float3 dIdx,
216  float3 dIdy,
217  float randu,
218  float randv,
219  ccl_private float3 *eval,
220  ccl_private float3 *omega_in,
221  ccl_private float3 *domega_in_dx,
222  ccl_private float3 *domega_in_dy,
223  ccl_private float *pdf)
224 {
225  ccl_private const HairBsdf *bsdf = (ccl_private const HairBsdf *)sc;
226  float offset = bsdf->offset;
227  float3 Tg = bsdf->T;
228  float roughness1 = bsdf->roughness1;
229  float roughness2 = bsdf->roughness2;
230  float Iz = dot(Tg, I);
231  float3 locy = normalize(I - Tg * Iz);
232  float3 locx = cross(locy, Tg);
233  float theta_r = M_PI_2_F - fast_acosf(Iz);
234 
235  float roughness1_inv = 1.0f / roughness1;
236  float a_TT = fast_atan2f(((M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
237  float b_TT = fast_atan2f(((-M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f);
238  float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f);
239 
240  float t = roughness1 * tanf(randu * (a_TT - b_TT) + b_TT);
241 
242  float theta_h = t + offset;
243  float theta_i = 2 * theta_h - theta_r;
244 
245  float costheta_i, sintheta_i;
246  fast_sincosf(theta_i, &sintheta_i, &costheta_i);
247 
248  float p = roughness2 * tanf(c_TT * (randv - 0.5f));
249  float phi = p + M_PI_F;
250  float theta_pdf = roughness1 /
251  (2 * (t * t + roughness1 * roughness1) * (a_TT - b_TT) * costheta_i);
252  float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
253 
254  float sinphi, cosphi;
255  fast_sincosf(phi, &sinphi, &cosphi);
256  *omega_in = (cosphi * costheta_i) * locy - (sinphi * costheta_i) * locx + (sintheta_i)*Tg;
257 
258  // differentials - TODO: find a better approximation for the transmission bounce
259 #ifdef __RAY_DIFFERENTIALS__
260  *domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
261  *domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
262 #endif
263 
264  *pdf = fabsf(phi_pdf * theta_pdf);
265  if (M_PI_2_F - fabsf(theta_i) < 0.001f) {
266  *pdf = 0.0f;
267  }
268 
269  *eval = make_float3(*pdf, *pdf, *pdf);
270 
271  /* TODO(sergey): Should always be negative, but seems some precision issue
272  * is involved here.
273  */
274  kernel_assert(dot(locy, *omega_in) < 1e-4f);
275 
276  return LABEL_TRANSMIT | LABEL_GLOSSY;
277 }
278 
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 int bsdf_hair_transmission_sample(ccl_private const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, ccl_private float3 *eval, ccl_private float3 *omega_in, ccl_private float3 *domega_in_dx, ccl_private float3 *domega_in_dy, ccl_private float *pdf)
Definition: bsdf_hair.h:212
ccl_device float3 bsdf_hair_transmission_eval_reflect(ccl_private const ShaderClosure *sc, const float3 I, const float3 omega_in, ccl_private float *pdf)
Definition: bsdf_hair.h:87
ccl_device int bsdf_hair_reflection_setup(ccl_private HairBsdf *bsdf)
Definition: bsdf_hair.h:24
ccl_device float3 bsdf_hair_reflection_eval_transmit(ccl_private const ShaderClosure *sc, const float3 I, const float3 omega_in, ccl_private float *pdf)
Definition: bsdf_hair.h:96
ccl_device float3 bsdf_hair_transmission_eval_transmit(ccl_private const ShaderClosure *sc, const float3 I, const float3 omega_in, ccl_private float *pdf)
Definition: bsdf_hair.h:105
ccl_device int bsdf_hair_reflection_sample(ccl_private const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, ccl_private float3 *eval, ccl_private float3 *omega_in, ccl_private float3 *domega_in_dx, ccl_private float3 *domega_in_dy, ccl_private float *pdf)
Definition: bsdf_hair.h:151
ccl_device int bsdf_hair_transmission_setup(ccl_private HairBsdf *bsdf)
Definition: bsdf_hair.h:32
ccl_device float3 bsdf_hair_reflection_eval_reflect(ccl_private const ShaderClosure *sc, const float3 I, const float3 omega_in, ccl_private float *pdf)
Definition: bsdf_hair.h:40
CCL_NAMESPACE_BEGIN struct HairBsdf HairBsdf
#define kernel_assert(cond)
Definition: cpu/compat.h:34
#define ccl_device
Definition: cuda/compat.h:32
#define ccl_private
Definition: cuda/compat.h:48
#define tanf(x)
Definition: cuda/compat.h:104
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
@ CLOSURE_BSDF_HAIR_TRANSMISSION_ID
@ CLOSURE_BSDF_HAIR_REFLECTION_ID
@ SD_BSDF_HAS_EVAL
Definition: kernel/types.h:744
@ SD_BSDF
Definition: kernel/types.h:742
@ LABEL_TRANSMIT
Definition: kernel/types.h:317
@ LABEL_GLOSSY
Definition: kernel/types.h:320
@ LABEL_REFLECT
Definition: kernel/types.h:318
ShaderClosure
Definition: kernel/types.h:726
ccl_device void fast_sincosf(float x, ccl_private float *sine, ccl_private float *cosine)
Definition: math_fast.h:134
ccl_device float fast_acosf(float x)
Definition: math_fast.h:253
ccl_device float fast_atan2f(float y, float x)
Definition: math_fast.h:304
ccl_device float fast_cosf(float x)
Definition: math_fast.h:106
#define fabsf(x)
Definition: metal/compat.h:219
#define make_float3(x, y, z)
Definition: metal/compat.h:204
T dot(const vec_base< T, Size > &a, const vec_base< T, Size > &b)
vec_base< T, 3 > cross(const vec_base< T, 3 > &a, const vec_base< T, 3 > &b)
T clamp(const T &a, const T &min, const T &max)
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
#define I
float roughness1
Definition: bsdf_hair.h:17
float offset
Definition: bsdf_hair.h:19
float roughness2
Definition: bsdf_hair.h:18
SHADER_CLOSURE_BASE
Definition: bsdf_hair.h:14
float3 T
Definition: bsdf_hair.h:16
#define M_PI_2_F
Definition: util/math.h:37
#define M_PI_F
Definition: util/math.h:34