Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/kernel_volume.h
| Show First 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stack) | ||||
| return method; | return method; | ||||
| } | } | ||||
| ccl_device_inline void kernel_volume_step_init(KernelGlobals *kg, | ccl_device_inline void kernel_volume_step_init(KernelGlobals *kg, | ||||
| ccl_addr_space PathState *state, | ccl_addr_space PathState *state, | ||||
| const float object_step_size, | const float object_step_size, | ||||
| float t, | float t, | ||||
| float *step_size, | float *step_size, | ||||
| float *step_offset) | float *step_shade_offset, | ||||
| float *steps_offset) | |||||
| { | { | ||||
| const int max_steps = kernel_data.integrator.volume_max_steps; | const int max_steps = kernel_data.integrator.volume_max_steps; | ||||
| float step = min(object_step_size, t); | float step = min(object_step_size, t); | ||||
| /* compute exact steps in advance for malloc */ | /* compute exact steps in advance for malloc */ | ||||
| if (t > max_steps * step) { | if (t > max_steps * step) { | ||||
| step = t / (float)max_steps; | step = t / (float)max_steps; | ||||
| } | } | ||||
| *step_size = step; | *step_size = step; | ||||
| *step_offset = path_state_rng_1D_hash(kg, state, 0x1e31d8a4) * step; | |||||
| /* Perform shading at this offset within a step, to integrate over | |||||
| * over the entire step segment. */ | |||||
| *step_shade_offset = path_state_rng_1D_hash(kg, state, 0x1e31d8a4); | |||||
| /* Shift starting point of all segment by this random amount to avoid | |||||
| * banding artifacts from the volume bounding shape. */ | |||||
| *steps_offset = path_state_rng_1D_hash(kg, state, 0x3d22c7b3); | |||||
| } | } | ||||
| /* Volume Shadows | /* Volume Shadows | ||||
| * | * | ||||
| * These functions are used to attenuate shadow rays to lights. Both absorption | * These functions are used to attenuate shadow rays to lights. Both absorption | ||||
| * and scattering will block light, represented by the extinction coefficient. */ | * and scattering will block light, represented by the extinction coefficient. */ | ||||
| /* homogeneous volume: assume shader evaluation at the starts gives | /* homogeneous volume: assume shader evaluation at the starts gives | ||||
| Show All 17 Lines | ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, | ||||
| Ray *ray, | Ray *ray, | ||||
| ShaderData *sd, | ShaderData *sd, | ||||
| float3 *throughput, | float3 *throughput, | ||||
| const float object_step_size) | const float object_step_size) | ||||
| { | { | ||||
| float3 tp = *throughput; | float3 tp = *throughput; | ||||
| const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ | const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ | ||||
| /* prepare for stepping */ | /* Prepare for stepping. | ||||
| * For shadows we do not offset all segments, since the starting point is | |||||
| * already a random distance inside the volume. It also appears to create | |||||
| * banding artifacts for unknown reasons. */ | |||||
| int max_steps = kernel_data.integrator.volume_max_steps; | int max_steps = kernel_data.integrator.volume_max_steps; | ||||
| float step_offset, step_size; | float step_size, step_shade_offset, unused; | ||||
| kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset); | kernel_volume_step_init( | ||||
| kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &unused); | |||||
| const float steps_offset = 1.0f; | |||||
| /* compute extinction at the start */ | /* compute extinction at the start */ | ||||
| float t = 0.0f; | float t = 0.0f; | ||||
| float3 sum = zero_float3(); | float3 sum = zero_float3(); | ||||
| for (int i = 0; i < max_steps; i++) { | for (int i = 0; i < max_steps; i++) { | ||||
| /* advance to new position */ | /* advance to new position */ | ||||
| float new_t = min(ray->t, (i + 1) * step_size); | float new_t = min(ray->t, (i + steps_offset) * step_size); | ||||
| float dt = new_t - t; | |||||
| /* use random position inside this segment to sample shader, adjust | |||||
| * for last step that is shorter than other steps. */ | |||||
| if (new_t == ray->t) { | |||||
| step_offset *= (new_t - t) / step_size; | |||||
| } | |||||
| float3 new_P = ray->P + ray->D * (t + step_offset); | float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset); | ||||
| float3 sigma_t = zero_float3(); | float3 sigma_t = zero_float3(); | ||||
| /* compute attenuation over segment */ | /* compute attenuation over segment */ | ||||
| if (volume_shader_extinction_sample(kg, sd, state, new_P, &sigma_t)) { | if (volume_shader_extinction_sample(kg, sd, state, new_P, &sigma_t)) { | ||||
| /* Compute expf() only for every Nth step, to save some calculations | /* Compute expf() only for every Nth step, to save some calculations | ||||
| * because exp(a)*exp(b) = exp(a+b), also do a quick tp_eps check then. */ | * because exp(a)*exp(b) = exp(a+b), also do a quick tp_eps check then. */ | ||||
| sum += (-sigma_t * dt); | |||||
| sum += (-sigma_t * (new_t - t)); | |||||
| if ((i & 0x07) == 0) { /* ToDo: Other interval? */ | if ((i & 0x07) == 0) { /* ToDo: Other interval? */ | ||||
| tp = *throughput * exp3(sum); | tp = *throughput * exp3(sum); | ||||
| /* stop if nearly all light is blocked */ | /* stop if nearly all light is blocked */ | ||||
| if (tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps) | if (tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps) | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg, | ||||
| ShaderData *sd, | ShaderData *sd, | ||||
| PathRadiance *L, | PathRadiance *L, | ||||
| ccl_addr_space float3 *throughput, | ccl_addr_space float3 *throughput, | ||||
| const float object_step_size) | const float object_step_size) | ||||
| { | { | ||||
| float3 tp = *throughput; | float3 tp = *throughput; | ||||
| const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ | const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ | ||||
| /* prepare for stepping */ | /* Prepare for stepping. | ||||
| * Using a different step offset for the first step avoids banding artifacts. */ | |||||
| int max_steps = kernel_data.integrator.volume_max_steps; | int max_steps = kernel_data.integrator.volume_max_steps; | ||||
| float step_offset, step_size; | float step_size, step_shade_offset, steps_offset; | ||||
| kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset); | kernel_volume_step_init( | ||||
| kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &steps_offset); | |||||
| /* compute coefficients at the start */ | /* compute coefficients at the start */ | ||||
| float t = 0.0f; | float t = 0.0f; | ||||
| float3 accum_transmittance = one_float3(); | float3 accum_transmittance = one_float3(); | ||||
| /* pick random color channel, we use the Veach one-sample | /* pick random color channel, we use the Veach one-sample | ||||
| * model with balance heuristic for the channels */ | * model with balance heuristic for the channels */ | ||||
| float xi = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); | float xi = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); | ||||
| float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); | float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); | ||||
| bool has_scatter = false; | bool has_scatter = false; | ||||
| for (int i = 0; i < max_steps; i++) { | for (int i = 0; i < max_steps; i++) { | ||||
| /* advance to new position */ | /* advance to new position */ | ||||
| float new_t = min(ray->t, (i + 1) * step_size); | float new_t = min(ray->t, (i + steps_offset) * step_size); | ||||
| float dt = new_t - t; | float dt = new_t - t; | ||||
| /* use random position inside this segment to sample shader, | float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset); | ||||
| * for last shorter step we remap it to fit within the segment. */ | |||||
| if (new_t == ray->t) { | |||||
| step_offset *= (new_t - t) / step_size; | |||||
| } | |||||
| float3 new_P = ray->P + ray->D * (t + step_offset); | |||||
| VolumeShaderCoefficients coeff ccl_optional_struct_init; | VolumeShaderCoefficients coeff ccl_optional_struct_init; | ||||
| /* compute segment */ | /* compute segment */ | ||||
| if (volume_shader_sample(kg, sd, state, new_P, &coeff)) { | if (volume_shader_sample(kg, sd, state, new_P, &coeff)) { | ||||
| int closure_flag = sd->flag; | int closure_flag = sd->flag; | ||||
| float3 new_tp; | float3 new_tp; | ||||
| float3 transmittance; | float3 transmittance; | ||||
| bool scatter = false; | bool scatter = false; | ||||
| ▲ Show 20 Lines • Show All 161 Lines • ▼ Show 20 Lines | ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, | ||||
| ShaderData *sd, | ShaderData *sd, | ||||
| VolumeSegment *segment, | VolumeSegment *segment, | ||||
| const float object_step_size) | const float object_step_size) | ||||
| { | { | ||||
| const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ | const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ | ||||
| /* prepare for volume stepping */ | /* prepare for volume stepping */ | ||||
| int max_steps; | int max_steps; | ||||
| float step_size, step_offset; | float step_size, step_shade_offset, steps_offset; | ||||
| if (object_step_size != FLT_MAX) { | if (object_step_size != FLT_MAX) { | ||||
| max_steps = kernel_data.integrator.volume_max_steps; | max_steps = kernel_data.integrator.volume_max_steps; | ||||
| kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset); | kernel_volume_step_init( | ||||
| kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &steps_offset); | |||||
| # ifdef __KERNEL_CPU__ | # ifdef __KERNEL_CPU__ | ||||
| /* NOTE: For the branched path tracing it's possible to have direct | /* NOTE: For the branched path tracing it's possible to have direct | ||||
| * and indirect light integration both having volume segments allocated. | * and indirect light integration both having volume segments allocated. | ||||
| * We detect this using index in the pre-allocated memory. Currently we | * We detect this using index in the pre-allocated memory. Currently we | ||||
| * only support two segments allocated at a time, if more needed some | * only support two segments allocated at a time, if more needed some | ||||
| * modifications to the KernelGlobals will be needed. | * modifications to the KernelGlobals will be needed. | ||||
| * | * | ||||
| Show All 10 Lines | # ifdef __KERNEL_CPU__ | ||||
| ++kg->decoupled_volume_steps_index; | ++kg->decoupled_volume_steps_index; | ||||
| # else | # else | ||||
| segment->steps = (VolumeStep *)malloc(sizeof(VolumeStep) * max_steps); | segment->steps = (VolumeStep *)malloc(sizeof(VolumeStep) * max_steps); | ||||
| # endif | # endif | ||||
| } | } | ||||
| else { | else { | ||||
| max_steps = 1; | max_steps = 1; | ||||
| step_size = ray->t; | step_size = ray->t; | ||||
| step_offset = 0.0f; | step_shade_offset = 0.0f; | ||||
| steps_offset = 1.0f; | |||||
| segment->steps = &segment->stack_step; | segment->steps = &segment->stack_step; | ||||
| } | } | ||||
| /* init accumulation variables */ | /* init accumulation variables */ | ||||
| float3 accum_emission = zero_float3(); | float3 accum_emission = zero_float3(); | ||||
| float3 accum_transmittance = one_float3(); | float3 accum_transmittance = one_float3(); | ||||
| float3 accum_albedo = zero_float3(); | float3 accum_albedo = zero_float3(); | ||||
| float3 cdf_distance = zero_float3(); | float3 cdf_distance = zero_float3(); | ||||
| float t = 0.0f; | float t = 0.0f; | ||||
| segment->numsteps = 0; | segment->numsteps = 0; | ||||
| segment->closure_flag = 0; | segment->closure_flag = 0; | ||||
| bool is_last_step_empty = false; | bool is_last_step_empty = false; | ||||
| VolumeStep *step = segment->steps; | VolumeStep *step = segment->steps; | ||||
| for (int i = 0; i < max_steps; i++, step++) { | for (int i = 0; i < max_steps; i++, step++) { | ||||
| /* advance to new position */ | /* advance to new position */ | ||||
| float new_t = min(ray->t, (i + 1) * step_size); | float new_t = min(ray->t, (i + steps_offset) * step_size); | ||||
| float dt = new_t - t; | float dt = new_t - t; | ||||
| /* use random position inside this segment to sample shader, | float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset); | ||||
| * for last shorter step we remap it to fit within the segment. */ | |||||
| if (new_t == ray->t) { | |||||
| step_offset *= (new_t - t) / step_size; | |||||
| } | |||||
| float3 new_P = ray->P + ray->D * (t + step_offset); | |||||
| VolumeShaderCoefficients coeff ccl_optional_struct_init; | VolumeShaderCoefficients coeff ccl_optional_struct_init; | ||||
| /* compute segment */ | /* compute segment */ | ||||
| if (volume_shader_sample(kg, sd, state, new_P, &coeff)) { | if (volume_shader_sample(kg, sd, state, new_P, &coeff)) { | ||||
| int closure_flag = sd->flag; | int closure_flag = sd->flag; | ||||
| float3 sigma_t = coeff.sigma_t; | float3 sigma_t = coeff.sigma_t; | ||||
| /* compute average albedo for channel sampling */ | /* compute average albedo for channel sampling */ | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | else { | ||||
| segment->numsteps++; | segment->numsteps++; | ||||
| is_last_step_empty = true; | is_last_step_empty = true; | ||||
| } | } | ||||
| } | } | ||||
| step->accum_transmittance = accum_transmittance; | step->accum_transmittance = accum_transmittance; | ||||
| step->cdf_distance = cdf_distance; | step->cdf_distance = cdf_distance; | ||||
| step->t = new_t; | step->t = new_t; | ||||
| step->shade_t = t + step_offset; | step->shade_t = t + dt * step_shade_offset; | ||||
| /* stop if at the end of the volume */ | /* stop if at the end of the volume */ | ||||
| t = new_t; | t = new_t; | ||||
| if (t == ray->t) | if (t == ray->t) | ||||
| break; | break; | ||||
| /* stop if nearly all light blocked */ | /* stop if nearly all light blocked */ | ||||
| if (accum_transmittance.x < tp_eps && accum_transmittance.y < tp_eps && | if (accum_transmittance.x < tp_eps && accum_transmittance.y < tp_eps && | ||||
| ▲ Show 20 Lines • Show All 536 Lines • Show Last 20 Lines | |||||