[Bf-blender-cvs] [462adab] soc-2016-cycles_denoising: Cycles: Generate and fill the Shadow feature passes

Lukas Stockner noreply at git.blender.org
Sun Jul 24 03:46:08 CEST 2016


Commit: 462adab15d44b8a6da83ff958ec845358e8d3b32
Author: Lukas Stockner
Date:   Sun Jul 24 02:00:41 2016 +0200
Branches: soc-2016-cycles_denoising
https://developer.blender.org/rB462adab15d44b8a6da83ff958ec845358e8d3b32

Cycles: Generate and fill the Shadow feature passes

This commit makes the path tracing kernel generate the needed data for the shadow passes and fill them.

The approach used here is quite similar to a shadowcatcher:
The R channel of the passes records the total energy of direct light queries, no matter whether they were shadowed or not.
The G channel records the amount of energy that actually was unoccluded. Therefore, dividing G by R produces a accurate pass containing the amount of shadowing (between zero and one, since G can never be larger than R).
The B channel contains an approximation of the variance of the shadow info.
However, since Var[E[Unoccluded]/E[Full]] (which is what would be needed) is impossible to compute analytically from the samples, Var[Unoccluded/Full] is used instead (Variance of the individual ratios at each sample, instead of the variance of the ratio of the mean values after sampling).
That's both biased and actually might not even be close, it still is of use in prefiltering: The correct variance can be estimated (with a lot of noise) from the difference of the A and B passes, and the approximation in the B channel can be used for the weights used to prefilter the noisy, but correct variance.

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

M	intern/cycles/kernel/kernel_accumulate.h
M	intern/cycles/kernel/kernel_bake.h
M	intern/cycles/kernel/kernel_passes.h
M	intern/cycles/kernel/kernel_path.h
M	intern/cycles/kernel/kernel_path_surface.h

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

diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
index d529ac1..c076a9b 100644
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ b/intern/cycles/kernel/kernel_accumulate.h
@@ -121,6 +121,18 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value)
 #endif
 }
 
+ccl_device_inline float3 bsdf_eval_sum(BsdfEval *eval, bool use_light_pass)
+{
+#ifdef __PASSES__
+	if(use_light_pass)
+		return eval->diffuse + eval->glossy + eval->transmission + eval->transparent + eval->subsurface + eval->scatter;
+	else
+		return eval->diffuse;
+#else
+	return *eval;
+#endif
+}
+
 /* Path Radiance
  *
  * We accumulate different render passes separately. After summing at the end
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 9ee0b09..4ad64d7 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -111,7 +111,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
 
 		/* sample light and BSDF */
 		if(!is_sss_sample && (pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT))) {
-			kernel_path_surface_connect_light(kg, &rng, sd, &emission_sd, throughput, &state, &L_sample);
+			kernel_path_surface_connect_light(kg, &rng, sd, &emission_sd, throughput, &state, &L_sample, NULL);
 
 			if(kernel_path_surface_bounce(kg, &rng, sd, &throughput, &state, &L_sample, &ray)) {
 #ifdef __LAMP_MIS__
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index 7e7cf29..252c45b 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -106,15 +106,39 @@ ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, int sa
 #endif // __SPLIT_KERNEL__ && __WORK_STEALING__
 }
 
-ccl_device_inline void kernel_write_denoising_passes(KernelGlobals *kg, ccl_global float *buffer,
-	ccl_addr_space PathState *state, ShaderData *sd, int sample, float3 world_albedo)
+ccl_device_inline void kernel_write_denoising_shadow(KernelGlobals *kg, ccl_global float *buffer,
+	int sample, float2 shadow_info)
 {
 	if(kernel_data.film.pass_denoising == 0)
 		return;
+
+	if(sample & 1) buffer += 3;
+	buffer += kernel_data.film.pass_denoising + 14;
+
+	if(sample < 2) {
+		buffer[0] = shadow_info.x; /* Unoccluded lighting */
+		buffer[1] = shadow_info.y; /* Occluded lighting */
+		buffer[2] = 0.0f; /* Sample variance */
+	}
+	else {
+		float old_shadowing = buffer[1] / max(buffer[0], 1e-7f);
+		buffer[0] += shadow_info.x;
+		buffer[1] += shadow_info.y;
+		float new_shadowing = buffer[1] / max(buffer[0], 1e-7f);
+		float cur_shadowing = shadow_info.y / max(shadow_info.x, 1e-7f);
+		buffer[2] += (cur_shadowing - old_shadowing) * (cur_shadowing - new_shadowing);
+	}
+}
+
+ccl_device_inline bool kernel_write_denoising_passes(KernelGlobals *kg, ccl_global float *buffer,
+	ccl_addr_space PathState *state, ShaderData *sd, int sample, float3 world_albedo)
+{
+	if(kernel_data.film.pass_denoising == 0)
+		return false;
 	buffer += kernel_data.film.pass_denoising;
 
 	if(state->flag & PATH_RAY_DENOISING_PASS_DONE)
-		return;
+		return false;
 
 	/* Can also be called if the ray misses the scene, sd is NULL in that case. */
 	if(sd) {
@@ -151,7 +175,7 @@ ccl_device_inline void kernel_write_denoising_passes(KernelGlobals *kg, ccl_glob
 			ShaderClosure *max_sc = ccl_fetch_array(sd, closure, max_weight_closure);
 			if(max_sc->roughness <= 0.075f) {
 				/* This bounce is almost specular, so don't write the data yet. */
-				return;
+				return false;
 			}
 			kernel_write_pass_float3_var(buffer, sample, normal/sum_weight);
 			kernel_write_pass_float3_var(buffer + 6, sample, albedo);
@@ -165,6 +189,7 @@ ccl_device_inline void kernel_write_denoising_passes(KernelGlobals *kg, ccl_glob
 	}
 
 	state->flag |= PATH_RAY_DENOISING_PASS_DONE;
+	return true;
 }
 
 ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L,
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 63298a2..1c7e1e9 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -508,7 +508,7 @@ ccl_device bool kernel_path_subsurface_scatter(
 			hit_L->direct_throughput = L->direct_throughput;
 			path_radiance_copy_indirect(hit_L, L);
 
-			kernel_path_surface_connect_light(kg, rng, sd, emission_sd, *hit_tp, state, hit_L);
+			kernel_path_surface_connect_light(kg, rng, sd, emission_sd, *hit_tp, state, hit_L, NULL);
 
 			if(kernel_path_surface_bounce(kg,
 			                              rng,
@@ -797,7 +797,7 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg,
 		float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
 		shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
 
-		kernel_write_denoising_passes(kg, buffer, &state, &sd, sample, make_float3(0.0f, 0.0f, 0.0f));
+		bool write_denoising_shadow = kernel_write_denoising_passes(kg, buffer, &state, &sd, sample, make_float3(0.0f, 0.0f, 0.0f));
 
 		/* holdout */
 #ifdef __HOLDOUT__
@@ -886,7 +886,10 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg,
 #endif  /* __SUBSURFACE__ */
 
 		/* direct lighting */
-		kernel_path_surface_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, L);
+		float2 shadow_info = make_float2(0.0f, 0.0f);
+		kernel_path_surface_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, L, &shadow_info);
+		if(write_denoising_shadow)
+			kernel_write_denoising_shadow(kg, buffer, sample, shadow_info);
 
 		/* compute direct lighting and next bounce */
 		if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, &state, L, &ray))
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index 74b1ae0..e17ce5b 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -186,7 +186,7 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng,
 /* path tracing: connect path directly to position on a light and add it to L */
 ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_addr_space RNG *rng,
 	ShaderData *sd, ShaderData *emission_sd, float3 throughput, ccl_addr_space PathState *state,
-	PathRadiance *L)
+	PathRadiance *L, float2 *shadow_info)
 {
 #ifdef __EMISSION__
 	if(!(kernel_data.integrator.use_direct_light && (ccl_fetch(sd, flag) & SD_BSDF_HAS_EVAL)))
@@ -211,11 +211,18 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_
 	if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
 		/* trace shadow ray */
 		float3 shadow;
+		float3 light_unoccluded;
+		if(shadow_info) {
+			light_unoccluded = throughput * bsdf_eval_sum(&L_light, L->use_light_pass);
+			shadow_info->x = average(light_unoccluded);
+		}
 
 		if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
 			/* accumulate */
 			path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
+			if(shadow_info) shadow_info->y = average(light_unoccluded*shadow);
 		}
+		else if(shadow_info) shadow_info->y = 0.0f;
 	}
 #endif
 }




More information about the Bf-blender-cvs mailing list