29ccl_device void subsurface_random_walk_remap(
const float albedo,
36 const float g2 = g * g;
37 const float g3 = g2 * g;
38 const float g4 = g3 * g;
39 const float g5 = g4 * g;
40 const float g6 = g5 * g;
41 const float g7 = g6 * g;
43 const float A = 1.8260523782f + -1.28451056436f * g + -1.79904629312f * g2 +
44 9.19393289202f * g3 + -22.8215585862f * g4 + 32.0234874259f * g5 +
45 -23.6264803333f * g6 + 7.21067002658f * g7;
46 const float B = 4.98511194385f +
48 expf(31.1491581433f * g + -201.847017512f * g2 + 841.576016723f * g3 +
49 -2018.09288505f * g4 + 2731.71560286f * g5 + -1935.41424244f * g6 +
51 const float C = 1.09686102424f + -0.394704063468f * g + 1.05258115941f * g2 +
52 -8.83963712726f * g3 + 28.8643230661f * g4 + -46.8802913581f * g5 +
53 38.5402837518f * g6 + -12.7181042538f * g7;
54 const float D = 0.496310210422f + 0.360146581622f * g + -2.15139309747f * g2 +
55 17.8896899217f * g3 + -55.2984010333f * g4 + 82.065982243f * g5 +
56 -58.5106008578f * g6 + 15.8478295021f * g7;
57 const float E = 4.23190299701f +
59 expf(76.7316253952f * g + -594.356773233f * g2 + 2448.8834203f * g3 +
60 -5576.68528998f * g4 + 7116.60171912f * g5 + -4763.54467887f * g6 +
62 const float F = 2.40602999408f + -2.51814844609f * g + 9.18494908356f * g2 +
63 -79.2191708682f * g3 + 259.082868209f * g4 + -403.613804597f * g5 +
64 302.85712436f * g6 + -87.4370473567f * g7;
70 *alpha =
clamp(*alpha, 0.0f, 0.999999f);
72 const float sigma_t_prime = 1.0f /
fmaxf(d, 1e-16f);
73 *sigma_t = sigma_t_prime / (1.0f - g);
78 const float anisotropy,
99 const float min_alpha = 0.2f;
124 const float phase_log,
132 const float phase_log,
138 return v - (
v + 1.0f) *
expf(-rand * phase_log);
144 return 1.0f /
sqrtf(1.0f -
powf(alpha, 2.44294f - 0.0215813f * alpha + 0.578637f / alpha));
169 return hit ?
T : sigma_t *
T;
174# define SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL 9
198 ray.self.object = object;
199 ray.self.prim = prim;
212 subsurface_random_walk_coefficients(albedo, radius, anisotropy, &sigma_t, &alpha, &throughput);
213 const Spectrum sigma_s = sigma_t * alpha;
223 const float diffusion_length = diffusion_length_dwivedi(
reduce_max(alpha));
225 if (diffusion_length == 1.0f) {
233 const float phase_log =
logf((diffusion_length + 1.0f) / (diffusion_length - 1.0f));
240 bool have_opposite_interface =
false;
241 float opposite_distance = 0.0f;
245 const float guided_fraction = 1.0f -
fmaxf(0.5f,
powf(
fabsf(anisotropy), 0.125f));
247# ifdef SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL
248 const Spectrum sigma_s_star = sigma_s * (1.0f - anisotropy);
249 const Spectrum sigma_t_star = sigma_t - sigma_s + sigma_s_star;
250 const Spectrum sigma_t_org = sigma_t;
251 const Spectrum sigma_s_org = sigma_s;
252 const float anisotropy_org = anisotropy;
253 const float guided_fraction_org = guided_fraction;
260# ifdef SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL
263 float guided_fraction;
266 if (bounce <= SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL) {
267 anisotropy = anisotropy_org;
268 guided_fraction = guided_fraction_org;
269 sigma_t = sigma_t_org;
270 sigma_s = sigma_s_org;
274 guided_fraction = 0.75f;
275 sigma_t = sigma_t_star;
276 sigma_s = sigma_s_star;
289 float backward_fraction = 0.0f;
290 float forward_pdf_factor = 0.0f;
291 float forward_stretching = 1.0f;
292 float backward_pdf_factor = 0.0f;
293 float backward_stretching = 1.0f;
305 bool guide_backward =
false;
306 if (have_opposite_interface) {
310 const float x =
clamp(
dot(ray.P -
P, -
N), 0.0f, opposite_distance);
311 backward_fraction = 1.0f /
312 (1.0f +
expf((opposite_distance - 2.0f *
x) / diffusion_length));
322 cos_theta = sample_phase_dwivedi(diffusion_length, phase_log, rand_scatter.
x);
325 if (guide_backward) {
334 ray.D, anisotropy, rand_scatter, &hg_pdf);
345 forward_pdf_factor =
M_1_2PI_F * eval_phase_dwivedi(diffusion_length, phase_log,
cos_theta) /
348 eval_phase_dwivedi(diffusion_length, phase_log, -
cos_theta) / hg_pdf;
353 forward_stretching = (1.0f -
cos_theta / diffusion_length);
354 backward_stretching = (1.0f +
cos_theta / diffusion_length);
356 sample_sigma_t *= guide_backward ? backward_stretching : forward_stretching;
361 float t = -
logf(1.0f - randt) / sample_sigma_t;
376 scene_intersect_local<true>(kg, &ray, &ss_isect,
object,
nullptr, 1);
377 hit = (ss_isect.num_hits > 0);
380 ray.tmax = ss_isect.hits[0].t;
386 have_opposite_interface =
true;
387 opposite_distance =
dot(ray.P + ray.tmax * ray.D -
P, -
N);
403 Spectrum pdf = subsurface_random_walk_pdf(sigma_t, t, hit, &transmittance);
406 Spectrum guided_pdf = subsurface_random_walk_pdf(
407 forward_stretching * sigma_t, t, hit,
nullptr);
409 if (have_opposite_interface) {
412 const Spectrum back_pdf = subsurface_random_walk_pdf(
413 backward_stretching * sigma_t, t, hit,
nullptr);
415 guided_pdf * forward_pdf_factor, back_pdf * backward_pdf_factor, backward_fraction);
419 guided_pdf *= forward_pdf_factor;
423 pdf =
mix(pdf, guided_pdf, guided_fraction);
429 throughput *= (hit ? transmittance : sigma_s * transmittance) /
dot(channel_pdf, pdf);
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline float cos_theta(const float3 w)
ccl_device_inline Spectrum safe_divide_color(Spectrum a, Spectrum b, const float fallback=0.0f)
reduce_max(value.rgb)") DEFINE_VALUE("REDUCE(lhs
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
ccl_device float3 spherical_cos_to_direction(const float cos_theta, const float phi)
ccl_device_inline T to_global(const float2 p, const T X, const T Y)
#define kernel_assert(cond)
#define ccl_device_forceinline
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define BSSRDF_MAX_BOUNCES
#define FOREACH_SPECTRUM_CHANNEL(counter)
#define GET_SPECTRUM_CHANNEL(v, i)
#define CCL_NAMESPACE_END
ccl_device_forceinline float differential_zero_compact()
constexpr T clamp(T, U, U) RET
#define VOLUME_THROUGHPUT_EPSILON
ccl_device Spectrum volume_color_transmittance(Spectrum sigma, const float t)
ccl_device int volume_sample_channel(Spectrum albedo, Spectrum throughput, ccl_private float *rand, ccl_private Spectrum *pdf)
ccl_device float volume_channel_get(Spectrum value, const int channel)
ccl_device_forceinline void guiding_record_bssrdf_bounce(KernelGlobals kg, IntegratorState state, const float pdf, const float3 N, const float3 wo, const Spectrum weight, const Spectrum albedo)
@ PRNG_SUBSURFACE_COLOR_CHANNEL
@ PRNG_SUBSURFACE_GUIDE_STRATEGY
@ PRNG_SUBSURFACE_SCATTER_DISTANCE
@ PRNG_SUBSURFACE_GUIDE_DIRECTION
ccl_device_inline bool isfinite_safe(const float f)
ccl_device_inline float reduce_min(const float2 a)
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
ccl_device_inline float path_state_rng_1D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
ccl_device_inline void path_state_rng_scramble(ccl_private RNGState *rng_state, const int seed)
ccl_device_inline float2 path_state_rng_2D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
#define INTEGRATOR_STATE_WRITE(state, nested_struct, member)
#define INTEGRATOR_STATE(state, nested_struct, member)
IntegratorStateCPU * IntegratorState
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
ccl_device float3 phase_henyey_greenstein_sample(const float3 D, const float g, const float2 rand, ccl_private float *pdf)
ccl_device float phase_henyey_greenstein(const float cos_theta, const float g)