[Bf-blender-cvs] [85bd1a8] soc-2016-cycles_denoising: Cycles: Write denoising feature passes

Lukas Stockner noreply at git.blender.org
Sat Jun 4 22:03:14 CEST 2016


Commit: 85bd1a8ad4a4b8bec691805a2b1fa27db4500954
Author: Lukas Stockner
Date:   Sat Jun 4 21:41:14 2016 +0200
Branches: soc-2016-cycles_denoising
https://developer.blender.org/rB85bd1a8ad4a4b8bec691805a2b1fa27db4500954

Cycles: Write denoising feature passes

With this commit, the newly added passes finally get some content.
The three explicitly stored features are the surface normal, the albedo of the surface
and the path length from the camera. These features will be used by the denoiser to "understand"
where differences in lighting come from - for example, the normal pass allows the denoiser to
smooth the noise on a wall, but keep the edge in the corner of the room perfectly sharp.
To preserve small detail like bumpmapped reflections, the actual normal used for shading
is stored instead of the surface normal which is used for the regular Normal pass.
The main purpose of the albedo pass is to preserve fine texture detail, but can also help to detect
object borders.
The depth pass helps for some edges where both surfaces have the same orientation
(so that normal don't help), but its variance also helps to detect depth-of-field blurring.

The real image passes aren't stored yet because they still require a bit of refactoring.

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

M	intern/cycles/kernel/kernel_passes.h
M	intern/cycles/kernel/kernel_path.h
M	intern/cycles/kernel/kernel_path_branched.h
M	intern/cycles/kernel/kernel_types.h
M	intern/cycles/render/buffers.cpp

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

diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index 20cf3fa..5b65bff 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -26,6 +26,20 @@ ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, int sam
 #endif // __SPLIT_KERNEL__ && __WORK_STEALING__
 }
 
+ccl_device_inline void kernel_write_pass_float_var(ccl_global float *buffer, int sample, float value)
+{
+	if(sample == 0) {
+		*buffer = value;
+		*(buffer + 1) = 0.0f;
+	}
+	else {
+		float old = *buffer;
+		buffer[0] += value;
+		/* Online single-pass variance estimation - difference to old mean multiplied by difference to new mean. */
+		buffer[1] += (value - (old / sample)) * (value - ((old + value) / (sample + 1)));
+	}
+}
+
 ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, int sample, float3 value)
 {
 #if defined(__SPLIT_KERNEL__) && defined(__WORK_STEALING__)
@@ -42,6 +56,30 @@ ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, int sa
 #endif // __SPLIT_KERNEL__ && __WORK_STEALING__
 }
 
+ccl_device_inline void kernel_write_pass_float3_var(ccl_global float *buffer, int sample, float3 value)
+{
+	if(sample == 0) {
+		buffer[0] = value.x;
+		buffer[1] = value.y;
+		buffer[2] = value.z;
+		buffer[3] = 0.0f;
+		buffer[4] = 0.0f;
+		buffer[5] = 0.0f;
+	}
+	else {
+		float old;
+		old = buffer[0];
+		buffer[0] += value.x;
+		buffer[3] += (value.x - (old / sample)) * (value.x - ((old + value.x) / (sample + 1)));
+		old = buffer[1];
+		buffer[1] += value.y;
+		buffer[4] += (value.y - (old / sample)) * (value.y - ((old + value.y) / (sample + 1)));
+		old = buffer[2];
+		buffer[2] += value.z;
+		buffer[5] += (value.z - (old / sample)) * (value.z - ((old + value.z) / (sample + 1)));
+	}
+}
+
 ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, int sample, float4 value)
 {
 #if defined(__SPLIT_KERNEL__) && defined(__WORK_STEALING__)
@@ -60,6 +98,64 @@ 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)
+{
+	if(kernel_data.film.pass_denoising == 0)
+		return;
+	buffer += kernel_data.film.pass_denoising;
+
+	if(state->flag & PATH_RAY_DENOISING_PASS_DONE)
+		return;
+
+	/* Can also be called if the ray misses the scene, sd is NULL in that case. */
+	if(sd) {
+		state->path_length += ccl_fetch(sd, ray_length);
+
+		float3 normal = make_float3(0.0f, 0.0f, 0.0f);
+		float3 albedo = make_float3(0.0f, 0.0f, 0.0f);
+		float sum_weight = 0.0f, max_weight = 0.0f;
+		int max_weight_closure = -1;
+
+		/* Average normal and albedo, determine the closure with the highest weight for the roughness decision. */
+		for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
+			ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
+
+			normal += sc->N * sc->sample_weight;
+			albedo += sc->weight;
+			sum_weight += sc->sample_weight;
+
+			if(sc->sample_weight > max_weight) {
+				max_weight = sc->sample_weight;
+				max_weight_closure = i;
+			}
+		}
+
+		if(sum_weight == 0.0f) {
+			kernel_write_pass_float3_var(buffer, sample, make_float3(0.0f, 0.0f, 0.0f));
+			kernel_write_pass_float3_var(buffer + 6, sample, make_float3(0.0f, 0.0f, 0.0f));
+			kernel_write_pass_float_var(buffer + 12, sample, 0.0f);
+		}
+		else {
+			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;
+			}
+			kernel_write_pass_float3_var(buffer, sample, normal/sum_weight);
+			kernel_write_pass_float3_var(buffer + 6, sample, albedo);
+			kernel_write_pass_float_var(buffer + 12, sample, state->path_length);
+		}
+	}
+	else {
+		kernel_write_pass_float3_var(buffer, sample, make_float3(0.0f, 0.0f, 0.0f));
+		kernel_write_pass_float3_var(buffer + 6, sample, world_albedo);
+		kernel_write_pass_float_var(buffer + 12, sample, 1e10f);
+	}
+
+	state->flag |= PATH_RAY_DENOISING_PASS_DONE;
+}
+
 ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L,
 	ShaderData *sd, int sample, ccl_addr_space PathState *state, float3 throughput)
 {
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index c136c85..5c4fa42 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -773,7 +773,10 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
 #ifdef __BACKGROUND__
 			/* sample background shader */
 			float3 L_background = indirect_background(kg, &state, &ray);
-			path_radiance_accum_background(&L, throughput, L_background, state.bounce);
+			path_radiance_accum_background(L, throughput, L_background, state.bounce);
+			kernel_write_denoising_passes(kg, buffer, &state, NULL, sample, L_background);
+#else
+			kernel_write_denoising_passes(kg, buffer, &state, NULL, sample, make_float3(0.0f, 0.0f, 0.0f));
 #endif
 
 			break;
@@ -785,6 +788,8 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
 		float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
 		shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
 
+		kernel_write_denoising_passes(kg, buffer, &state, &sd, sample, make_float3(0.0f, 0.0f, 0.0f));
+
 		/* holdout */
 #ifdef __HOLDOUT__
 		if((sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK)) && (state.flag & PATH_RAY_CAMERA)) {
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index 13ae4cf..a7953a0 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -433,7 +433,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
 #ifdef __BACKGROUND__
 			/* sample background shader */
 			float3 L_background = indirect_background(kg, &state, &ray);
-			path_radiance_accum_background(&L, throughput, L_background, state.bounce);
+			path_radiance_accum_background(L, throughput, L_background, state.bounce);
+			kernel_write_denoising_passes(kg, buffer, &state, NULL, sample, L_background);
+#else
+			kernel_write_denoising_passes(kg, buffer, &state, NULL, sample, make_float3(0.0f, 0.0f, 0.0f));
 #endif
 
 			break;
@@ -445,6 +448,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
 		shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
 		shader_merge_closures(&sd);
 
+		kernel_write_denoising_passes(kg, buffer, &state, &sd, sample, make_float3(0.0f, 0.0f, 0.0f));
+
 		/* holdout */
 #ifdef __HOLDOUT__
 		if(sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK)) {
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index a21f669..4b472ab 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -282,27 +282,28 @@ enum SamplingPattern {
  * layer visibility tests. */
 
 enum PathRayFlag {
-	PATH_RAY_CAMERA = 1,
-	PATH_RAY_REFLECT = 2,
-	PATH_RAY_TRANSMIT = 4,
-	PATH_RAY_DIFFUSE = 8,
-	PATH_RAY_GLOSSY = 16,
-	PATH_RAY_SINGULAR = 32,
-	PATH_RAY_TRANSPARENT = 64,
-
-	PATH_RAY_SHADOW_OPAQUE = 128,
-	PATH_RAY_SHADOW_TRANSPARENT = 256,
+	PATH_RAY_CAMERA              = (1 << 0),
+	PATH_RAY_REFLECT             = (1 << 1),
+	PATH_RAY_TRANSMIT            = (1 << 2),
+	PATH_RAY_DIFFUSE             = (1 << 3),
+	PATH_RAY_GLOSSY              = (1 << 4),
+	PATH_RAY_SINGULAR            = (1 << 5),
+	PATH_RAY_TRANSPARENT         = (1 << 6),
+
+	PATH_RAY_SHADOW_OPAQUE       = (1 << 7),
+	PATH_RAY_SHADOW_TRANSPARENT  = (1 << 8),
 	PATH_RAY_SHADOW = (PATH_RAY_SHADOW_OPAQUE|PATH_RAY_SHADOW_TRANSPARENT),
 
-	PATH_RAY_CURVE = 512, /* visibility flag to define curve segments */
-	PATH_RAY_VOLUME_SCATTER = 1024, /* volume scattering */
+	PATH_RAY_CURVE               = (1 << 9), /* visibility flag to define curve segments */
+	PATH_RAY_VOLUME_SCATTER      = (1 << 10), /* volume scattering */
 
 	/* note that these can use maximum 12 bits, the other are for layers */
 	PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024),
 
-	PATH_RAY_MIS_SKIP = 2048,
-	PATH_RAY_DIFFUSE_ANCESTOR = 4096,
-	PATH_RAY_SINGLE_PASS_DONE = 8192,
+	PATH_RAY_MIS_SKIP            = (1 << 11),
+	PATH_RAY_DIFFUSE_ANCESTOR    = (1 << 12),
+	PATH_RAY_SINGLE_PASS_DONE    = (1 << 13),
+	PATH_RAY_DENOISING_PASS_DONE = (1 << 14),
 
 	/* we need layer member flags to be the 20 upper bits */
 	PATH_RAY_LAYER_SHIFT = (32-20)
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index 32778b3..baad81a 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -177,7 +177,51 @@ bool RenderBuffers::copy_from_device()
 
 bool RenderBuffers::get_denoising_rect(int type, float exposure, int sample, int components, float *pixels)
 {
-	return false;
+	if(!params.denoising_passes)
+		/* The RenderBuffer doesn't have denoising passes. */
+		return false;
+	if(!(type & 0b111111111))
+		/* The type doesn't correspond to any denoising pass. */
+		return false;
+
+	float scale = 1.0f;
+	int type_offset = 0;
+	switch(type) {
+		case (1 << 0): break;
+		case (1 << 1): type_offset =  3; break;
+		case (1 << 2): type_offset =  6; break;
+		case (1 << 3): type_offset =  9; break;
+		case (1 << 4): type_offset = 12; break;
+		case (1 << 5): type_offset = 13; break;
+		case (1 << 6): type_offset = 14; scale = exposure; break;
+		case (1 << 7): type_offset = 17; scale = exposure*exposure; break;
+		case (1 << 8): type_offset = 20; scale = exposure/sample; break;
+	}
+
+	int pass_offset = params.get_denoise_offset() + type_offset;
+
+	float *in = (float*)buffer.data_pointer + pass_offset;
+	int pass_stride = params.get_passes_size();
+
+	int size = params.width*params.height;
+
+	if(components == 1) {
+		assert(type & 0b110000);
+		for(int i = 0; i < size; i++, in += pass_stride)
+			pixels[i] = *in;
+	}
+	else {
+		assert(components == 3);
+		assert(!(type & 0b110000));
+
+		for(int i = 0; i <

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list