30enum VolumeIntegrateEvent {
31 VOLUME_PATH_SCATTERED = 0,
32 VOLUME_PATH_ATTENUATED = 1,
33 VOLUME_PATH_MISSED = 2
36struct VolumeIntegrateResult {
41 ShaderVolumePhases direct_phases;
42# ifdef __PATH_GUIDING__
43 VolumeSampleMethod direct_sample_method;
47 bool indirect_scatter;
50 ShaderVolumePhases indirect_phases;
57# define VOLUME_THROUGHPUT_EPSILON 1e-6f
64struct VolumeShaderCoefficients {
70struct EquiangularCoefficients {
72 Interval<float> t_range;
88 *extinction = sd->closure_transparent_extinction;
100 volume_shader_eval<false>(kg,
state, sd, path_flag, volume_read_lambda_pass);
107 coeff->sigma_t = (sd->flag &
SD_EXTINCTION) ? sd->closure_transparent_extinction :
112 for (
int i = 0;
i < sd->num_closure;
i++) {
116 coeff->sigma_s += sc->weight;
143template<const
bool shadow>
146 const float object_step_size,
151 vstep->t.min = vstep->t.max = tmin;
153 if (object_step_size ==
FLT_MAX) {
155 vstep->size = tmax - tmin;
156 vstep->shade_offset = 0.0f;
157 vstep->offset = 1.0f;
158 vstep->max_steps = 1;
162 vstep->max_steps =
kernel_data.integrator.volume_max_steps;
163 const float t = tmax - tmin;
164 float step_size =
min(object_step_size, t);
166 if (t > vstep->max_steps * step_size) {
168 step_size = t / (float)vstep->max_steps;
171 vstep->size = step_size;
178 vstep->offset = 1.0f;
191 if (vstep.t.max == ray->tmax) {
197 vstep.t.min = vstep.t.max;
198 vstep.t.max =
min(ray->tmax, ray->tmin + (
step + vstep.offset) * vstep.size);
199 const float shade_t =
mix(vstep.t.min, vstep.t.max, vstep.shade_offset);
200 *shade_P = ray->P + ray->D * shade_t;
202 return step < vstep.max_steps;
217 const float object_step_size)
227 volume_step_init<true>(kg, &rng_state, object_step_size, ray->tmin, ray->tmax, &vstep);
231 for (
int step = 0; volume_integrate_advance(
step, ray, &sd->P, vstep);
step++) {
234 if (shadow_volume_shader_sample(kg,
state, sd, &sigma_t)) {
238 sum += (-sigma_t * vstep.t.length());
239 if ((
step & 0x07) == 0) {
240 tp = *throughput *
exp(
sum);
250 if (vstep.t.max == ray->tmax) {
252 tp = *throughput *
exp(
sum);
265# define VOLUME_SAMPLE_PDF_CUTOFF 1e-8f
272 const float delta =
dot((coeffs.P - ray->P), ray->D);
278 const float tmin = coeffs.t_range.min;
279 const float tmax = coeffs.t_range.max;
280 const float theta_a =
atan2f(tmin - delta,
D);
281 const float theta_b =
atan2f(tmax - delta,
D);
282 const float t_ =
D *
tanf((xi * theta_b) + (1 - xi) * theta_a);
287 *pdf =
D / ((theta_b - theta_a) * (
D *
D + t_ * t_));
289 return clamp(delta + t_, tmin, tmax);
294 const float sample_t)
296 const float delta =
dot((coeffs.P - ray->P), ray->D);
302 const float tmin = coeffs.t_range.min;
303 const float tmax = coeffs.t_range.max;
304 const float t_ = sample_t - delta;
306 const float theta_a =
atan2f(tmin - delta,
D);
307 const float theta_b =
atan2f(tmax - delta,
D);
312 const float pdf =
D / ((theta_b - theta_a) * (
D *
D + t_ * t_));
343 const int closure_flag,
351 Spectrum emission = coeff->emission;
372struct VolumeIntegrateState {
378 VolumeSampleMethod direct_sample_method;
381 float equiangular_pdf;
387 if (!
result.indirect_scatter) {
393 else if (!
result.direct_scatter) {
400 return (
result.direct_scatter &&
result.indirect_scatter);
404ccl_device bool volume_sample_indirect_scatter(
414 if (
result.indirect_scatter) {
422 if (1.0f - vstate.rscatter >= sample_transmittance) {
428 const float new_dt = -
logf(1.0f - vstate.rscatter) / sample_sigma_t;
429 const float new_t = t.min + new_dt;
434 const float distance_pdf =
dot(channel_pdf, coeff.sigma_t * new_transmittance);
436 if (vstate.distance_pdf * distance_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
438 result.indirect_scatter =
true;
439 result.indirect_t = new_t;
440 result.indirect_throughput *= coeff.sigma_s * new_transmittance / distance_pdf;
441 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
442 vstate.distance_pdf *= distance_pdf;
445 volume_shader_copy_phases(&
result.indirect_phases, sd);
452 const float distance_pdf =
dot(channel_pdf, transmittance);
453 result.indirect_throughput *= transmittance / distance_pdf;
454 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
455 vstate.distance_pdf *= distance_pdf;
459 vstate.rscatter = 1.0f - (1.0f - vstate.rscatter) / sample_transmittance;
469 const ccl_private EquiangularCoefficients &equiangular_coeffs,
484 albedo,
result.indirect_throughput, &vstate.rchannel, &channel_pdf);
487 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !
result.direct_scatter) {
488 if (t.contains(
result.direct_t) && vstate.equiangular_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
489 const float new_dt =
result.direct_t - t.min;
492 result.direct_scatter =
true;
493 result.direct_throughput *= coeff.sigma_s * new_transmittance / vstate.equiangular_pdf;
494 volume_shader_copy_phases(&
result.direct_phases, sd);
497 if (vstate.use_mis) {
498 const float distance_pdf = vstate.distance_pdf *
499 dot(channel_pdf, coeff.sigma_t * new_transmittance);
500 const float mis_weight = 2.0f *
power_heuristic(vstate.equiangular_pdf, distance_pdf);
501 result.direct_throughput *= mis_weight;
505 result.direct_throughput *= transmittance;
506 vstate.distance_pdf *=
dot(channel_pdf, transmittance);
511 if (volume_sample_indirect_scatter(
512 transmittance, channel_pdf, channel, sd, coeff, t, vstate,
result))
514 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
517 result.direct_scatter =
true;
520 volume_shader_copy_phases(&
result.direct_phases, sd);
523 if (vstate.use_mis) {
524 const float equiangular_pdf = volume_equiangular_pdf(
525 ray, equiangular_coeffs,
result.indirect_t);
526 const float mis_weight =
power_heuristic(vstate.distance_pdf, equiangular_pdf);
527 result.direct_throughput *= 2.0f * mis_weight;
535 const VolumeSampleMethod direct_sample_method,
542 vstate.direct_sample_method = direct_sample_method;
543 vstate.use_mis = (direct_sample_method == VOLUME_SAMPLE_MIS);
544 if (vstate.use_mis) {
545 if (vstate.rscatter < 0.5f) {
546 vstate.rscatter *= 2.0f;
547 vstate.direct_sample_method = VOLUME_SAMPLE_DISTANCE;
550 vstate.rscatter = (vstate.rscatter - 0.5f) * 2.0f;
551 vstate.direct_sample_method = VOLUME_SAMPLE_EQUIANGULAR;
554 vstate.equiangular_pdf = 0.0f;
555 vstate.distance_pdf = 1.0f;
569 const float object_step_size,
570 const VolumeSampleMethod direct_sample_method,
571 const ccl_private EquiangularCoefficients &equiangular_coeffs,
578 volume_step_init<false>(kg, rng_state, object_step_size, ray->tmin, ray->tmax, &vstep);
582 volume_integrate_state_init(kg, rng_state, direct_sample_method, vstate);
586 result.direct_throughput = throughput;
587 result.indirect_throughput = throughput;
590 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
591 result.direct_t = volume_equiangular_sample(
592 ray, equiangular_coeffs, vstate.rscatter, &vstate.equiangular_pdf);
594# ifdef __PATH_GUIDING__
595 result.direct_sample_method = vstate.direct_sample_method;
598# ifdef __DENOISING_FEATURES__
605 for (
int step = 0; volume_integrate_advance(
step, ray, &sd->P, vstep);
step++) {
608 if (volume_shader_sample(kg,
state, sd, &coeff)) {
609 const int closure_flag = sd->flag;
612 const float dt = vstep.t.length();
621 if (!
result.indirect_scatter) {
622 const Spectrum emission = volume_emission_integrate(
623 &coeff, closure_flag, transmittance, dt);
624 accum_emission +=
result.indirect_throughput * emission;
630# ifdef __DENOISING_FEATURES__
632 if (write_denoising_features && (closure_flag &
SD_SCATTER)) {
634 accum_albedo +=
result.indirect_throughput * albedo * (
one_spectrum() - transmittance);
639 volume_integrate_step_scattering(
640 sd, ray, equiangular_coeffs, coeff, transmittance, vstep.t, vstate,
result);
644 result.indirect_throughput *= transmittance;
645 result.direct_throughput *= transmittance;
648 if (volume_integrate_should_stop(
result)) {
655 if (!
is_zero(accum_emission)) {
662# ifdef __DENOISING_FEATURES__
664 if (write_denoising_features) {
665 film_write_denoising_features_volume(
696 ray->tmax - ray->tmin,
717 equiangular_coeffs->P = ls.P;
719 return volume_equiangular_valid_ray_segment(
720 kg, ray->P, ray->D, &equiangular_coeffs->t_range, &ls);
732# ifdef __PATH_GUIDING__
754 kg, rand_light, sd->time,
P,
N, object_receiver, shader_flags, bounce, path_flag, &ls))
779 const float phase_pdf = volume_shader_phase_eval(
780 kg,
state, sd, phases, ls.D, &phase_eval, ls.shader);
782 bsdf_eval_mul(&phase_eval, light_eval / ls.pdf * mis_weight);
829 state, path, render_pixel_index);
831 state, path, rng_offset);
833 state, path, rng_pixel);
840 state, path, diffuse_bounce);
842 state, path, glossy_bounce);
844 state, path, transmission_bounce);
850# ifdef __PATH_GUIDING__
853 state, guiding, path_segment);
857 integrator_state_copy_volume_stack_to_shadow(kg, shadow_state,
state);
876 float phase_pdf = 0.0f;
877 float unguided_phase_pdf = 0.0f;
880 float sampled_roughness = 1.0f;
883# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
885 label = volume_shader_phase_guided_sample(kg,
905 label = volume_shader_phase_sample(
906 kg, sd, phases, svc, rand_phase, &phase_eval, &phase_wo, &phase_pdf, &sampled_roughness);
912 unguided_phase_pdf = phase_pdf;
919# ifdef __LIGHT_TREE__
925# ifdef __RAY_DIFFERENTIALS__
936 kg,
state, sd, phase_weight, phase_pdf,
normalize(phase_wo), sampled_roughness);
940 const Spectrum throughput_phase = throughput * phase_weight;
952 const float3 previous_P = ray->P + ray->D * ray->tmin;
957# ifdef __LIGHT_LINKING__
990 EquiangularCoefficients equiangular_coeffs = {
zero_float3(), {ray->tmin, ray->tmax}};
992 const bool have_equiangular_sample =
993 need_light_sample && integrate_volume_equiangular_sample_light(
994 kg,
state, ray, &sd, &rng_state, &equiangular_coeffs, ls);
996 const VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
997 volume_stack_sample_method(kg,
state) :
998 VOLUME_SAMPLE_DISTANCE;
1002 const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass);
1004# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
1008 float3 unlit_throughput = initial_throughput;
1010 bool guiding_generated_new_segment =
false;
1011 float rand_phase_guiding = 0.5f;
1015 VolumeIntegrateResult
result = {};
1016 volume_integrate_heterogeneous(kg,
1023 direct_sample_method,
1034 state, path, continuation_probability);
1035 if (continuation_probability == 0.0f) {
1036 return VOLUME_PATH_MISSED;
1040 if (
result.direct_scatter) {
1041 const float3 direct_P = ray->P + result.direct_t * ray->D;
1043# ifdef __PATH_GUIDING__
1044 if (kernel_data.integrator.use_guiding) {
1045# if PATH_GUIDING_LEVEL >= 1
1046 if (result.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
1050 const float3 transmittance_weight = spectrum_to_rgb(
1051 safe_divide_color(result.indirect_throughput, initial_throughput));
1052 guiding_record_volume_transmission(kg, state, transmittance_weight);
1053 guiding_record_volume_segment(kg, state, direct_P, sd.wi);
1054 guiding_generated_new_segment = true;
1055 unlit_throughput = result.indirect_throughput / continuation_probability;
1056 rand_phase_guiding = path_state_rng_1D(kg, &rng_state, PRNG_VOLUME_PHASE_GUIDING_DISTANCE);
1064 float3 scatterEval = one_float3();
1065 if (state->guiding.path_segment) {
1066 const pgl_vec3f scatteringWeight = state->guiding.path_segment->scatteringWeight;
1067 scatterEval = make_float3(scatteringWeight.x, scatteringWeight.y, scatteringWeight.z);
1069 unlit_throughput /= scatterEval;
1070 unlit_throughput *= continuation_probability;
1071 rand_phase_guiding = path_state_rng_1D(
1072 kg, &rng_state, PRNG_VOLUME_PHASE_GUIDING_EQUIANGULAR);
1075# if PATH_GUIDING_LEVEL >= 4
1076 volume_shader_prepare_guiding(
1077 kg, state, &sd, rand_phase_guiding, direct_P, ray->D, &result.direct_phases);
1082 result.direct_throughput /= continuation_probability;
1083 integrate_volume_direct_light(kg,
1089# ifdef __PATH_GUIDING__
1092 result.direct_throughput,
1100 if (
result.indirect_scatter) {
1101# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
1102 if (!guiding_generated_new_segment) {
1103 const float3 transmittance_weight = spectrum_to_rgb(
1104 safe_divide_color(result.indirect_throughput, initial_throughput));
1105 guiding_record_volume_transmission(kg, state, transmittance_weight);
1108 result.indirect_throughput /= continuation_probability;
1112 if (
result.indirect_scatter) {
1113 sd.P = ray->P +
result.indirect_t * ray->D;
1115# if defined(__PATH_GUIDING__)
1116# if PATH_GUIDING_LEVEL >= 1
1117 if (!guiding_generated_new_segment) {
1121# if PATH_GUIDING_LEVEL >= 4
1124 if (
result.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
1126 volume_shader_prepare_guiding(
1127 kg,
state, &sd, rand_phase_guiding, sd.P, ray->D, &
result.indirect_phases);
1132 if (integrate_volume_phase_scatter(kg,
state, &sd, ray, &rng_state, &
result.indirect_phases)) {
1133 return VOLUME_PATH_SCATTERED;
1135 return VOLUME_PATH_MISSED;
1137# if defined(__PATH_GUIDING__)
1139 state->guiding.use_volume_guiding =
false;
1141 return VOLUME_PATH_ATTENUATED;
1165 volume_stack_clean(kg,
state);
1169 if (event == VOLUME_PATH_MISSED) {
1175 if (event == VOLUME_PATH_ATTENUATED) {
1182# ifdef __SHADOW_LINKING__
1183 if (shadow_linking_schedule_intersection_kernel<DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME>(kg,
MINLINE float safe_sqrtf(float a)
ccl_device_inline bool area_light_valid_ray_segment(const ccl_global KernelAreaLight *light, float3 P, float3 D, ccl_private Interval< float > *t_range)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
static T sum(const btAlignedObjectArray< T > &items)
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_inline bool light_sample_terminate(KernelGlobals kg, ccl_private BsdfEval *ccl_restrict eval, const float rand_terminate)
CCL_NAMESPACE_BEGIN ccl_device_noinline_cpu Spectrum light_sample_shader_eval(KernelGlobals kg, IntegratorState state, ccl_private ShaderData *ccl_restrict emission_sd, ccl_private LightSample *ccl_restrict ls, const float time)
ccl_device_inline float light_sample_mis_weight_nee(KernelGlobals kg, const float nee_pdf, const float forward_pdf)
ccl_device_inline void light_sample_to_volume_shadow_ray(KernelGlobals kg, const ccl_private ShaderData *ccl_restrict sd, const ccl_private LightSample *ccl_restrict ls, const float3 P, ccl_private Ray *ray)
ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg, const float3 rand, const float time, const float3 P, const float3 D, const float t, const int object_receiver, const int bounce, const uint32_t path_flag, ccl_private LightSample *ls)
#define kernel_assert(cond)
#define CLOSURE_IS_VOLUME(type)
#define ccl_device_forceinline
#define ccl_optional_struct_init
#define kernel_data_fetch(name, index)
#define AS_SHADER_DATA(shader_data_tiny_storage)
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define KERNEL_FEATURE_LIGHT_PASSES
#define FOREACH_SPECTRUM_CHANNEL(counter)
#define GET_SPECTRUM_CHANNEL(v, i)
#define KERNEL_FEATURE_LIGHT_LINKING
#define CCL_NAMESPACE_END
ccl_device_forceinline float differential_make_compact(const float dD)
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, 3 > float3
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
constexpr T clamp(T, U, U) RET
ccl_device_forceinline void integrator_intersect_next_kernel_after_volume(KernelGlobals kg, IntegratorState state, const ccl_private Intersection *ccl_restrict isect, ccl_global float *ccl_restrict render_buffer)
#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_gpu_kernel_postfix ccl_global KernelWorkTile const int ccl_global float * render_buffer
ccl_device_inline int object_lightgroup(KernelGlobals kg, const int object)
ccl_device_forceinline void guiding_record_volume_segment(KernelGlobals kg, IntegratorState state, const float3 P, const float3 I)
ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg, IntegratorState state, const ccl_private ShaderData *sd, const Spectrum weight, const float pdf, const float3 wo, const float roughness)
ccl_device_forceinline void guiding_record_volume_emission(KernelGlobals kg, IntegratorState state, const Spectrum Le)
ccl_device_inline bool light_link_object_match(KernelGlobals kg, const int object_receiver, const int object_emitter)
ccl_device_inline bool light_sample(KernelGlobals kg, const int lamp, const float2 rand, const float3 P, const float3 N, const int shader_flags, const uint32_t path_flag, ccl_private LightSample *ls)
ccl_device_inline int light_link_receiver_nee(KernelGlobals kg, const ccl_private ShaderData *sd)
ccl_device_inline int light_link_receiver_forward(KernelGlobals kg, IntegratorState state)
@ SD_BSDF_HAS_TRANSMISSION
ShaderData ShaderDataTinyStorage
@ PRNG_VOLUME_SHADE_OFFSET
@ PRNG_VOLUME_PHASE_GUIDING_DISTANCE
@ PRNG_VOLUME_COLOR_CHANNEL
@ PRNG_VOLUME_SCATTER_DISTANCE
@ PATH_RAY_TERMINATE_IN_NEXT_VOLUME
@ PATH_RAY_DENOISING_FEATURES
@ DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST
ccl_device_inline bool triangle_light_valid_ray_segment(KernelGlobals kg, const float3 P, const float3 D, ccl_private Interval< float > *t_range, const ccl_private LightSample *ls)
ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval)
ccl_device_inline void film_write_volume_emission(KernelGlobals kg, ConstIntegratorState state, const Spectrum L, ccl_global float *ccl_restrict render_buffer, const int lightgroup=LIGHTGROUP_NONE)
ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, const float value)
ccl_device_inline Spectrum bsdf_eval_sum(const ccl_private BsdfEval *eval)
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline bool is_zero(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
ccl_device float power_heuristic(const float a, const float b)
ccl_device_inline float path_state_rng_1D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
ccl_device_inline void shadow_path_state_rng_load(ConstIntegratorShadowState state, ccl_private RNGState *rng_state)
ccl_device_inline float path_state_rng_light_termination(KernelGlobals kg, const ccl_private RNGState *state)
ccl_device_inline void path_state_rng_load(ConstIntegratorState state, ccl_private RNGState *rng_state)
ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state, const int label, const int shader_flag)
ccl_device_inline float2 path_state_rng_2D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
ccl_device_inline float3 path_state_rng_3D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
#define PROFILING_INIT(kg, event)
@ PROFILING_SHADE_VOLUME_INTEGRATE
@ PROFILING_SHADE_VOLUME_SETUP
@ PROFILING_SHADE_VOLUME_DIRECT_LIGHT
@ PROFILING_SHADE_VOLUME_INDIRECT_LIGHT
CCL_NAMESPACE_BEGIN ccl_device void integrator_shade_volume(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
ccl_device_inline bool spot_light_valid_ray_segment(KernelGlobals kg, const ccl_global KernelLight *klight, const float3 P, const float3 D, ccl_private Interval< float > *t_range)
IntegratorShadowStateCPU * IntegratorShadowState
#define INTEGRATOR_STATE_WRITE(state, nested_struct, member)
#define INTEGRATOR_STATE(state, nested_struct, member)
#define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
IntegratorStateCPU * IntegratorState
ccl_device_forceinline void integrator_path_terminate(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel)
ccl_device_forceinline void integrator_path_next(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
ccl_device_forceinline IntegratorShadowState integrator_shadow_path_init(KernelGlobals kg, IntegratorState state, const DeviceKernel next_kernel, const bool is_ao)
ccl_device_forceinline void integrator_state_write_shadow_ray_self(KernelGlobals kg, IntegratorShadowState state, const ccl_private Ray *ccl_restrict ray)
ccl_device_forceinline void integrator_state_read_ray(ConstIntegratorState state, ccl_private Ray *ccl_restrict ray)
ccl_device_forceinline void integrator_state_write_shadow_ray(IntegratorShadowState state, const ccl_private Ray *ccl_restrict ray)
ccl_device_forceinline void integrator_state_read_isect(ConstIntegratorState state, ccl_private Intersection *ccl_restrict isect)
packed_float3 PackedSpectrum