Blender  V3.3
bsdf_ashikhmin_shirley.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 /*
5  * ASHIKHMIN SHIRLEY BSDF
6  *
7  * Implementation of
8  * Michael Ashikhmin and Peter Shirley: "An Anisotropic Phong BRDF Model" (2000)
9  *
10  * The Fresnel factor is missing to get a separable bsdf (intensity*color), as is
11  * the case with all other microfacet-based BSDF implementations in Cycles.
12  *
13  * Other than that, the implementation directly follows the paper.
14  */
15 
16 #pragma once
17 
19 
21 {
22  bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
23  bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
24 
26  return SD_BSDF | SD_BSDF_HAS_EVAL;
27 }
28 
30 {
32 
33  bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
34  bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
35 }
36 
38 {
39  return 2.0f / (roughness * roughness) - 2.0f;
40 }
41 
44  const float3 I,
45  const float3 omega_in,
46  ccl_private float *pdf)
47 {
48  ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
49  float3 N = bsdf->N;
50 
51  float NdotI = dot(N, I); /* in Cycles/OSL convention I is omega_out */
52  float NdotO = dot(N, omega_in); /* and consequently we use for O omaga_in ;) */
53 
54  float out = 0.0f;
55 
56  if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) {
57  *pdf = 0.0f;
58  return make_float3(0.0f, 0.0f, 0.0f);
59  }
60  if (NdotI > 0.0f && NdotO > 0.0f) {
61  NdotI = fmaxf(NdotI, 1e-6f);
62  NdotO = fmaxf(NdotO, 1e-6f);
63  float3 H = normalize(omega_in + I);
64  float HdotI = fmaxf(fabsf(dot(H, I)), 1e-6f);
65  float HdotN = fmaxf(dot(H, N), 1e-6f);
66 
67  /* pump from original paper
68  * (first derivative disc., but cancels the HdotI in the pdf nicely) */
69  float pump = 1.0f / fmaxf(1e-6f, (HdotI * fmaxf(NdotO, NdotI)));
70  /* pump from d-brdf paper */
71  /*float pump = 1.0f / fmaxf(1e-4f, ((NdotO + NdotI) * (NdotO*NdotI))); */
72 
73  float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x);
74  float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y);
75 
76  if (n_x == n_y) {
77  /* isotropic */
78  float e = n_x;
79  float lobe = powf(HdotN, e);
80  float norm = (n_x + 1.0f) / (8.0f * M_PI_F);
81 
82  out = NdotO * norm * lobe * pump;
83  /* this is p_h / 4(H.I) (conversion from 'wh measure' to 'wi measure', eq. 8 in paper). */
84  *pdf = norm * lobe / HdotI;
85  }
86  else {
87  /* anisotropic */
88  float3 X, Y;
89  make_orthonormals_tangent(N, bsdf->T, &X, &Y);
90 
91  float HdotX = dot(H, X);
92  float HdotY = dot(H, Y);
93  float lobe;
94  if (HdotN < 1.0f) {
95  float e = (n_x * HdotX * HdotX + n_y * HdotY * HdotY) / (1.0f - HdotN * HdotN);
96  lobe = powf(HdotN, e);
97  }
98  else {
99  lobe = 1.0f;
100  }
101  float norm = sqrtf((n_x + 1.0f) * (n_y + 1.0f)) / (8.0f * M_PI_F);
102 
103  out = NdotO * norm * lobe * pump;
104  *pdf = norm * lobe / HdotI;
105  }
106  }
107 
108  return make_float3(out, out, out);
109 }
110 
112  const float3 I,
113  const float3 omega_in,
114  ccl_private float *pdf)
115 {
116  *pdf = 0.0f;
117  return make_float3(0.0f, 0.0f, 0.0f);
118 }
119 
121  float n_y,
122  float randu,
123  float randv,
124  ccl_private float *phi,
125  ccl_private float *cos_theta)
126 {
127  *phi = atanf(sqrtf((n_x + 1.0f) / (n_y + 1.0f)) * tanf(M_PI_2_F * randu));
128  float cos_phi = cosf(*phi);
129  float sin_phi = sinf(*phi);
130  *cos_theta = powf(randv, 1.0f / (n_x * cos_phi * cos_phi + n_y * sin_phi * sin_phi + 1.0f));
131 }
132 
134  float3 Ng,
135  float3 I,
136  float3 dIdx,
137  float3 dIdy,
138  float randu,
139  float randv,
140  ccl_private float3 *eval,
141  ccl_private float3 *omega_in,
142  ccl_private float3 *domega_in_dx,
143  ccl_private float3 *domega_in_dy,
144  ccl_private float *pdf)
145 {
146  ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
147  float3 N = bsdf->N;
149 
150  float NdotI = dot(N, I);
151  if (NdotI > 0.0f) {
152 
153  float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x);
154  float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y);
155 
156  /* get x,y basis on the surface for anisotropy */
157  float3 X, Y;
158 
159  if (n_x == n_y)
160  make_orthonormals(N, &X, &Y);
161  else
162  make_orthonormals_tangent(N, bsdf->T, &X, &Y);
163 
164  /* sample spherical coords for h in tangent space */
165  float phi;
166  float cos_theta;
167  if (n_x == n_y) {
168  /* isotropic sampling */
169  phi = M_2PI_F * randu;
170  cos_theta = powf(randv, 1.0f / (n_x + 1.0f));
171  }
172  else {
173  /* anisotropic sampling */
174  if (randu < 0.25f) { /* first quadrant */
175  float remapped_randu = 4.0f * randu;
177  n_x, n_y, remapped_randu, randv, &phi, &cos_theta);
178  }
179  else if (randu < 0.5f) { /* second quadrant */
180  float remapped_randu = 4.0f * (.5f - randu);
182  n_x, n_y, remapped_randu, randv, &phi, &cos_theta);
183  phi = M_PI_F - phi;
184  }
185  else if (randu < 0.75f) { /* third quadrant */
186  float remapped_randu = 4.0f * (randu - 0.5f);
188  n_x, n_y, remapped_randu, randv, &phi, &cos_theta);
189  phi = M_PI_F + phi;
190  }
191  else { /* fourth quadrant */
192  float remapped_randu = 4.0f * (1.0f - randu);
194  n_x, n_y, remapped_randu, randv, &phi, &cos_theta);
195  phi = 2.0f * M_PI_F - phi;
196  }
197  }
198 
199  /* get half vector in tangent space */
200  float sin_theta = sqrtf(fmaxf(0.0f, 1.0f - cos_theta * cos_theta));
201  float cos_phi = cosf(phi);
202  float sin_phi = sinf(phi); /* no sqrt(1-cos^2) here b/c it causes artifacts */
203  float3 h = make_float3(sin_theta * cos_phi, sin_theta * sin_phi, cos_theta);
204 
205  /* half vector to world space */
206  float3 H = h.x * X + h.y * Y + h.z * N;
207  float HdotI = dot(H, I);
208  if (HdotI < 0.0f)
209  H = -H;
210 
211  /* reflect I on H to get omega_in */
212  *omega_in = -I + (2.0f * HdotI) * H;
213 
214  if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) {
215  /* Some high number for MIS. */
216  *pdf = 1e6f;
217  *eval = make_float3(1e6f, 1e6f, 1e6f);
219  }
220  else {
221  /* leave the rest to eval_reflect */
222  *eval = bsdf_ashikhmin_shirley_eval_reflect(sc, I, *omega_in, pdf);
223  }
224 
225 #ifdef __RAY_DIFFERENTIALS__
226  /* just do the reflection thing for now */
227  *domega_in_dx = (2.0f * dot(N, dIdx)) * N - dIdx;
228  *domega_in_dy = (2.0f * dot(N, dIdy)) * N - dIdy;
229 #endif
230  }
231 
232  return label;
233 }
234 
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color or the default fallback if none is specified Separate Split a vector into its X
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color or the default fallback if none is specified Separate Split a vector into its Y
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ccl_device void bsdf_ashikhmin_shirley_blur(ccl_private ShaderClosure *sc, float roughness)
ccl_device float3 bsdf_ashikhmin_shirley_eval_transmit(ccl_private const ShaderClosure *sc, const float3 I, const float3 omega_in, ccl_private float *pdf)
ccl_device_forceinline float3 bsdf_ashikhmin_shirley_eval_reflect(ccl_private const ShaderClosure *sc, const float3 I, const float3 omega_in, ccl_private float *pdf)
ccl_device int bsdf_ashikhmin_shirley_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)
ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float roughness)
CCL_NAMESPACE_BEGIN ccl_device int bsdf_ashikhmin_shirley_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant(float n_x, float n_y, float randu, float randv, ccl_private float *phi, ccl_private float *cos_theta)
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition: btVector3.h:263
#define ccl_device_forceinline
Definition: cuda/compat.h:35
#define sinf(x)
Definition: cuda/compat.h:102
#define cosf(x)
Definition: cuda/compat.h:101
#define ccl_device
Definition: cuda/compat.h:32
#define ccl_private
Definition: cuda/compat.h:48
#define ccl_device_inline
Definition: cuda/compat.h:34
#define tanf(x)
Definition: cuda/compat.h:104
#define powf(x, y)
Definition: cuda/compat.h:103
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
const char * label
@ CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID
@ SD_BSDF_HAS_EVAL
Definition: kernel/types.h:744
@ SD_BSDF
Definition: kernel/types.h:742
@ LABEL_SINGULAR
Definition: kernel/types.h:321
@ LABEL_GLOSSY
Definition: kernel/types.h:320
@ LABEL_REFLECT
Definition: kernel/types.h:318
ShaderClosure
Definition: kernel/types.h:726
#define N
#define H(x, y, z)
#define fmaxf(x, y)
Definition: metal/compat.h:228
#define atanf(x)
Definition: metal/compat.h:223
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
#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)
T clamp(const T &a, const T &min, const T &max)
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
#define I
ccl_device void make_orthonormals_tangent(const float3 N, const float3 T, ccl_private float3 *a, ccl_private float3 *b)
float z
float y
float x
#define M_PI_2_F
Definition: util/math.h:37
#define M_2PI_F
Definition: util/math.h:60
#define M_PI_F
Definition: util/math.h:34
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
Definition: util/math.h:566