Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2018-03-26 13:13:36 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2018-03-27 02:08:30 +0300
commita7aee250b82161592bb673adf59508e759a867f4 (patch)
treea82f2ce17d06cfdfd5634b7a3da7cd22b219f485 /intern/cycles/kernel/kernel_volume.h
parent3c45fdd171fa6ebd65f19f9fac9b204865e13136 (diff)
Fix T54420: too much volume render noise with multiple volume objects.
Random numbers for step offset were correlated, now use stratified samples which reduces noise as well for some types of volumes, mainly procedural ones where the step size is bigger than the volume features.
Diffstat (limited to 'intern/cycles/kernel/kernel_volume.h')
-rw-r--r--intern/cycles/kernel/kernel_volume.h81
1 files changed, 48 insertions, 33 deletions
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 88360e5f1ae..86378289b02 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -156,6 +156,24 @@ ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stac
return method;
}
+ccl_device_inline void kernel_volume_step_init(KernelGlobals *kg,
+ ccl_addr_space PathState *state,
+ float t,
+ float *step_size,
+ float *step_offset)
+{
+ const int max_steps = kernel_data.integrator.volume_max_steps;
+ float step = min(kernel_data.integrator.volume_step_size, t);
+
+ /* compute exact steps in advance for malloc */
+ if(t > max_steps * step) {
+ step = t / (float)max_steps;
+ }
+
+ *step_size = step;
+ *step_offset = path_state_rng_1D_hash(kg, state, 0x1e31d8a4) * step;
+}
+
/* Volume Shadows
*
* These functions are used to attenuate shadow rays to lights. Both absorption
@@ -188,8 +206,8 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
/* prepare for stepping */
int max_steps = kernel_data.integrator.volume_max_steps;
- float step = kernel_data.integrator.volume_step_size;
- float random_jitter_offset = lcg_step_float_addrspace(&state->rng_congruential) * step;
+ float step_offset, step_size;
+ kernel_volume_step_init(kg, state, ray->t, &step_size, &step_offset);
/* compute extinction at the start */
float t = 0.0f;
@@ -198,14 +216,15 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
for(int i = 0; i < max_steps; i++) {
/* advance to new position */
- float new_t = min(ray->t, (i+1) * step);
- float dt = new_t - t;
+ float new_t = min(ray->t, (i+1) * step_size);
- /* use random position inside this segment to sample shader */
- if(new_t == ray->t)
- random_jitter_offset = lcg_step_float_addrspace(&state->rng_congruential) * dt;
+ /* 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 + random_jitter_offset);
+ float3 new_P = ray->P + ray->D * (t + step_offset);
float3 sigma_t;
/* compute attenuation over segment */
@@ -504,8 +523,8 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
/* prepare for stepping */
int max_steps = kernel_data.integrator.volume_max_steps;
- float step_size = kernel_data.integrator.volume_step_size;
- float random_jitter_offset = lcg_step_float_addrspace(&state->rng_congruential) * step_size;
+ float step_offset, step_size;
+ kernel_volume_step_init(kg, state, ray->t, &step_size, &step_offset);
/* compute coefficients at the start */
float t = 0.0f;
@@ -522,11 +541,13 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
float new_t = min(ray->t, (i+1) * step_size);
float dt = new_t - t;
- /* use random position inside this segment to sample shader */
- if(new_t == ray->t)
- random_jitter_offset = lcg_step_float_addrspace(&state->rng_congruential) * dt;
+ /* use random position inside this segment to sample shader,
+ * 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 + random_jitter_offset);
+ float3 new_P = ray->P + ray->D * (t + step_offset);
VolumeShaderCoefficients coeff;
/* compute segment */
@@ -694,19 +715,12 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
/* prepare for volume stepping */
int max_steps;
- float step_size, random_jitter_offset;
+ float step_size, step_offset;
if(heterogeneous) {
- const int global_max_steps = kernel_data.integrator.volume_max_steps;
- step_size = kernel_data.integrator.volume_step_size;
- /* compute exact steps in advance for malloc */
- if(ray->t > global_max_steps*step_size) {
- max_steps = global_max_steps;
- step_size = ray->t / (float)max_steps;
- }
- else {
- max_steps = max((int)ceilf(ray->t/step_size), 1);
- }
+ max_steps = kernel_data.integrator.volume_max_steps;
+ kernel_volume_step_init(kg, state, ray->t, &step_size, &step_offset);
+
#ifdef __KERNEL_CPU__
/* NOTE: For the branched path tracing it's possible to have direct
* and indirect light integration both having volume segments allocated.
@@ -723,19 +737,18 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
sizeof(*kg->decoupled_volume_steps));
if(kg->decoupled_volume_steps[index] == NULL) {
kg->decoupled_volume_steps[index] =
- (VolumeStep*)malloc(sizeof(VolumeStep)*global_max_steps);
+ (VolumeStep*)malloc(sizeof(VolumeStep)*max_steps);
}
segment->steps = kg->decoupled_volume_steps[index];
++kg->decoupled_volume_steps_index;
#else
segment->steps = (VolumeStep*)malloc(sizeof(VolumeStep)*max_steps);
#endif
- random_jitter_offset = lcg_step_float(&state->rng_congruential) * step_size;
}
else {
max_steps = 1;
step_size = ray->t;
- random_jitter_offset = 0.0f;
+ step_offset = 0.0f;
segment->steps = &segment->stack_step;
}
@@ -757,11 +770,13 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
float new_t = min(ray->t, (i+1) * step_size);
float dt = new_t - t;
- /* use random position inside this segment to sample shader */
- if(heterogeneous && new_t == ray->t)
- random_jitter_offset = lcg_step_float(&state->rng_congruential) * dt;
+ /* use random position inside this segment to sample shader,
+ * 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 + random_jitter_offset);
+ float3 new_P = ray->P + ray->D * (t + step_offset);
VolumeShaderCoefficients coeff;
/* compute segment */
@@ -818,7 +833,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
step->accum_transmittance = accum_transmittance;
step->cdf_distance = cdf_distance;
step->t = new_t;
- step->shade_t = t + random_jitter_offset;
+ step->shade_t = t + step_offset;
/* stop if at the end of the volume */
t = new_t;