Blender  V2.93
bsdf_microfacet_multi_impl.h
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* Evaluate the BSDF from wi to wo.
18  * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF,
19  * which is evaluated stochastically through a random walk. At each bounce (except for the first
20  * one), the amount of reflection from here towards wo is evaluated before bouncing again.
21  *
22  * Because of the random walk, the evaluation is not deterministic, but its expected value is equal
23  * to the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined
24  * analytically, so the single-scattering PDF plus a diffuse term to account for the
25  * multi-scattered energy is used. In combination with MIS, that is enough to produce an unbiased
26  * result, although the balance heuristic isn't necessarily optimal anymore.
27  */
29  float3 wo,
30  const bool wo_outside,
31  const float3 color,
32  const float alpha_x,
33  const float alpha_y,
34  ccl_addr_space uint *lcg_state,
35  const float eta,
36  bool use_fresnel,
37  const float3 cspec0)
38 {
39  /* Evaluating for a shallower incoming direction produces less noise, and the properties of the
40  * BSDF guarantee reciprocity. */
41  bool swapped = false;
42 #ifdef MF_MULTI_GLASS
43  if (wi.z * wo.z < 0.0f) {
44  /* Glass transmission is a special case and requires the directions to change hemisphere. */
45  if (-wo.z < wi.z) {
46  swapped = true;
47  float3 tmp = -wo;
48  wo = -wi;
49  wi = tmp;
50  }
51  }
52  else
53 #endif
54  if (wo.z < wi.z) {
55  swapped = true;
56  float3 tmp = wo;
57  wo = wi;
58  wi = tmp;
59  }
60 
61  if (wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside))
62  return make_float3(0.0f, 0.0f, 0.0f);
63 
64  const float2 alpha = make_float2(alpha_x, alpha_y);
65 
66  float lambda_r = mf_lambda(-wi, alpha);
67  float shadowing_lambda = mf_lambda(wo_outside ? wo : -wo, alpha);
68 
69  /* Analytically compute single scattering for lower noise. */
70  float3 eval;
71  float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
72  const float3 wh = normalize(wi + wo);
73 #ifdef MF_MULTI_GLASS
74  eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta);
75  if (wo_outside)
76  eval *= -lambda_r / (shadowing_lambda - lambda_r);
77  else
78  eval *= -lambda_r * beta(-lambda_r, shadowing_lambda + 1.0f);
79 #else /* MF_MULTI_GLOSSY */
80  const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda);
81  float val = G2 * 0.25f / wi.z;
82  if (alpha.x == alpha.y)
83  val *= D_ggx(wh, alpha.x);
84  else
85  val *= D_ggx_aniso(wh, alpha);
86  eval = make_float3(val, val, val);
87 #endif
88 
89  float F0 = fresnel_dielectric_cos(1.0f, eta);
90  if (use_fresnel) {
91  throughput = interpolate_fresnel_color(wi, wh, eta, F0, cspec0);
92 
93  eval *= throughput;
94  }
95 
96  float3 wr = -wi;
97  float hr = 1.0f;
98  float C1_r = 1.0f;
99  float G1_r = 0.0f;
100  bool outside = true;
101 
102  for (int order = 0; order < 10; order++) {
103  /* Sample microfacet height. */
104  float height_rand = lcg_step_float_addrspace(lcg_state);
105  if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand))
106  break;
107  /* Sample microfacet normal. */
108  float vndf_rand_y = lcg_step_float_addrspace(lcg_state);
109  float vndf_rand_x = lcg_step_float_addrspace(lcg_state);
110  float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y);
111 
112 #ifdef MF_MULTI_GLASS
113  if (order == 0 && use_fresnel) {
114  /* Evaluate amount of scattering towards wo on this microfacet. */
115  float3 phase;
116  if (outside)
117  phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta);
118  else
119  phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta);
120 
121  eval = throughput * phase *
122  mf_G1(wo_outside ? wo : -wo,
123  mf_C1((outside == wo_outside) ? hr : -hr),
124  shadowing_lambda);
125  }
126 #endif
127  if (order > 0) {
128  /* Evaluate amount of scattering towards wo on this microfacet. */
129  float3 phase;
130 #ifdef MF_MULTI_GLASS
131  if (outside)
132  phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta);
133  else
134  phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta);
135 #else /* MF_MULTI_GLOSSY */
136  phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha) * throughput;
137 #endif
138  eval += throughput * phase *
139  mf_G1(wo_outside ? wo : -wo,
140  mf_C1((outside == wo_outside) ? hr : -hr),
141  shadowing_lambda);
142  }
143  if (order + 1 < 10) {
144  /* Bounce from the microfacet. */
145 #ifdef MF_MULTI_GLASS
146  bool next_outside;
147  float3 wi_prev = -wr;
148  float phase_rand = lcg_step_float_addrspace(lcg_state);
149  wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside);
150  if (!next_outside) {
151  outside = !outside;
152  wr = -wr;
153  hr = -hr;
154  }
155 
156  if (use_fresnel && !next_outside) {
157  throughput *= color;
158  }
159  else if (use_fresnel && order > 0) {
160  throughput *= interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0);
161  }
162 #else /* MF_MULTI_GLOSSY */
163  if (use_fresnel && order > 0) {
164  throughput *= interpolate_fresnel_color(-wr, wm, eta, F0, cspec0);
165  }
166  wr = mf_sample_phase_glossy(-wr, &throughput, wm);
167 #endif
168 
169  lambda_r = mf_lambda(wr, alpha);
170 
171  if (!use_fresnel)
172  throughput *= color;
173 
174  C1_r = mf_C1(hr);
175  G1_r = mf_G1(wr, C1_r, lambda_r);
176  }
177  }
178 
179  if (swapped)
180  eval *= fabsf(wi.z / wo.z);
181  return eval;
182 }
183 
184 /* Perform a random walk on the microsurface starting from wi, returning the direction in which the
185  * walk escaped the surface in wo. The function returns the throughput between wi and wo. Without
186  * reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal.
187  */
189  float3 *wo,
190  const float3 color,
191  const float alpha_x,
192  const float alpha_y,
193  ccl_addr_space uint *lcg_state,
194  const float eta,
195  bool use_fresnel,
196  const float3 cspec0)
197 {
198  const float2 alpha = make_float2(alpha_x, alpha_y);
199 
200  float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
201  float3 wr = -wi;
202  float lambda_r = mf_lambda(wr, alpha);
203  float hr = 1.0f;
204  float C1_r = 1.0f;
205  float G1_r = 0.0f;
206  bool outside = true;
207 
208  float F0 = fresnel_dielectric_cos(1.0f, eta);
209  if (use_fresnel) {
210  throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0);
211  }
212 
213  int order;
214  for (order = 0; order < 10; order++) {
215  /* Sample microfacet height. */
216  float height_rand = lcg_step_float_addrspace(lcg_state);
217  if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) {
218  /* The random walk has left the surface. */
219  *wo = outside ? wr : -wr;
220  return throughput;
221  }
222  /* Sample microfacet normal. */
223  float vndf_rand_y = lcg_step_float_addrspace(lcg_state);
224  float vndf_rand_x = lcg_step_float_addrspace(lcg_state);
225  float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y);
226 
227  /* First-bounce color is already accounted for in mix weight. */
228  if (!use_fresnel && order > 0)
229  throughput *= color;
230 
231  /* Bounce from the microfacet. */
232 #ifdef MF_MULTI_GLASS
233  bool next_outside;
234  float3 wi_prev = -wr;
235  float phase_rand = lcg_step_float_addrspace(lcg_state);
236  wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside);
237  if (!next_outside) {
238  hr = -hr;
239  wr = -wr;
240  outside = !outside;
241  }
242 
243  if (use_fresnel) {
244  if (!next_outside) {
245  throughput *= color;
246  }
247  else {
248  float3 t_color = interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0);
249 
250  if (order == 0)
251  throughput = t_color;
252  else
253  throughput *= t_color;
254  }
255  }
256 #else /* MF_MULTI_GLOSSY */
257  if (use_fresnel) {
258  float3 t_color = interpolate_fresnel_color(-wr, wm, eta, F0, cspec0);
259 
260  if (order == 0)
261  throughput = t_color;
262  else
263  throughput *= t_color;
264  }
265  wr = mf_sample_phase_glossy(-wr, &throughput, wm);
266 #endif
267 
268  /* Update random walk parameters. */
269  lambda_r = mf_lambda(wr, alpha);
270  G1_r = mf_G1(wr, C1_r, lambda_r);
271  }
272  *wo = make_float3(0.0f, 0.0f, 1.0f);
273  return make_float3(0.0f, 0.0f, 0.0f);
274 }
275 
276 #undef MF_MULTI_GLASS
277 #undef MF_MULTI_GLOSSY
278 #undef MF_PHASE_FUNCTION
unsigned int uint
Definition: BLI_sys_types.h:83
_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 order
ccl_device_forceinline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U)
ccl_device_forceinline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha)
ccl_device_forceinline float D_ggx_aniso(const float3 wm, const float2 alpha)
ccl_device_forceinline float mf_C1(const float h)
ccl_device_forceinline float mf_lambda(const float3 w, const float2 alpha)
ccl_device_forceinline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta)
ccl_device_forceinline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside)
#define MF_FUNCTION_FULL_NAME(prefix)
CCL_NAMESPACE_BEGIN ccl_device_forceinline float D_ggx(float3 wm, float alpha)
ccl_device_forceinline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float randx, const float randy)
ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi, float3 *weight, const float3 wm)
ccl_device_forceinline float mf_G1(const float3 w, const float C1, const float lambda)
ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME() mf_eval(float3 wi, float3 wo, const bool wo_outside, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state, const float eta, bool use_fresnel, const float3 cspec0)
ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME() mf_sample(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state, const float eta, bool use_fresnel, const float3 cspec0)
ccl_device float fresnel_dielectric_cos(float cosi, float eta)
Definition: bsdf_util.h:104
ccl_device_forceinline float3 interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0)
Definition: bsdf_util.h:139
static CCL_NAMESPACE_BEGIN const double alpha
#define ccl_addr_space
#define ccl_device_forceinline
#define make_float2(x, y)
#define fabsf(x)
#define make_float3(x, y, z)
ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng)
ccl_device_inline float beta(float x, float y)
Definition: util_math.h:666
ccl_device_inline float2 normalize(const float2 &a)