[Bf-blender-cvs] [d88d0772370] cycles-x: Cycles X: refactor to separately track direct and indirect in volumes

Brecht Van Lommel noreply at git.blender.org
Fri Jul 23 19:29:02 CEST 2021


Commit: d88d07723709dec7e62ad5db2187cd451e9eb21c
Author: Brecht Van Lommel
Date:   Wed Jul 7 21:01:54 2021 +0200
Branches: cycles-x
https://developer.blender.org/rBd88d07723709dec7e62ad5db2187cd451e9eb21c

Cycles X: refactor to separately track direct and indirect in volumes

So that we can scatter at two different positions.

Ref D11845

===================================================================

M	intern/cycles/kernel/integrator/integrator_shade_volume.h

===================================================================

diff --git a/intern/cycles/kernel/integrator/integrator_shade_volume.h b/intern/cycles/kernel/integrator/integrator_shade_volume.h
index 08457473cd8..4e4b6243615 100644
--- a/intern/cycles/kernel/integrator/integrator_shade_volume.h
+++ b/intern/cycles/kernel/integrator/integrator_shade_volume.h
@@ -31,6 +31,21 @@ typedef enum VolumeIntegrateEvent {
   VOLUME_PATH_MISSED = 2
 } VolumeIntegrateEvent;
 
+typedef struct VolumeIntegrateResult {
+  /* Throughput and offset for direct light scattering. */
+  VolumeSampleMethod direct_sample_method;
+  bool direct_scatter;
+  float3 direct_throughput;
+  float direct_t;
+  ShaderVolumePhases direct_phases;
+
+  /* Throughput and offset for indirect light scattering. */
+  bool indirect_scatter;
+  float3 indirect_throughput;
+  float indirect_t;
+  ShaderVolumePhases indirect_phases;
+} VolumeIntegrateResult;
+
 /* Ignore paths that have volume throughput below this value, to avoid unnecessary work
  * and precision issues.
  * todo: this value could be tweaked or turned into a probability to avoid unnecessary
@@ -366,24 +381,88 @@ ccl_device float3 volume_emission_integrate(VolumeShaderCoefficients *coeff,
   return emission;
 }
 
-/* Volume Path */
+/* Volume Integration */
+
+typedef struct VolumeIntegrateState {
+  /* Volume segment extents. */
+  float start_t;
+  float end_t;
+
+  /* Current throughput. */
+  float3 throughput;
+
+  /* If volume is absorption-only up to this point, and no probabilistic
+   * scattering or termination has been used yet. */
+  bool absorption_only;
+
+  /* Random numbers for scattering. */
+  float rscatter;
+  float rphase;
+} VolumeIntegrateState;
+
+ccl_device_forceinline void volume_integrate_step_scattering(
+    const ShaderData *sd,
+    const VolumeShaderCoefficients &ccl_restrict coeff,
+    const float3 transmittance,
+    VolumeIntegrateState &ccl_restrict vstate,
+    VolumeIntegrateResult &ccl_restrict result)
+{
+  /* Distance sampling */
+
+  /* Pick random color channel, we use the Veach one-sample
+   * model with balance heuristic for the channels. */
+  const float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
+  float3 channel_pdf;
+  const int channel = volume_sample_channel(
+      albedo, result.indirect_throughput, vstate.rphase, &channel_pdf);
+
+  /* decide if we will scatter or continue */
+  const float sample_transmittance = volume_channel_get(transmittance, channel);
+
+  if (1.0f - vstate.rscatter >= sample_transmittance) {
+    /* compute sampling distance */
+    const float sample_sigma_t = volume_channel_get(coeff.sigma_t, channel);
+    const float new_dt = -logf(1.0f - vstate.rscatter) / sample_sigma_t;
+    const float new_t = vstate.start_t + new_dt;
+
+    /* transmittance and pdf */
+    const float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
+    const float3 pdf = coeff.sigma_t * new_transmittance;
+
+    /* throughput */
+    result.indirect_scatter = true;
+    result.indirect_t = new_t;
+    result.indirect_throughput *= coeff.sigma_s * new_transmittance / dot(channel_pdf, pdf);
+    shader_copy_volume_phases(&result.indirect_phases, sd);
+
+    result.direct_scatter = true;
+    result.direct_t = result.indirect_t;
+    result.direct_throughput = result.indirect_throughput;
+    shader_copy_volume_phases(&result.direct_phases, sd); /* TODO: only copy once? */
+  }
+  else {
+    /* throughput */
+    const float pdf = dot(channel_pdf, transmittance);
+    result.indirect_throughput *= transmittance / pdf;
+
+    /* remap rscatter so we can reuse it and keep thing stratified */
+    vstate.rscatter = 1.0f - (1.0f - vstate.rscatter) / sample_transmittance;
+  }
+}
 
 /* heterogeneous volume distance sampling: integrate stepping through the
  * volume until we reach the end, get absorbed entirely, or run out of
  * iterations. this does probabilistically scatter or get transmitted through
  * for path tracing where we don't want to branch. */
-ccl_device VolumeIntegrateEvent
-volume_integrate_heterogeneous(INTEGRATOR_STATE_ARGS,
-                               Ray *ccl_restrict ray,
-                               ShaderData *ccl_restrict sd,
-                               ShaderVolumePhases *ccl_restrict phases,
-                               ccl_addr_space float3 *ccl_restrict throughput,
-                               const RNGState *rng_state,
-                               ccl_global float *ccl_restrict render_buffer,
-                               const float object_step_size)
+ccl_device_forceinline void volume_integrate_heterogeneous(INTEGRATOR_STATE_ARGS,
+                                                           Ray *ccl_restrict ray,
+                                                           ShaderData *ccl_restrict sd,
+                                                           const RNGState *rng_state,
+                                                           ccl_global float *ccl_restrict
+                                                               render_buffer,
+                                                           const float object_step_size,
+                                                           VolumeIntegrateResult &result)
 {
-  float3 tp = *throughput;
-
   /* Prepare for stepping.
    * Using a different step offset for the first step avoids banding artifacts. */
   int max_steps;
@@ -397,123 +476,86 @@ volume_integrate_heterogeneous(INTEGRATOR_STATE_ARGS,
                    &steps_offset,
                    &max_steps);
 
-  /* compute coefficients at the start */
-  float t = 0.0f;
-  float3 accum_transmittance = one_float3();
+  /* Initialize volume integration state. */
+  VolumeIntegrateState vstate ccl_optional_struct_init;
+  vstate.start_t = 0.0f;
+  vstate.end_t = 0.0f;
+  vstate.absorption_only = true;
+  vstate.rscatter = path_state_rng_1D(kg, rng_state, PRNG_SCATTER_DISTANCE);
+  vstate.rphase = path_state_rng_1D(kg, rng_state, PRNG_PHASE_CHANNEL);
 
-  /* pick random color channel, we use the Veach one-sample
-   * model with balance heuristic for the channels */
-  float xi = path_state_rng_1D(kg, rng_state, PRNG_SCATTER_DISTANCE);
-  const float rphase = path_state_rng_1D(kg, rng_state, PRNG_PHASE_CHANNEL);
-  bool has_scatter = false;
+  /* Initialize volume integration result. */
+  const float3 throughput = INTEGRATOR_STATE(path, throughput);
+  result.direct_throughput = throughput;
+  result.indirect_throughput = throughput;
 
   for (int i = 0; i < max_steps; i++) {
-    /* advance to new position */
-    float new_t = min(ray->t, (i + steps_offset) * step_size);
-    float dt = new_t - t;
-
-    float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
-    VolumeShaderCoefficients coeff ccl_optional_struct_init;
+    /* Advance to new position */
+    vstate.end_t = min(ray->t, (i + steps_offset) * step_size);
+    const float shade_t = vstate.start_t + (vstate.end_t - vstate.start_t) * step_shade_offset;
+    sd->P = ray->P + ray->D * shade_t;
 
     /* compute segment */
-    sd->P = new_P;
+    VolumeShaderCoefficients coeff ccl_optional_struct_init;
     if (volume_shader_sample(INTEGRATOR_STATE_PASS, sd, &coeff)) {
-      int closure_flag = sd->flag;
-      float3 new_tp;
-      float3 transmittance;
-      bool scatter = false;
-
-      /* distance sampling */
-      if ((closure_flag & SD_SCATTER) || (has_scatter && (closure_flag & SD_EXTINCTION))) {
-        has_scatter = true;
-
-        /* Sample channel, use MIS with balance heuristic. */
-        const float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
-        float3 channel_pdf;
-        const int channel = volume_sample_channel(albedo, tp, rphase, &channel_pdf);
-
-        /* compute transmittance over full step */
-        transmittance = volume_color_transmittance(coeff.sigma_t, dt);
-
-        /* decide if we will scatter or continue */
-        const float sample_transmittance = volume_channel_get(transmittance, channel);
-
-        if (1.0f - xi >= sample_transmittance) {
-          /* compute sampling distance */
-          const float sample_sigma_t = volume_channel_get(coeff.sigma_t, channel);
-          const float new_dt = -logf(1.0f - xi) / sample_sigma_t;
-          new_t = t + new_dt;
-
-          /* transmittance and pdf */
-          const float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
-          const float3 pdf = coeff.sigma_t * new_transmittance;
-
-          /* throughput */
-          new_tp = tp * coeff.sigma_s * new_transmittance / dot(channel_pdf, pdf);
-          scatter = true;
-        }
-        else {
-          /* throughput */
-          const float pdf = dot(channel_pdf, transmittance);
-          new_tp = tp * transmittance / pdf;
+      const int closure_flag = sd->flag;
 
-          /* remap xi so we can reuse it and keep thing stratified */
-          xi = 1.0f - (1.0f - xi) / sample_transmittance;
-        }
-      }
-      else if (closure_flag & SD_EXTINCTION) {
-        /* absorption only, no sampling needed */
-        transmittance = volume_color_transmittance(coeff.sigma_t, dt);
-        new_tp = tp * transmittance;
-      }
-      else {
-        transmittance = zero_float3();
-        new_tp = tp;
-      }
+      /* Evaluate transmittance over segment. */
+      const float dt = (vstate.end_t - vstate.start_t);
+      const float3 transmittance = (closure_flag & SD_EXTINCTION) ?
+                                       volume_color_transmittance(coeff.sigma_t, dt) :
+                                       one_float3();
 
-      /* integrate emission attenuated by absorption */
+      /* Emission. */
       if (closure_flag & SD_EMISSION) {
-        const float3 emission = volume_emission_integrate(&coeff, closure_flag, transmittance, dt);
-        kernel_accum_emission(INTEGRATOR_STATE_PASS, tp, emission, render_buffer);
+        /* Only write emission before indirect light scatter position, since we terminate
+         * stepping at that point if we have already found a direct light scatter position. */
+        if (!result.indirect_scatter) {
+          /* TODO: write only once to avoid overhead of atomics? */
+          const float3 emission = volume_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list