[Bf-blender-cvs] [fe22264] master: Cycles Volume Render: add volume emission support.

Brecht Van Lommel noreply at git.blender.org
Sat Dec 28 23:22:22 CET 2013


Commit: fe222643b4a53fae38bc5ead86551b99abbdc583
Author: Brecht Van Lommel
Date:   Sat Dec 28 23:00:51 2013 +0100
https://developer.blender.org/rBfe222643b4a53fae38bc5ead86551b99abbdc583

Cycles Volume Render: add volume emission support.

This is done using the existing Emission node and closure (we may add a volume
emission node, not clear yet if it will be needed).

Volume emission only supports indirect light sampling which means it's not very
efficient to make small or far away bright light sources. Using direct light
sampling and MIS would be tricky and probably won't be added anytime soon. Other
renderers don't support this either as far as I know, lamps and ray visibility
tricks may be used instead.

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

M	intern/cycles/kernel/closure/volume.h
M	intern/cycles/kernel/kernel_path.h
M	intern/cycles/kernel/kernel_shader.h
M	intern/cycles/kernel/kernel_shadow.h
M	intern/cycles/kernel/kernel_volume.h

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

diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h
index dae24fb..4cf918f 100644
--- a/intern/cycles/kernel/closure/volume.h
+++ b/intern/cycles/kernel/closure/volume.h
@@ -39,7 +39,7 @@ ccl_device int volume_henyey_greenstein_setup(ShaderClosure *sc)
 	/* clamp anisotropy to avoid delta function */
 	sc->data0 = signf(sc->data0) * min(fabsf(sc->data0), 1.0f - 1e-3f);
 
-	return SD_BSDF|SD_BSDF_HAS_EVAL;
+	return SD_BSDF|SD_BSDF_HAS_EVAL|SD_VOLUME;
 }
 
 ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf)
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index b703970..7aea673 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -96,7 +96,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
 		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);
+			kernel_volume_integrate(kg, &state, &segment_ray, L, &throughput);
 		}
 #endif
 
@@ -518,7 +518,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
 		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);
+			kernel_volume_integrate(kg, &state, &segment_ray, &L, &throughput);
 		}
 #endif
 
@@ -1022,7 +1022,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
 		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);
+			kernel_volume_integrate(kg, &state, &segment_ray, &L, &throughput);
 		}
 #endif
 
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 685143b..7b9a4ab 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -412,15 +412,15 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
 
 /* ShaderData setup from point inside volume */
 
-ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int volume_shader, int bounce)
+ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int bounce)
 {
 	/* vectors */
 	sd->P = ray->P;
 	sd->N = -ray->D;  
 	sd->Ng = -ray->D;
 	sd->I = -ray->D;
-	sd->shader = volume_shader;
-	sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+	sd->shader = SHADER_NO_ID;
+	sd->flag = 0;
 #ifdef __OBJECT_MOTION__
 	sd->time = ray->time;
 #endif
@@ -992,6 +992,7 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
 #else
 	sd->closure.type = NBUILTIN_CLOSURES;
 #endif
+	sd->flag = 0;
 
 	for(int i = 0; stack[i].shader != SHADER_NO_ID; i++) {
 		/* setup shaderdata from stack. it's mostly setup already in
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 80c9da8..4bf063e 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -74,7 +74,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
 #ifdef __VOLUME__
 					/* attenuation for last line segment towards light */
 					if(ps.volume_stack[0].shader != SHADER_NO_ID)
-						throughput *= kernel_volume_get_shadow_attenuation(kg, &ps, ray);
+						kernel_volume_get_shadow_attenuation(kg, &ps, ray, &throughput);
 #endif
 
 					*shadow *= throughput;
@@ -89,7 +89,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
 				if(ps.volume_stack[0].shader != SHADER_NO_ID) {
 					Ray segment_ray = *ray;
 					segment_ray.t = isect.t;
-					throughput *= kernel_volume_get_shadow_attenuation(kg, &ps, &segment_ray);
+					kernel_volume_get_shadow_attenuation(kg, &ps, &segment_ray, &throughput);
 				}
 #endif
 
@@ -120,7 +120,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
 #ifdef __VOLUME__
 	else if(!result && state->volume_stack[0].shader != SHADER_NO_ID) {
 		/* apply attenuation from current volume shader */
-		*shadow *= kernel_volume_get_shadow_attenuation(kg, state, ray);
+		kernel_volume_get_shadow_attenuation(kg, state, ray, shadow);
 	}
 #endif
 #endif
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index fa201e1..6b198ed 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -21,8 +21,21 @@ CCL_NAMESPACE_BEGIN
  * extinction coefficient = absorption coefficient + scattering coefficient
  * sigma_t = sigma_a + sigma_s */
 
-ccl_device float3 volume_shader_get_extinction_coefficient(ShaderData *sd)
+typedef struct VolumeShaderSample {
+	float3 sigma_a;
+	float3 sigma_s;
+	float3 emission;
+} VolumeShaderSample;
+
+/* evaluate shader to get extinction coefficient at P */
+ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack, int path_flag, ShaderContext ctx, float3 P, float3 *extinction)
 {
+	sd->P = P;
+	shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx);
+
+	if(!(sd->flag & SD_VOLUME))
+		return false;
+
 	float3 sigma_t = make_float3(0.0f, 0.0f, 0.0f);
 
 	for(int i = 0; i < sd->num_closure; i++) {
@@ -32,45 +45,35 @@ ccl_device float3 volume_shader_get_extinction_coefficient(ShaderData *sd)
 			sigma_t += sc->weight;
 	}
 
-	return sigma_t;
+	*extinction = sigma_t;
+	return true;
 }
 
-ccl_device float3 volume_shader_get_scattering_coefficient(ShaderData *sd)
+/* evaluate shader to get absorption, scattering and emission at P */
+ccl_device bool volume_shader_sample(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack, int path_flag, ShaderContext ctx, float3 P, VolumeShaderSample *sample)
 {
-	float3 sigma_s = make_float3(0.0f, 0.0f, 0.0f);
-
-	for(int i = 0; i < sd->num_closure; i++) {
-		const ShaderClosure *sc = &sd->closure[i];
-
-		if(CLOSURE_IS_VOLUME(sc->type) && sc->type != CLOSURE_VOLUME_ABSORPTION_ID)
-			sigma_s += sc->weight;
-	}
+	sd->P = P;
+	shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx);
 
-	return sigma_s;
-}
+	if(!(sd->flag & (SD_VOLUME|SD_EMISSION)))
+		return false;
 
-ccl_device float3 volume_shader_get_absorption_coefficient(ShaderData *sd)
-{
-	float3 sigma_a = make_float3(0.0f, 0.0f, 0.0f);
+	sample->sigma_a = make_float3(0.0f, 0.0f, 0.0f);
+	sample->sigma_s = make_float3(0.0f, 0.0f, 0.0f);
+	sample->emission = make_float3(0.0f, 0.0f, 0.0f);
 
 	for(int i = 0; i < sd->num_closure; i++) {
 		const ShaderClosure *sc = &sd->closure[i];
 
 		if(sc->type == CLOSURE_VOLUME_ABSORPTION_ID)
-			sigma_a += sc->weight;
+			sample->sigma_a += sc->weight;
+		else if(sc->type == CLOSURE_EMISSION_ID)
+			sample->emission += sc->weight;
+		else if(CLOSURE_IS_VOLUME(sc->type))
+			sample->sigma_s += sc->weight;
 	}
 
-	return sigma_a;
-}
-
-/* evaluate shader to get extinction coefficient at P */
-ccl_device float3 volume_extinction_sample(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack, int path_flag, ShaderContext ctx, float3 P)
-{
-	sd->P = P;
-
-	shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx);
-
-	return volume_shader_get_extinction_coefficient(sd);
+	return true;
 }
 
 ccl_device float3 volume_color_attenuation(float3 sigma, float t)
@@ -81,32 +84,76 @@ ccl_device float3 volume_color_attenuation(float3 sigma, float t)
 /* Volumetric Shadows */
 
 /* get the volume attenuation over line segment defined by segment_ray, with the
- * assumption that there are surfaces blocking light between the endpoints */
-ccl_device float3 kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathState *state, Ray *segment_ray)
+ * assumption that there are no surfaces blocking light between the endpoints */
+ccl_device void kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathState *state, Ray *segment_ray, float3 *throughput)
 {
 	ShaderData sd;
-	shader_setup_from_volume(kg, &sd, segment_ray, state->volume_stack[0].shader, state->bounce);
-
-	/* do we have a volume shader? */
-	if(!(sd.flag & SD_HAS_VOLUME))
-		return make_float3(1.0f, 1.0f, 1.0f);
+	shader_setup_from_volume(kg, &sd, segment_ray, state->bounce);
 
-	/* single shader evaluation at the start */
 	ShaderContext ctx = SHADER_CONTEXT_SHADOW;
 	int path_flag = PATH_RAY_SHADOW;
-	float3 attenuation;
+	float3 sigma_t;
+
+	/* homogenous volume: assume shader evaluation at the starts gives
+	 * the extinction coefficient for the entire line segment */
+	if(!volume_shader_extinction_sample(kg, &sd, state->volume_stack, path_flag, ctx, segment_ray->P, &sigma_t))
+		return;
+
+	*throughput *= volume_color_attenuation(sigma_t, segment_ray->t);
+}
+
+/* Volumetric Path */
+
+/* get the volume attenuation and emission over line segment defined by
+ * segment_ray, with the assumption that there are no surfaces blocking light
+ * between the endpoints */
+ccl_device void kernel_volume_integrate(KernelGlobals *kg, PathState *state, Ray *segment_ray, PathRadiance *L, float3 *throughput)
+{
+	ShaderData sd;
+	shader_setup_from_volume(kg, &sd, segment_ray, state->bounce);
+
+	ShaderContext ctx = SHADER_CONTEXT_VOLUME;
+	int path_flag = PATH_RAY_SHADOW;
+	VolumeShaderSample sample;
+
+	/* homogenous volume: assume shader evaluation at the starts gives
+	 * the extinction coefficient for the entire line segment */
+	if(!volume_shader_sample(kg, &sd, state->volume_stack, path_flag, ctx, segment_ray->P, &sample))
+		return;
+	
+	int closure_flag = sd.flag;
+	float t = segment_ray->t;
 
-	//if(sd.flag & SD_HOMOGENEOUS_VOLUME) {
-		/* homogenous volume: assume shader evaluation at the starts gives
-		 * the extinction coefficient for the entire line segment */
+	/* compute attenuation from absorption (+ scattering for now) */
+	float3 sigma_t, attenuation;
 
-		/* todo: could this use sigma_t_cache? */
-		float3 sigma_t = volume_extinction_sample(kg, &sd, state->volume

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list