Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/kernel_volume.h
| Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
| 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_offset, | ||||
| float *first_step_mul) | |||||
| { | { | ||||
| 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; | /* For the seeds the only thing that matters is that they are not used | ||||
| * anywhere else in the kernel. Using some random integer makes it easy | |||||
| * for them to be unique. */ | |||||
| *step_offset = path_state_rng_1D_hash(kg, state, 0x1e31d8a4); | |||||
| *first_step_mul = 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 19 Lines | |||||
| 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 */ | ||||
| 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_offset, step_offset_abs; | ||||
| 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_offset, &step_offset_abs); | ||||
| /* We don't need first_step_mul from kernel_volume_step_init() - just reuse the var */ | |||||
| step_offset_abs = step_size * step_offset; | |||||
| /* 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 = 1; 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 * step_size); | ||||
| /* use random position inside this segment to sample shader, adjust | |||||
| * for last step that is shorter than other steps. */ | |||||
| if (new_t == ray->t) { | if (new_t == ray->t) { | ||||
| step_offset *= (new_t - t) / step_size; | step_size = new_t - t; | ||||
| step_offset_abs = step_size * step_offset; | |||||
| } | } | ||||
| float3 new_P = ray->P + ray->D * (t + step_offset); | float3 new_P = ray->P + ray->D * (t + step_offset_abs); | ||||
| 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 * step_size); | |||||
| 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 184 Lines • ▼ Show 20 Lines | |||||
| 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 */ | ||||
| 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_offset, first_step_mul; | ||||
| 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_offset, &first_step_mul); | ||||
| /* 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 + first_step_mul) * 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_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 | |||||
| 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_offset, first_step_mul; | ||||
| 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_offset, &first_step_mul); | ||||
| # 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 11 Lines | |||||
| # 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_offset = 0.0f; | ||||
| first_step_mul = 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 + first_step_mul) * 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_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 | |||||
| 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_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 92 Lines • Show Last 20 Lines | |||||