[Bf-blender-cvs] [2b39214] master: Cycles Volume Render: add support for overlapping volume objects.

Brecht Van Lommel noreply at git.blender.org
Sat Dec 28 20:13:35 CET 2013


Commit: 2b39214c4d8811b06545b83c4e42a7578266e2b1
Author: Brecht Van Lommel
Date:   Sat Dec 28 20:02:40 2013 +0100
https://developer.blender.org/rB2b39214c4d8811b06545b83c4e42a7578266e2b1

Cycles Volume Render: add support for overlapping volume objects.

This works pretty much as you would expect, overlapping volume objects gives
a more dense volume. What did change is that world volume shaders are now
active everywhere, they are no longer excluded inside objects.

This may not be desirable and we need to think of better control over this.
In some cases you clearly want it to happen, for example if you are rendering
a fire in a foggy environment. In other cases like the inside of a house you
may not want any fog, but it doesn't seem possible in general for the renderer
to automatically determine what is inside or outside of the house.

This is implemented using a simple fixed size array of shader/object ID pairs,
limited to max 15 overlapping objects. The closures from all shaders are put
into a single closure array, exactly the same as if an add shader was used to
combine them.

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

M	intern/cycles/kernel/kernel_path.h
M	intern/cycles/kernel/kernel_path_state.h
M	intern/cycles/kernel/kernel_shader.h
M	intern/cycles/kernel/kernel_shadow.h
M	intern/cycles/kernel/kernel_types.h
M	intern/cycles/kernel/kernel_volume.h
M	intern/cycles/kernel/osl/osl_shader.cpp
M	intern/cycles/kernel/osl/osl_shader.h
M	intern/cycles/kernel/svm/svm.h

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

diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index d318a85..b703970 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -34,7 +34,6 @@
 #include "kernel_light.h"
 #include "kernel_emission.h"
 #include "kernel_passes.h"
-#include "kernel_path_state.h"
 
 #ifdef __SUBSURFACE__
 #include "kernel_subsurface.h"
@@ -44,6 +43,7 @@
 #include "kernel_volume.h"
 #endif
 
+#include "kernel_path_state.h"
 #include "kernel_shadow.h"
 
 CCL_NAMESPACE_BEGIN
@@ -93,10 +93,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
 
 #ifdef __VOLUME__
 		/* volume attenuation */
-		if(state.volume_shader != SHADER_NO_ID) {
+		if(state.volume_stack[0].shader != SHADER_NO_ID) {
 			Ray segment_ray = ray;
 			segment_ray.t = (hit)? isect.t: FLT_MAX;
-			throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
+			throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);
 		}
 #endif
 
@@ -116,7 +116,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
 		float rbsdf = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF);
 		shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT);
 #ifdef __BRANCHED_PATH__
-		shader_merge_closures(kg, &sd);
+		shader_merge_closures(&sd);
 #endif
 
 		/* blurring of bsdf after bounces, for rays that have a small likelihood
@@ -291,7 +291,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
 #ifdef __VOLUME__
 			/* enter/exit volume */
 			if(label & LABEL_TRANSMIT)
-				kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+				kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
 #endif
 		}
 #ifdef __VOLUME__
@@ -308,7 +308,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
 #endif
 
 			/* enter/exit volume */
-			kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+			kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
 		}
 #endif
 		else {
@@ -411,7 +411,7 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn
 #ifdef __VOLUME__
 		/* enter/exit volume */
 		if(label & LABEL_TRANSMIT)
-			kernel_volume_enter_exit(kg, sd, &state->volume_shader);
+			kernel_volume_stack_enter_exit(kg, sd, state->volume_stack);
 #endif
 		return true;
 	}
@@ -429,7 +429,7 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn
 #endif
 
 		/* enter/exit volume */
-		kernel_volume_enter_exit(kg, sd, &state->volume_shader);
+		kernel_volume_stack_enter_exit(kg, sd, state->volume_stack);
 		return true;
 	}
 #endif
@@ -515,10 +515,10 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
 
 #ifdef __VOLUME__
 		/* volume attenuation */
-		if(state.volume_shader != SHADER_NO_ID) {
+		if(state.volume_stack[0].shader != SHADER_NO_ID) {
 			Ray segment_ray = ray;
 			segment_ray.t = (hit)? isect.t: FLT_MAX;
-			throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
+			throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);
 		}
 #endif
 
@@ -769,7 +769,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
 #ifdef __VOLUME__
 			/* enter/exit volume */
 			if(label & LABEL_TRANSMIT)
-				kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+				kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
 #endif
 
 		}
@@ -787,7 +787,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
 #endif
 
 			/* enter/exit volume */
-			kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+			kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
 		}
 #endif
 		else {
@@ -957,7 +957,7 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *
 #ifdef __VOLUME__
 			/* enter/exit volume */
 			if(label & LABEL_TRANSMIT)
-				kernel_volume_enter_exit(kg, sd, &ps.volume_shader);
+				kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack);
 #endif
 
 			kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
@@ -1019,10 +1019,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
 
 #ifdef __VOLUME__
 		/* volume attenuation */
-		if(state.volume_shader != SHADER_NO_ID) {
+		if(state.volume_stack[0].shader != SHADER_NO_ID) {
 			Ray segment_ray = ray;
 			segment_ray.t = (hit)? isect.t: FLT_MAX;
-			throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
+			throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);
 		}
 #endif
 
@@ -1050,7 +1050,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
 		ShaderData sd;
 		shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
 		shader_eval_surface(kg, &sd, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
-		shader_merge_closures(kg, &sd);
+		shader_merge_closures(&sd);
 
 		/* holdout */
 #ifdef __HOLDOUT__
@@ -1198,7 +1198,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
 
 #ifdef __VOLUME__
 		/* enter/exit volume */
-		kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+		kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
 #endif
 	}
 
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
index 2df8f56..afca28f 100644
--- a/intern/cycles/kernel/kernel_path_state.h
+++ b/intern/cycles/kernel/kernel_path_state.h
@@ -16,20 +16,6 @@
 
 CCL_NAMESPACE_BEGIN
 
-typedef struct PathState {
-	int flag;
-	int bounce;
-
-	int diffuse_bounce;
-	int glossy_bounce;
-	int transmission_bounce;
-	int transparent_bounce;
-
-#ifdef __VOLUME__
-	int volume_shader;
-#endif
-} PathState;
-
 ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state)
 {
 	state->flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP;
@@ -40,8 +26,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state)
 	state->transparent_bounce = 0;
 
 #ifdef __VOLUME__
-	/* todo: this assumes camera is always in air, need to detect when it isn't */
-	state->volume_shader = kernel_data.background.volume_shader;
+	kernel_volume_stack_init(kg, state->volume_stack);
 #endif
 }
 
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index a2f4e0a..685143b 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -459,6 +459,41 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
 	sd->ray_dP = ray->dP;
 }
 
+/* Merging */
+
+#if defined(__BRANCHED_PATH__) || defined(__VOLUME__)
+ccl_device void shader_merge_closures(ShaderData *sd)
+{
+	/* merge identical closures, better when we sample a single closure at a time */
+	for(int i = 0; i < sd->num_closure; i++) {
+		ShaderClosure *sci = &sd->closure[i];
+
+		for(int j = i + 1; j < sd->num_closure; j++) {
+			ShaderClosure *scj = &sd->closure[j];
+
+#ifdef __OSL__
+			if(!sci->prim && !scj->prim && sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
+#else
+			if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
+#endif
+				sci->weight += scj->weight;
+				sci->sample_weight += scj->sample_weight;
+
+				int size = sd->num_closure - (j+1);
+				if(size > 0) {
+					for(int k = 0; k < size; k++) {
+						scj[k] = scj[k+1];
+					}
+				}
+
+				sd->num_closure--;
+				j--;
+			}
+		}
+	}
+}
+#endif
+
 /* BSDF */
 
 #ifdef __MULTI_CLOSURE__
@@ -851,9 +886,16 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
 ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
 	float randb, int path_flag, ShaderContext ctx)
 {
+#ifdef __MULTI_CLOSURE__
+	sd->num_closure = 0;
+	sd->randb_closure = randb;
+#else
+	sd->closure.type = NBUILTIN_CLOSURES;
+#endif
+
 #ifdef __OSL__
-	if (kg->osl)
-		OSLShader::eval_surface(kg, sd, randb, path_flag, ctx);
+	if(kg->osl)
+		OSLShader::eval_surface(kg, sd, path_flag, ctx);
 	else
 #endif
 	{
@@ -871,9 +913,17 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
 
 ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
 {
+#ifdef __MULTI_CLOSURE__
+	sd->num_closure = 0;
+	sd->randb_closure = 0.0f;
+#else
+	sd->closure.type = NBUILTIN_CLOSURES;
+#endif
+
 #ifdef __OSL__
-	if (kg->osl)
+	if(kg->osl) {
 		return OSLShader::eval_background(kg, sd, path_flag, ctx);
+	}
 	else
 #endif
 
@@ -907,6 +957,7 @@ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int
 
 /* Volume */
 
+#ifdef __VOLUME__
 ccl_device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
 	float3 omega_in, float3 omega_out)
 {
@@ -931,30 +982,77 @@ ccl_device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
 /* Volume Evaluation */
 
 ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
-	float randb, int path_flag, ShaderContext ctx)
+	VolumeStack *stack, float randb, int path_flag, ShaderContext ctx)
 {
+	/* reset closures once at the start, we will be accumulating the closures
+	 * for all volumes in the stack into a single array of closures */
+#ifdef __MULTI_CLOSURE__
+	sd->num_closure = 0;
+	sd->randb_closure = randb;
+#else
+	sd->closure.type = NBUILTIN_CLOSURES;
+#endif
+
+	for(int i = 0; stack[i].shader != SHADER_NO_ID; i++) {
+		/* setup shaderdata from stack. it's mostly setup already in
+		 * shader_setup_from_volume, this switching should be quick */
+		sd->object = stack[i].object;
+		sd->shader = stack[i].shader;
+
+		sd->flag &= ~(SD_SHADER_FLAGS|SD_OBJECT_FLAGS);
+		sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+
+		if(sd->object != ~0) {
+			sd->flag |= kernel_tex_fetch(__object_flag, sd->object);
+
+#ifdef __OBJECT_MOTION__
+			/* todo: this is inefficient for motion blur, we should be
+			 * caching matrices instead of recomputing them each step */
+			shader_setup_object_transforms(k

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list