[Bf-blender-cvs] [a466d7ae248] master: Cycles: better distance sampling for chromatic volume extinction.

Brecht Van Lommel noreply at git.blender.org
Fri Nov 10 01:53:10 CET 2017


Commit: a466d7ae248b2807b4e2f8693b458d3da509e9bc
Author: Brecht Van Lommel
Date:   Thu Nov 9 04:42:07 2017 +0100
Branches: master
https://developer.blender.org/rBa466d7ae248b2807b4e2f8693b458d3da509e9bc

Cycles: better distance sampling for chromatic volume extinction.

Previously we picked one of the RGB channels with equal probability, but this
works poorly in a dense volume after many bounces. Now we take into account
the throughput and single scattering albedo.

This makes it a little more practical to do brute force SSS with volumes, but
is still very inefficient because we do direct light sampling at every volume
bounce even when inside an opaque mesh. In theory there could be a light inside
the mesh so we can't automatically disable direct lighting.

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

M	intern/cycles/kernel/kernel_volume.h

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

diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 5604d8e5163..2af4c9a5e7a 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -74,7 +74,8 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals *kg,
 	                                            make_float3(0.0f, 0.0f, 0.0f);
 
 	if(sd->flag & SD_SCATTER) {
-		if(state->volume_bounce < kernel_data.integrator.max_volume_bounce) {
+		if(state->bounce < kernel_data.integrator.max_bounce &&
+		   state->volume_bounce < kernel_data.integrator.max_volume_bounce) {
 			for(int i = 0; i < sd->num_closure; i++) {
 				const ShaderClosure *sc = &sd->closure[i];
 
@@ -340,6 +341,34 @@ ccl_device float3 kernel_volume_emission_integrate(VolumeShaderCoefficients *coe
 
 /* Volume Path */
 
+ccl_device int kernel_volume_sample_channel(float3 albedo, float3 throughput, float rand, float3 *pdf)
+{
+	/* Sample color channel proportional to throughput and single scattering
+	 * albedo, to significantly reduce noise with many bounce, following:
+	 *
+	 * "Practical and Controllable Subsurface Scattering for Production Path
+	 *  Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */
+	float3 weights = fabs(throughput * albedo);
+	float sum_weights = weights.x + weights.y + weights.z;
+
+	if(sum_weights > 0.0f) {
+		*pdf = weights/sum_weights;
+	}
+	else {
+		*pdf = make_float3(1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f);
+	}
+
+	if(rand < pdf->x) {
+		return 0;
+	}
+	else if(rand < pdf->x + pdf->y) {
+		return 1;
+	}
+	else {
+		return 2;
+	}
+}
+
 /* homogeneous volume: assume shader evaluation at the start gives
  * the volume shading coefficient for the entire line segment */
 ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(
@@ -363,20 +392,18 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(
 #ifdef __VOLUME_SCATTER__
 	/* randomly scatter, and if we do t is shortened */
 	if(closure_flag & SD_SCATTER) {
-		/* extinction coefficient */
-		float3 sigma_t = coeff.sigma_t;
-
-		/* pick random color channel, we use the Veach one-sample
-		 * model with balance heuristic for the channels */
+		/* Sample channel, use MIS with balance heuristic. */
 		float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL);
-		int channel = (int)(rphase*3.0f);
+		float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
+		float3 channel_pdf;
+		int channel = kernel_volume_sample_channel(albedo, *throughput, rphase, &channel_pdf);
 
 		/* decide if we will hit or miss */
 		bool scatter = true;
 		float xi = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE);
 
 		if(probalistic_scatter) {
-			float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel);
+			float sample_sigma_t = kernel_volume_channel_get(coeff.sigma_t, channel);
 			float sample_transmittance = expf(-sample_sigma_t * t);
 
 			if(1.0f - xi >= sample_transmittance) {
@@ -397,19 +424,19 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(
 			float sample_t;
 
 			/* distance sampling */
-			sample_t = kernel_volume_distance_sample(ray->t, sigma_t, channel, xi, &transmittance, &pdf);
+			sample_t = kernel_volume_distance_sample(ray->t, coeff.sigma_t, channel, xi, &transmittance, &pdf);
 
 			/* modify pdf for hit/miss decision */
 			if(probalistic_scatter)
-				pdf *= make_float3(1.0f, 1.0f, 1.0f) - volume_color_transmittance(sigma_t, t);
+				pdf *= make_float3(1.0f, 1.0f, 1.0f) - volume_color_transmittance(coeff.sigma_t, t);
 
-			new_tp = *throughput * coeff.sigma_s * transmittance / average(pdf);
+			new_tp = *throughput * coeff.sigma_s * transmittance / dot(channel_pdf, pdf);
 			t = sample_t;
 		}
 		else {
 			/* no scattering */
-			float3 transmittance = volume_color_transmittance(sigma_t, t);
-			float pdf = average(transmittance);
+			float3 transmittance = volume_color_transmittance(coeff.sigma_t, t);
+			float pdf = dot(channel_pdf, transmittance);
 			new_tp = *throughput * transmittance / pdf;
 		}
 	}
@@ -423,8 +450,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(
 
 	/* integrate emission attenuated by extinction */
 	if(L && (closure_flag & SD_EMISSION)) {
-		float3 sigma_t = coeff.sigma_t;
-		float3 transmittance = volume_color_transmittance(sigma_t, ray->t);
+		float3 transmittance = volume_color_transmittance(coeff.sigma_t, ray->t);
 		float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, ray->t);
 		path_radiance_accum_emission(L, state, *throughput, emission);
 	}
@@ -473,7 +499,6 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
 	 * model with balance heuristic for the channels */
 	float xi = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE);
 	float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL);
-	int channel = (int)(rphase*3.0f);
 	bool has_scatter = false;
 
 	for(int i = 0; i < max_steps; i++) {
@@ -500,32 +525,34 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
 			if((closure_flag & SD_SCATTER) || (has_scatter && (closure_flag & SD_EXTINCTION))) {
 				has_scatter = true;
 
-				float3 sigma_t = coeff.sigma_t;
-				float3 sigma_s = coeff.sigma_s;
+				/* Sample channel, use MIS with balance heuristic. */
+				float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
+				float3 channel_pdf;
+				int channel = kernel_volume_sample_channel(albedo, tp, rphase, &channel_pdf);
 
 				/* compute transmittance over full step */
-				transmittance = volume_color_transmittance(sigma_t, dt);
+				transmittance = volume_color_transmittance(coeff.sigma_t, dt);
 
 				/* decide if we will scatter or continue */
 				float sample_transmittance = kernel_volume_channel_get(transmittance, channel);
 
 				if(1.0f - xi >= sample_transmittance) {
 					/* compute sampling distance */
-					float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel);
+					float sample_sigma_t = kernel_volume_channel_get(coeff.sigma_t, channel);
 					float new_dt = -logf(1.0f - xi)/sample_sigma_t;
 					new_t = t + new_dt;
 
 					/* transmittance and pdf */
-					float3 new_transmittance = volume_color_transmittance(sigma_t, new_dt);
-					float3 pdf = sigma_t * new_transmittance;
+					float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
+					float3 pdf = coeff.sigma_t * new_transmittance;
 
 					/* throughput */
-					new_tp = tp * sigma_s * new_transmittance / average(pdf);
+					new_tp = tp * coeff.sigma_s * new_transmittance / dot(channel_pdf, pdf);
 					scatter = true;
 				}
 				else {
 					/* throughput */
-					float pdf = average(transmittance);
+					float pdf = dot(channel_pdf, transmittance);
 					new_tp = tp * transmittance / pdf;
 
 					/* remap xi so we can reuse it and keep thing stratified */
@@ -632,6 +659,7 @@ typedef struct VolumeSegment {
 
 	float3 accum_emission;		/* accumulated emission at end of segment */
 	float3 accum_transmittance;	/* accumulated transmittance at end of segment */
+	float3 accum_albedo;        /* accumulated average albedo over segment */
 
 	int sampling_method;		/* volume sampling method */
 } VolumeSegment;
@@ -698,6 +726,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
 	/* init accumulation variables */
 	float3 accum_emission = make_float3(0.0f, 0.0f, 0.0f);
 	float3 accum_transmittance = make_float3(1.0f, 1.0f, 1.0f);
+	float3 accum_albedo = make_float3(0.0f, 0.0f, 0.0f);
 	float3 cdf_distance = make_float3(0.0f, 0.0f, 0.0f);
 	float t = 0.0f;
 
@@ -724,6 +753,11 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
 			int closure_flag = sd->flag;
 			float3 sigma_t = coeff.sigma_t;
 
+			/* compute average albedo for channel sampling */
+			if(closure_flag & SD_SCATTER) {
+				accum_albedo += dt * safe_divide_color(coeff.sigma_s, sigma_t);
+			}
+
 			/* compute accumulated transmittance */
 			float3 transmittance = volume_color_transmittance(sigma_t, dt);
 
@@ -783,6 +817,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
 	/* store total emission and transmittance */
 	segment->accum_emission = accum_emission;
 	segment->accum_transmittance = accum_transmittance;
+	segment->accum_albedo = accum_albedo;
 
 	/* normalize cumulative density function for distance sampling */
 	VolumeStep *last_step = segment->steps + segment->numsteps - 1;
@@ -825,9 +860,13 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter(
 {
 	kernel_assert(segment->closure_flag & SD_SCATTER);
 
-	/* pick random color channel, we use the Veach one-sample
-	 * model with balance heuristic for the channels */
-	int channel = (int)(rphase*3.0f);
+	/* Sample color channel, use MIS with balance heuristic. */
+	float3 channel_pdf;
+	int channel = kernel_volume_sample_channel(segment->accum_albedo,
+	                                           *throughput,
+	                                           rphase,
+	                                           &channel_pdf);
+
 	float xi = rscatter;
 
 	/* probabilistic scattering decision based on transmittance */
@@ -914,7 +953,7 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter(
 		if(probalistic_scatter)
 			distance_pdf *= make_float3(1.0f, 1.0f, 1.0f) - segment->accum_transmittance;
 
-		pdf = average(distance_pdf * step_pdf_distance);
+		pdf = dot(channel_pdf, distance_pdf * step_pdf_distance);
 
 		/* multiple importance sampling */
 		if(use_mis) {
@@ -977,7 +1016,7 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter(
 		/* multiple importance sampling */
 		if(use_mis) {
 			float3 distance_pdf3 = kernel_volume_distance_pdf(step_t, step->sigma_t, step_sample_t);
-			float distance_pdf = average(distance_pdf3 * step_pdf_distance);
+			float distance_pdf = dot(channel_pdf, distance_pdf3 * step_pdf_distance);
 			mis_weight = 2.0f*power_heuristic(pdf, distance_pdf);
 		}
 	}



More information about the Bf-blender-cvs mailing list