Blender  V2.93
kernel_subsurface.h
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2013 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 
18 
19 /* BSSRDF using disk based importance sampling.
20  *
21  * BSSRDF Importance Sampling, SIGGRAPH 2013
22  * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf
23  */
24 
26 subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, float r, bool all)
27 {
28  /* This is the Veach one-sample model with balance heuristic, some pdf
29  * factors drop out when using balance heuristic weighting. For branched
30  * path tracing (all) we sample all closure and don't use MIS. */
31  float3 eval_sum = zero_float3();
32  float pdf_sum = 0.0f;
33  float sample_weight_inv = 0.0f;
34 
35  if (!all) {
36  float sample_weight_sum = 0.0f;
37 
38  for (int i = 0; i < sd->num_closure; i++) {
39  sc = &sd->closure[i];
40 
41  if (CLOSURE_IS_DISK_BSSRDF(sc->type)) {
42  sample_weight_sum += sc->sample_weight;
43  }
44  }
45 
46  sample_weight_inv = 1.0f / sample_weight_sum;
47  }
48 
49  for (int i = 0; i < sd->num_closure; i++) {
50  sc = &sd->closure[i];
51 
52  if (CLOSURE_IS_DISK_BSSRDF(sc->type)) {
53  /* in case of branched path integrate we sample all bssrdf's once,
54  * for path trace we pick one, so adjust pdf for that */
55  float sample_weight = (all) ? 1.0f : sc->sample_weight * sample_weight_inv;
56 
57  /* compute pdf */
58  float3 eval = bssrdf_eval(sc, r);
59  float pdf = bssrdf_pdf(sc, disk_r);
60 
61  eval_sum += sc->weight * eval;
62  pdf_sum += sample_weight * pdf;
63  }
64  }
65 
66  return (pdf_sum > 0.0f) ? eval_sum / pdf_sum : zero_float3();
67 }
68 
70  const ShaderClosure *sc,
71  float3 throughput,
72  bool all)
73 {
74  /* This is the Veach one-sample model with balance heuristic, some pdf
75  * factors drop out when using balance heuristic weighting. For branched
76  * path tracing (all) we sample all closure and don't use MIS. */
77  if (!all) {
78  float bssrdf_weight = 0.0f;
79  float weight = sc->sample_weight;
80 
81  for (int i = 0; i < sd->num_closure; i++) {
82  sc = &sd->closure[i];
83 
84  if (CLOSURE_IS_BSSRDF(sc->type)) {
85  bssrdf_weight += sc->sample_weight;
86  }
87  }
88  throughput *= bssrdf_weight / weight;
89  }
90  return throughput;
91 }
92 
93 /* replace closures with a single diffuse bsdf closure after scatter step */
95  KernelGlobals *kg, ShaderData *sd, ClosureType type, float roughness, float3 weight, float3 N)
96 {
97  sd->flag &= ~SD_CLOSURE_FLAGS;
98  sd->num_closure = 0;
99  sd->num_closure_left = kernel_data.integrator.max_closures;
100 
101 #ifdef __PRINCIPLED__
104  sd, sizeof(PrincipledDiffuseBsdf), weight);
105 
106  if (bsdf) {
107  bsdf->N = N;
108  bsdf->roughness = roughness;
109  sd->flag |= bsdf_principled_diffuse_setup(bsdf);
110 
111  /* replace CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID with this special ID so render passes
112  * can recognize it as not being a regular Disney principled diffuse closure */
114  }
115  }
117 #endif /* __PRINCIPLED__ */
118  {
119  DiffuseBsdf *bsdf = (DiffuseBsdf *)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight);
120 
121  if (bsdf) {
122  bsdf->N = N;
123  sd->flag |= bsdf_diffuse_setup(bsdf);
124 
125  /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
126  * can recognize it as not being a regular diffuse closure */
127  bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
128  }
129  }
130 }
131 
132 /* optionally do blurring of color and/or bump mapping, at the cost of a shader evaluation */
134 {
135  color = max(color, zero_float3());
136 
137  if (exponent == 1.0f) {
138  /* nothing to do */
139  }
140  else if (exponent == 0.5f) {
141  color.x = sqrtf(color.x);
142  color.y = sqrtf(color.y);
143  color.z = sqrtf(color.z);
144  }
145  else {
146  color.x = powf(color.x, exponent);
147  color.y = powf(color.y, exponent);
148  color.z = powf(color.z, exponent);
149  }
150 
151  return color;
152 }
153 
155  KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, float3 *eval, float3 *N)
156 {
157  /* average color and texture blur at outgoing point */
158  float texture_blur;
159  float3 out_color = shader_bssrdf_sum(sd, NULL, &texture_blur);
160 
161  /* do we have bump mapping? */
162  bool bump = (sd->flag & SD_HAS_BSSRDF_BUMP) != 0;
163 
164  if (bump || texture_blur > 0.0f) {
165  /* average color and normal at incoming point */
166  shader_eval_surface(kg, sd, state, NULL, state->flag);
167  float3 in_color = shader_bssrdf_sum(sd, (bump) ? N : NULL, NULL);
168 
169  /* we simply divide out the average color and multiply with the average
170  * of the other one. we could try to do this per closure but it's quite
171  * tricky to match closures between shader evaluations, their number and
172  * order may change, this is simpler */
173  if (texture_blur > 0.0f) {
174  out_color = subsurface_color_pow(out_color, texture_blur);
175  in_color = subsurface_color_pow(in_color, texture_blur);
176 
177  *eval *= safe_divide_color(in_color, out_color);
178  }
179  }
180 }
181 
182 /* Subsurface scattering step, from a point on the surface to other
183  * nearby points on the same object.
184  */
186  LocalIntersection *ss_isect,
187  ShaderData *sd,
188  const ShaderClosure *sc,
189  uint *lcg_state,
190  float disk_u,
191  float disk_v,
192  bool all)
193 {
194  /* pick random axis in local frame and point on disk */
195  float3 disk_N, disk_T, disk_B;
196  float pick_pdf_N, pick_pdf_T, pick_pdf_B;
197 
198  disk_N = sd->Ng;
199  make_orthonormals(disk_N, &disk_T, &disk_B);
200 
201  if (disk_v < 0.5f) {
202  pick_pdf_N = 0.5f;
203  pick_pdf_T = 0.25f;
204  pick_pdf_B = 0.25f;
205  disk_v *= 2.0f;
206  }
207  else if (disk_v < 0.75f) {
208  float3 tmp = disk_N;
209  disk_N = disk_T;
210  disk_T = tmp;
211  pick_pdf_N = 0.25f;
212  pick_pdf_T = 0.5f;
213  pick_pdf_B = 0.25f;
214  disk_v = (disk_v - 0.5f) * 4.0f;
215  }
216  else {
217  float3 tmp = disk_N;
218  disk_N = disk_B;
219  disk_B = tmp;
220  pick_pdf_N = 0.25f;
221  pick_pdf_T = 0.25f;
222  pick_pdf_B = 0.5f;
223  disk_v = (disk_v - 0.75f) * 4.0f;
224  }
225 
226  /* sample point on disk */
227  float phi = M_2PI_F * disk_v;
228  float disk_height, disk_r;
229 
230  bssrdf_sample(sc, disk_u, &disk_r, &disk_height);
231 
232  float3 disk_P = (disk_r * cosf(phi)) * disk_T + (disk_r * sinf(phi)) * disk_B;
233 
234  /* create ray */
235 #ifdef __SPLIT_KERNEL__
236  Ray ray_object = ss_isect->ray;
237  Ray *ray = &ray_object;
238 #else
239  Ray *ray = &ss_isect->ray;
240 #endif
241  ray->P = sd->P + disk_N * disk_height + disk_P;
242  ray->D = -disk_N;
243  ray->t = 2.0f * disk_height;
244  ray->dP = sd->dP;
245  ray->dD = differential3_zero();
246  ray->time = sd->time;
247 
248  /* intersect with the same object. if multiple intersections are found it
249  * will use at most BSSRDF_MAX_HITS hits, a random subset of all hits */
250  scene_intersect_local(kg, ray, ss_isect, sd->object, lcg_state, BSSRDF_MAX_HITS);
251  int num_eval_hits = min(ss_isect->num_hits, BSSRDF_MAX_HITS);
252 
253  for (int hit = 0; hit < num_eval_hits; hit++) {
254  /* Quickly retrieve P and Ng without setting up ShaderData. */
255  float3 hit_P;
256  if (sd->type & PRIMITIVE_TRIANGLE) {
257  hit_P = triangle_refine_local(kg, sd, &ss_isect->hits[hit], ray);
258  }
259 #ifdef __OBJECT_MOTION__
260  else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
261  float3 verts[3];
263  sd->object,
264  kernel_tex_fetch(__prim_index, ss_isect->hits[hit].prim),
265  sd->time,
266  verts);
267  hit_P = motion_triangle_refine_local(kg, sd, &ss_isect->hits[hit], ray, verts);
268  }
269 #endif /* __OBJECT_MOTION__ */
270  else {
271  ss_isect->weight[hit] = zero_float3();
272  continue;
273  }
274 
275  float3 hit_Ng = ss_isect->Ng[hit];
276  if (ss_isect->hits[hit].object != OBJECT_NONE) {
277  object_normal_transform(kg, sd, &hit_Ng);
278  }
279 
280  /* Probability densities for local frame axes. */
281  float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
282  float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
283  float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
284 
285  /* Multiple importance sample between 3 axes, power heuristic
286  * found to be slightly better than balance heuristic. pdf_N
287  * in the MIS weight and denominator cancelled out. */
288  float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
289  if (ss_isect->num_hits > BSSRDF_MAX_HITS) {
290  w *= ss_isect->num_hits / (float)BSSRDF_MAX_HITS;
291  }
292 
293  /* Real distance to sampled point. */
294  float r = len(hit_P - sd->P);
295 
296  /* Evaluate profiles. */
297  float3 eval = subsurface_scatter_eval(sd, sc, disk_r, r, all) * w;
298 
299  ss_isect->weight[hit] = eval;
300  }
301 
302 #ifdef __SPLIT_KERNEL__
303  ss_isect->ray = *ray;
304 #endif
305 
306  return num_eval_hits;
307 }
308 
309 #if defined(__KERNEL_OPTIX__) && defined(__SHADER_RAYTRACE__)
311  LocalIntersection *ss_isect,
312  int hit,
313  ShaderData *sd,
316  float roughness)
317 {
318  optixDirectCall<void>(2, kg, ss_isect, hit, sd, state, type, roughness);
319 }
320 extern "C" __device__ void __direct_callable__subsurface_scatter_multi_setup(
321 #else
323 #endif
324  KernelGlobals *kg,
325  LocalIntersection *ss_isect,
326  int hit,
327  ShaderData *sd,
330  float roughness)
331 {
332 #ifdef __SPLIT_KERNEL__
333  Ray ray_object = ss_isect->ray;
334  Ray *ray = &ray_object;
335 #else
336  Ray *ray = &ss_isect->ray;
337 #endif
338 
339  /* Workaround for AMD GPU OpenCL compiler. Most probably cache bypass issue. */
340 #if defined(__SPLIT_KERNEL__) && defined(__KERNEL_OPENCL_AMD__) && defined(__KERNEL_GPU__)
341  kernel_split_params.dummy_sd_flag = sd->flag;
342 #endif
343 
344  /* Setup new shading point. */
345  shader_setup_from_subsurface(kg, sd, &ss_isect->hits[hit], ray);
346 
347  /* Optionally blur colors and bump mapping. */
348  float3 weight = ss_isect->weight[hit];
349  float3 N = sd->N;
350  subsurface_color_bump_blur(kg, sd, state, &weight, &N);
351 
352  /* Setup diffuse BSDF. */
354 }
355 
356 /* Random walk subsurface scattering.
357  *
358  * "Practical and Controllable Subsurface Scattering for Production Path
359  * Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */
360 
362  const float d,
363  float *sigma_t,
364  float *alpha)
365 {
366  /* Compute attenuation and scattering coefficients from albedo. */
367  *alpha = 1.0f - expf(A * (-5.09406f + A * (2.61188f - A * 4.31805f)));
368  const float s = 1.9f - A + 3.5f * sqr(A - 0.8f);
369 
370  *sigma_t = 1.0f / fmaxf(d * s, 1e-16f);
371 }
372 
374  float3 *sigma_t,
375  float3 *alpha,
376  float3 *weight)
377 {
378  const Bssrdf *bssrdf = (const Bssrdf *)sc;
379  const float3 A = bssrdf->albedo;
380  const float3 d = bssrdf->radius;
381  float sigma_t_x, sigma_t_y, sigma_t_z;
382  float alpha_x, alpha_y, alpha_z;
383 
384  subsurface_random_walk_remap(A.x, d.x, &sigma_t_x, &alpha_x);
385  subsurface_random_walk_remap(A.y, d.y, &sigma_t_y, &alpha_y);
386  subsurface_random_walk_remap(A.z, d.z, &sigma_t_z, &alpha_z);
387 
388  *sigma_t = make_float3(sigma_t_x, sigma_t_y, sigma_t_z);
389  *alpha = make_float3(alpha_x, alpha_y, alpha_z);
390 
391  /* Closure mixing and Fresnel weights separate from albedo. */
392  *weight = safe_divide_color(bssrdf->weight, A);
393 }
394 
395 /* References for Dwivedi sampling:
396  *
397  * [1] "A Zero-variance-based Sampling Scheme for Monte Carlo Subsurface Scattering"
398  * by Jaroslav KÅ™ivánek and Eugene d'Eon (SIGGRAPH 2014)
399  * https://cgg.mff.cuni.cz/~jaroslav/papers/2014-zerovar/
400  *
401  * [2] "Improving the Dwivedi Sampling Scheme"
402  * by Johannes Meng, Johannes Hanika, and Carsten Dachsbacher (EGSR 2016)
403  * https://cg.ivd.kit.edu/1951.php
404  *
405  * [3] "Zero-Variance Theory for Efficient Subsurface Scattering"
406  * by Eugene d'Eon and Jaroslav KÅ™ivánek (SIGGRAPH 2020)
407  * https://iliyan.com/publications/RenderingCourse2020
408  */
409 
410 ccl_device_forceinline float eval_phase_dwivedi(float v, float phase_log, float cos_theta)
411 {
412  /* Eq. 9 from [2] using precomputed log((v + 1) / (v - 1))*/
413  return 1.0f / ((v - cos_theta) * phase_log);
414 }
415 
416 ccl_device_forceinline float sample_phase_dwivedi(float v, float phase_log, float rand)
417 {
418  /* Based on Eq. 10 from [2]: `v - (v + 1) * pow((v - 1) / (v + 1), rand)`
419  * Since we're already pre-computing `phase_log = log((v + 1) / (v - 1))` for the evaluation,
420  * we can implement the power function like this. */
421  return v - (v + 1) * expf(-rand * phase_log);
422 }
423 
425 {
426  /* Eq. 67 from [3] */
427  return 1.0f / sqrtf(1.0f - powf(alpha, 2.44294f - 0.0215813f * alpha + 0.578637f / alpha));
428 }
429 
431 {
432  float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
433  float phi = M_2PI_F * randv;
434  float3 dir = make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cos_theta);
435 
436  float3 T, B;
437  make_orthonormals(D, &T, &B);
438  return dir.x * T + dir.y * B + dir.z * D;
439 }
440 
442  float t,
443  bool hit,
444  float3 *transmittance)
445 {
446  float3 T = volume_color_transmittance(sigma_t, t);
447  if (transmittance) {
448  *transmittance = T;
449  }
450  return hit ? T : sigma_t * T;
451 }
452 
453 #ifdef __KERNEL_OPTIX__
454 ccl_device_inline /* inline trace calls */
455 #else
457 #endif
458  bool
459  subsurface_random_walk(KernelGlobals *kg,
460  LocalIntersection *ss_isect,
461  ShaderData *sd,
463  const ShaderClosure *sc,
464  const float bssrdf_u,
465  const float bssrdf_v,
466  bool all)
467 {
468  /* Sample diffuse surface scatter into the object. */
469  float3 D;
470  float pdf;
471  sample_cos_hemisphere(-sd->N, bssrdf_u, bssrdf_v, &D, &pdf);
472  if (dot(-sd->Ng, D) <= 0.0f) {
473  return 0;
474  }
475 
476  /* Convert subsurface to volume coefficients.
477  * The single-scattering albedo is named alpha to avoid confusion with the surface albedo. */
478  float3 sigma_t, alpha;
479  float3 throughput = one_float3();
480  subsurface_random_walk_coefficients(sc, &sigma_t, &alpha, &throughput);
481  float3 sigma_s = sigma_t * alpha;
482 
483  /* Theoretically it should be better to use the exact alpha for the channel we're sampling at
484  * each bounce, but in practice there doesn't seem to be a noticeable difference in exchange
485  * for making the code significantly more complex and slower (if direction sampling depends on
486  * the sampled channel, we need to compute its PDF per-channel and consider it for MIS later on).
487  *
488  * Since the strength of the guided sampling increases as alpha gets lower, using a value that
489  * is too low results in fireflies while one that's too high just gives a bit more noise.
490  * Therefore, the code here uses the highest of the three albedos to be safe. */
491  float diffusion_length = diffusion_length_dwivedi(max3(alpha));
492  /* Precompute term for phase sampling. */
493  float phase_log = logf((diffusion_length + 1) / (diffusion_length - 1));
494 
495  /* Setup ray. */
496 #ifdef __SPLIT_KERNEL__
497  Ray ray_object = ss_isect->ray;
498  Ray *ray = &ray_object;
499 #else
500  Ray *ray = &ss_isect->ray;
501 #endif
502  ray->P = ray_offset(sd->P, -sd->Ng);
503  ray->D = D;
504  ray->t = FLT_MAX;
505  ray->time = sd->time;
506 
507  /* Modify state for RNGs, decorrelated from other paths. */
508  uint prev_rng_offset = state->rng_offset;
509  uint prev_rng_hash = state->rng_hash;
510  state->rng_hash = cmj_hash(state->rng_hash + state->rng_offset, 0xdeadbeef);
511 
512  /* Random walk until we hit the surface again. */
513  bool hit = false;
514  bool have_opposite_interface = false;
515  float opposite_distance = 0.0f;
516 
517  /* Todo: Disable for alpha>0.999 or so? */
518  const float guided_fraction = 0.75f;
519 
520  for (int bounce = 0; bounce < BSSRDF_MAX_BOUNCES; bounce++) {
521  /* Advance random number offset. */
522  state->rng_offset += PRNG_BOUNCE_NUM;
523 
524  /* Sample color channel, use MIS with balance heuristic. */
525  float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL);
526  float3 channel_pdf;
527  int channel = kernel_volume_sample_channel(alpha, throughput, rphase, &channel_pdf);
528  float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel);
530 
531  /* We need the result of the raycast to compute the full guided PDF, so just remember the
532  * relevant terms to avoid recomputing them later. */
533  float backward_fraction = 0.0f;
534  float forward_pdf_factor = 0.0f;
535  float forward_stretching = 1.0f;
536  float backward_pdf_factor = 0.0f;
537  float backward_stretching = 1.0f;
538 
539  /* For the initial ray, we already know the direction, so just do classic distance sampling. */
540  if (bounce > 0) {
541  /* Decide whether we should use guided or classic sampling. */
542  bool guided = (path_state_rng_1D(kg, state, PRNG_LIGHT_TERMINATE) < guided_fraction);
543 
544  /* Determine if we want to sample away from the incoming interface.
545  * This only happens if we found a nearby opposite interface, and the probability for it
546  * depends on how close we are to it already.
547  * This probability term comes from the recorded presentation of [3]. */
548  bool guide_backward = false;
549  if (have_opposite_interface) {
550  /* Compute distance of the random walk between the tangent plane at the starting point
551  * and the assumed opposite interface (the parallel plane that contains the point we
552  * found in our ray query for the opposite side). */
553  float x = clamp(dot(ray->P - sd->P, -sd->N), 0.0f, opposite_distance);
554  backward_fraction = 1.0f / (1.0f + expf((opposite_distance - 2 * x) / diffusion_length));
555  guide_backward = path_state_rng_1D(kg, state, PRNG_TERMINATE) < backward_fraction;
556  }
557 
558  /* Sample scattering direction. */
559  float scatter_u, scatter_v;
560  path_state_rng_2D(kg, state, PRNG_BSDF_U, &scatter_u, &scatter_v);
561  float cos_theta;
562  if (guided) {
563  cos_theta = sample_phase_dwivedi(diffusion_length, phase_log, scatter_u);
564  /* The backwards guiding distribution is just mirrored along sd->N, so swapping the
565  * sign here is enough to sample from that instead. */
566  if (guide_backward) {
567  cos_theta = -cos_theta;
568  }
569  }
570  else {
571  cos_theta = 2.0f * scatter_u - 1.0f;
572  }
573  ray->D = direction_from_cosine(sd->N, cos_theta, scatter_v);
574 
575  /* Compute PDF factor caused by phase sampling (as the ratio of guided / classic).
576  * Since phase sampling is channel-independent, we can get away with applying a factor
577  * to the guided PDF, which implicitly means pulling out the classic PDF term and letting
578  * it cancel with an equivalent term in the numerator of the full estimator.
579  * For the backward PDF, we again reuse the same probability distribution with a sign swap.
580  */
581  forward_pdf_factor = 2.0f * eval_phase_dwivedi(diffusion_length, phase_log, cos_theta);
582  backward_pdf_factor = 2.0f * eval_phase_dwivedi(diffusion_length, phase_log, -cos_theta);
583 
584  /* Prepare distance sampling.
585  * For the backwards case, this also needs the sign swapped since now directions against
586  * sd->N (and therefore with negative cos_theta) are preferred. */
587  forward_stretching = (1.0f - cos_theta / diffusion_length);
588  backward_stretching = (1.0f + cos_theta / diffusion_length);
589  if (guided) {
590  sample_sigma_t *= guide_backward ? backward_stretching : forward_stretching;
591  }
592  }
593 
594  /* Sample direction along ray. */
595  float t = -logf(1.0f - randt) / sample_sigma_t;
596 
597  /* On the first bounce, we use the raycast to check if the opposite side is nearby.
598  * If yes, we will later use backwards guided sampling in order to have a decent
599  * chance of connecting to it.
600  * Todo: Maybe use less than 10 times the mean free path? */
601  ray->t = (bounce == 0) ? max(t, 10.0f / (min3(sigma_t))) : t;
602  scene_intersect_local(kg, ray, ss_isect, sd->object, NULL, 1);
603  hit = (ss_isect->num_hits > 0);
604 
605  if (hit) {
606 #ifdef __KERNEL_OPTIX__
607  /* t is always in world space with OptiX. */
608  ray->t = ss_isect->hits[0].t;
609 #else
610  /* Compute world space distance to surface hit. */
611  float3 D = ray->D;
613  D = normalize(D) * ss_isect->hits[0].t;
614  object_dir_transform(kg, sd, &D);
615  ray->t = len(D);
616 #endif
617  }
618 
619  if (bounce == 0) {
620  /* Check if we hit the opposite side. */
621  if (hit) {
622  have_opposite_interface = true;
623  opposite_distance = dot(ray->P + ray->t * ray->D - sd->P, -sd->N);
624  }
625  /* Apart from the opposite side check, we were supposed to only trace up to distance t,
626  * so check if there would have been a hit in that case. */
627  hit = ray->t < t;
628  }
629 
630  /* Use the distance to the exit point for the throughput update if we found one. */
631  if (hit) {
632  t = ray->t;
633  }
634  else if (bounce == 0) {
635  /* Restore original position if nothing was hit after the first bounce,
636  * without the ray_offset() that was added to avoid self-intersection.
637  * Otherwise if that offset is relatively large compared to the scattering
638  * radius, we never go back up high enough to exit the surface. */
639  ray->P = sd->P;
640  }
641 
642  /* Advance to new scatter location. */
643  ray->P += t * ray->D;
644 
645  float3 transmittance;
646  float3 pdf = subsurface_random_walk_pdf(sigma_t, t, hit, &transmittance);
647  if (bounce > 0) {
648  /* Compute PDF just like we do for classic sampling, but with the stretched sigma_t. */
649  float3 guided_pdf = subsurface_random_walk_pdf(forward_stretching * sigma_t, t, hit, NULL);
650 
651  if (have_opposite_interface) {
652  /* First step of MIS: Depending on geometry we might have two methods for guided
653  * sampling, so perform MIS between them. */
654  float3 back_pdf = subsurface_random_walk_pdf(backward_stretching * sigma_t, t, hit, NULL);
655  guided_pdf = mix(
656  guided_pdf * forward_pdf_factor, back_pdf * backward_pdf_factor, backward_fraction);
657  }
658  else {
659  /* Just include phase sampling factor otherwise. */
660  guided_pdf *= forward_pdf_factor;
661  }
662 
663  /* Now we apply the MIS balance heuristic between the classic and guided sampling. */
664  pdf = mix(pdf, guided_pdf, guided_fraction);
665  }
666 
667  /* Finally, we're applying MIS again to combine the three color channels.
668  * Altogether, the MIS computation combines up to nine different estimators:
669  * {classic, guided, backward_guided} x {r, g, b} */
670  throughput *= (hit ? transmittance : sigma_s * transmittance) / dot(channel_pdf, pdf);
671 
672  if (hit) {
673  /* If we hit the surface, we are done. */
674  break;
675  }
676  else if (throughput.x < VOLUME_THROUGHPUT_EPSILON &&
677  throughput.y < VOLUME_THROUGHPUT_EPSILON &&
678  throughput.z < VOLUME_THROUGHPUT_EPSILON) {
679  /* Avoid unnecessary work and precision issue when throughput gets really small. */
680  break;
681  }
682  }
683 
684  kernel_assert(isfinite_safe(throughput.x) && isfinite_safe(throughput.y) &&
685  isfinite_safe(throughput.z));
686 
687  state->rng_offset = prev_rng_offset;
688  state->rng_hash = prev_rng_hash;
689 
690  /* Return number of hits in ss_isect. */
691  if (!hit) {
692  return 0;
693  }
694 
695  /* TODO: gain back performance lost from merging with disk BSSRDF. We
696  * only need to return on hit so this indirect ray push/pop overhead
697  * is not actually needed, but it does keep the code simpler. */
698  ss_isect->weight[0] = subsurface_scatter_walk_eval(sd, sc, throughput, all);
699 #ifdef __SPLIT_KERNEL__
700  ss_isect->ray = *ray;
701 #endif
702 
703  return 1;
704 }
705 
707  LocalIntersection *ss_isect,
708  ShaderData *sd,
710  const ShaderClosure *sc,
711  uint *lcg_state,
712  float bssrdf_u,
713  float bssrdf_v,
714  bool all)
715 {
716  if (CLOSURE_IS_DISK_BSSRDF(sc->type)) {
717  return subsurface_scatter_disk(kg, ss_isect, sd, sc, lcg_state, bssrdf_u, bssrdf_v, all);
718  }
719  else {
720  return subsurface_random_walk(kg, ss_isect, sd, state, sc, bssrdf_u, bssrdf_v, all);
721  }
722 }
723 
typedef float(TangentPoint)[2]
MINLINE float safe_sqrtf(float a)
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 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 GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_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 type
_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_inline ShaderClosure * bsdf_alloc(ShaderData *sd, int size, float3 weight)
Definition: alloc.h:58
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define A
ccl_device int bsdf_diffuse_setup(DiffuseBsdf *bsdf)
Definition: bsdf_diffuse.h:46
ccl_device int bsdf_principled_diffuse_setup(PrincipledDiffuseBsdf *bsdf)
ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r)
Definition: bssrdf.h:488
ccl_device_forceinline float3 bssrdf_eval(const ShaderClosure *sc, float r)
Definition: bssrdf.h:479
ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h)
Definition: bssrdf.h:425
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
static CCL_NAMESPACE_BEGIN const double alpha
static float verts[][3]
ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, int prim, float time, float3 verts[3])
ccl_device_inline void object_inverse_dir_transform(KernelGlobals *kg, const ShaderData *sd, float3 *D)
Definition: geom_object.h:190
ccl_device_inline void object_normal_transform(KernelGlobals *kg, const ShaderData *sd, float3 *N)
Definition: geom_object.h:166
ccl_device_inline void object_dir_transform(KernelGlobals *kg, const ShaderData *sd, float3 *D)
Definition: geom_object.h:178
ccl_device_inline float3 triangle_refine_local(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray)
ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
#define kernel_data
#define kernel_assert(cond)
#define ccl_addr_space
#define kernel_tex_fetch(tex, index)
#define ccl_device_forceinline
#define logf(x)
#define sinf(x)
#define cosf(x)
#define ccl_device
#define expf(x)
#define ccl_device_inline
#define powf(x, y)
#define ccl_device_noinline
#define CCL_NAMESPACE_END
#define fmaxf(x, y)
#define fabsf(x)
#define sqrtf(x)
#define make_float3(x, y, z)
ccl_device differential3 differential3_zero()
ccl_device_inline uint cmj_hash(uint i, uint p)
ccl_device_inline void sample_cos_hemisphere(const float3 N, float randu, float randv, float3 *omega_in, float *pdf)
ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, const ccl_addr_space PathState *state, int dimension, float *fx, float *fy)
ccl_device_inline float path_state_rng_1D(KernelGlobals *kg, const ccl_addr_space PathState *state, int dimension)
ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, ccl_global float *buffer, int path_flag)
#define kernel_split_params
ccl_device_inline int subsurface_scatter_multi_intersect(KernelGlobals *kg, LocalIntersection *ss_isect, ShaderData *sd, ccl_addr_space PathState *state, const ShaderClosure *sc, uint *lcg_state, float bssrdf_u, float bssrdf_v, bool all)
ccl_device_forceinline float diffusion_length_dwivedi(float alpha)
ccl_device_noinline void subsurface_scatter_multi_setup(KernelGlobals *kg, LocalIntersection *ss_isect, int hit, ShaderData *sd, ccl_addr_space PathState *state, ClosureType type, float roughness)
ccl_device_inline float3 subsurface_scatter_walk_eval(ShaderData *sd, const ShaderClosure *sc, float3 throughput, bool all)
ccl_device_forceinline float3 direction_from_cosine(float3 D, float cos_theta, float randv)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, float r, bool all)
ccl_device_forceinline float sample_phase_dwivedi(float v, float phase_log, float rand)
ccl_device void subsurface_random_walk_coefficients(const ShaderClosure *sc, float3 *sigma_t, float3 *alpha, float3 *weight)
ccl_device_noinline bool subsurface_random_walk(KernelGlobals *kg, LocalIntersection *ss_isect, ShaderData *sd, ccl_addr_space PathState *state, const ShaderClosure *sc, const float bssrdf_u, const float bssrdf_v, bool all)
ccl_device_forceinline float3 subsurface_random_walk_pdf(float3 sigma_t, float t, bool hit, float3 *transmittance)
ccl_device void subsurface_scatter_setup_diffuse_bsdf(KernelGlobals *kg, ShaderData *sd, ClosureType type, float roughness, float3 weight, float3 N)
ccl_device float3 subsurface_color_pow(float3 color, float exponent)
ccl_device void subsurface_random_walk_remap(const float A, const float d, float *sigma_t, float *alpha)
ccl_device_forceinline float eval_phase_dwivedi(float v, float phase_log, float cos_theta)
ccl_device_inline int subsurface_scatter_disk(KernelGlobals *kg, LocalIntersection *ss_isect, ShaderData *sd, const ShaderClosure *sc, uint *lcg_state, float disk_u, float disk_v, bool all)
ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, float3 *eval, float3 *N)
@ SD_CLOSURE_FLAGS
Definition: kernel_types.h:863
@ SD_HAS_BSSRDF_BUMP
Definition: kernel_types.h:879
@ PRIMITIVE_MOTION_TRIANGLE
Definition: kernel_types.h:687
@ PRIMITIVE_TRIANGLE
Definition: kernel_types.h:686
@ PRNG_BOUNCE_NUM
Definition: kernel_types.h:248
@ PRNG_LIGHT_TERMINATE
Definition: kernel_types.h:244
@ PRNG_BSDF_U
Definition: kernel_types.h:240
@ PRNG_SCATTER_DISTANCE
Definition: kernel_types.h:247
@ PRNG_TERMINATE
Definition: kernel_types.h:245
@ PRNG_PHASE_CHANNEL
Definition: kernel_types.h:246
#define OBJECT_NONE
Definition: kernel_types.h:59
ShaderData
#define BSSRDF_MAX_BOUNCES
Definition: kernel_types.h:51
ShaderClosure
Definition: kernel_types.h:831
#define BSSRDF_MAX_HITS
Definition: kernel_types.h:50
#define VOLUME_THROUGHPUT_EPSILON
Definition: kernel_volume.h:23
ccl_device float3 volume_color_transmittance(float3 sigma, float t)
ccl_device int kernel_volume_sample_channel(float3 albedo, float3 throughput, float rand, float3 *pdf)
ccl_device float kernel_volume_channel_get(float3 value, int channel)
static ulong state[N]
#define T
#define B
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
params N
#define min(a, b)
Definition: sort.c:51
closure color bssrdf(string method, normal N, vector radius, color albedo) BUILTIN
Definition: bssrdf.h:22
struct Intersection hits[LOCAL_MAX_HITS]
float3 weight[LOCAL_MAX_HITS]
float3 Ng[LOCAL_MAX_HITS]
float t
Definition: kernel_types.h:649
differential3 dD
Definition: kernel_types.h:660
float3 P
Definition: kernel_types.h:647
float time
Definition: kernel_types.h:650
differential3 dP
Definition: kernel_types.h:659
float3 D
Definition: kernel_types.h:648
float z
Definition: sky_float3.h:35
float y
Definition: sky_float3.h:35
float x
Definition: sky_float3.h:35
#define CLOSURE_IS_BSDF_BSSRDF(type)
Definition: svm_types.h:603
ClosureType
Definition: svm_types.h:527
@ CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID
Definition: svm_types.h:570
@ CLOSURE_BSSRDF_PRINCIPLED_ID
Definition: svm_types.h:576
@ CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID
Definition: svm_types.h:579
@ CLOSURE_BSDF_BSSRDF_ID
Definition: svm_types.h:569
#define CLOSURE_IS_BSSRDF(type)
Definition: svm_types.h:623
#define CLOSURE_IS_DISK_BSSRDF(type)
Definition: svm_types.h:625
float max
__forceinline bool all(const avxb &b)
Definition: util_avxb.h:214
#define mix(a, b, c)
Definition: util_hash.h:30
ccl_device_inline void make_orthonormals(const float3 N, float3 *a, float3 *b)
Definition: util_math.h:477
ccl_device_inline float sqr(float a)
Definition: util_math.h:651
#define M_2PI_F
Definition: util_math.h:69
ccl_device_inline float3 safe_divide_color(float3 a, float3 b)
Definition: util_math.h:514
ccl_device_inline bool isfinite_safe(float f)
Definition: util_math.h:270
ccl_device_inline int clamp(int a, int mn, int mx)
Definition: util_math.h:283
ccl_device_inline float2 normalize(const float2 &a)
ccl_device_inline float dot(const float2 &a, const float2 &b)
ccl_device_inline float3 one_float3()
ccl_device_inline float min3(float3 a)
ccl_device_inline float3 zero_float3()
ccl_device_inline float max3(float3 a)
uint len
BLI_INLINE float D(const float *data, const int res[3], int x, int y, int z)
Definition: voxel.c:29