<div dir="ltr">Maybe this can be seen as a boolean operation (boolean volume node?) in which we can decide if two volumes add, subtract or merge densities</div><div class="gmail_extra"><br clear="all"><div>Daniel Salazar<br>

<a href="http://patazstudio.com" target="_blank">patazstudio.com</a></div>
<br><br><div class="gmail_quote">On Sat, Dec 28, 2013 at 1:13 PM, Brecht Van Lommel <span dir="ltr"><<a href="mailto:noreply@git.blender.org" target="_blank">noreply@git.blender.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

Commit: 2b39214c4d8811b06545b83c4e42a7578266e2b1<br>
Author: Brecht Van Lommel<br>
Date:   Sat Dec 28 20:02:40 2013 +0100<br>
<a href="https://developer.blender.org/rB2b39214c4d8811b06545b83c4e42a7578266e2b1" target="_blank">https://developer.blender.org/rB2b39214c4d8811b06545b83c4e42a7578266e2b1</a><br>
<br>
Cycles Volume Render: add support for overlapping volume objects.<br>
<br>
This works pretty much as you would expect, overlapping volume objects gives<br>
a more dense volume. What did change is that world volume shaders are now<br>
active everywhere, they are no longer excluded inside objects.<br>
<br>
This may not be desirable and we need to think of better control over this.<br>
In some cases you clearly want it to happen, for example if you are rendering<br>
a fire in a foggy environment. In other cases like the inside of a house you<br>
may not want any fog, but it doesn't seem possible in general for the renderer<br>
to automatically determine what is inside or outside of the house.<br>
<br>
This is implemented using a simple fixed size array of shader/object ID pairs,<br>
limited to max 15 overlapping objects. The closures from all shaders are put<br>
into a single closure array, exactly the same as if an add shader was used to<br>
combine them.<br>
<br>
===================================================================<br>
<br>
M       intern/cycles/kernel/kernel_path.h<br>
M       intern/cycles/kernel/kernel_path_state.h<br>
M       intern/cycles/kernel/kernel_shader.h<br>
M       intern/cycles/kernel/kernel_shadow.h<br>
M       intern/cycles/kernel/kernel_types.h<br>
M       intern/cycles/kernel/kernel_volume.h<br>
M       intern/cycles/kernel/osl/osl_shader.cpp<br>
M       intern/cycles/kernel/osl/osl_shader.h<br>
M       intern/cycles/kernel/svm/svm.h<br>
<br>
===================================================================<br>
<br>
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h<br>
index d318a85..b703970 100644<br>
--- a/intern/cycles/kernel/kernel_path.h<br>
+++ b/intern/cycles/kernel/kernel_path.h<br>
@@ -34,7 +34,6 @@<br>
 #include "kernel_light.h"<br>
 #include "kernel_emission.h"<br>
 #include "kernel_passes.h"<br>
-#include "kernel_path_state.h"<br>
<br>
 #ifdef __SUBSURFACE__<br>
 #include "kernel_subsurface.h"<br>
@@ -44,6 +43,7 @@<br>
 #include "kernel_volume.h"<br>
 #endif<br>
<br>
+#include "kernel_path_state.h"<br>
 #include "kernel_shadow.h"<br>
<br>
 CCL_NAMESPACE_BEGIN<br>
@@ -93,10 +93,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra<br>
<br>
 #ifdef __VOLUME__<br>
                /* volume attenuation */<br>
-               if(state.volume_shader != SHADER_NO_ID) {<br>
+               if(state.volume_stack[0].shader != SHADER_NO_ID) {<br>
                        Ray segment_ray = ray;<br>
                        segment_ray.t = (hit)? isect.t: FLT_MAX;<br>
-                       throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);<br>
+                       throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);<br>
                }<br>
 #endif<br>
<br>
@@ -116,7 +116,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra<br>
                float rbsdf = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF);<br>
                shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT);<br>
 #ifdef __BRANCHED_PATH__<br>
-               shader_merge_closures(kg, &sd);<br>
+               shader_merge_closures(&sd);<br>
 #endif<br>
<br>
                /* blurring of bsdf after bounces, for rays that have a small likelihood<br>
@@ -291,7 +291,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra<br>
 #ifdef __VOLUME__<br>
                        /* enter/exit volume */<br>
                        if(label & LABEL_TRANSMIT)<br>
-                               kernel_volume_enter_exit(kg, &sd, &state.volume_shader);<br>
+                               kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);<br>
 #endif<br>
                }<br>
 #ifdef __VOLUME__<br>
@@ -308,7 +308,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra<br>
 #endif<br>
<br>
                        /* enter/exit volume */<br>
-                       kernel_volume_enter_exit(kg, &sd, &state.volume_shader);<br>
+                       kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);<br>
                }<br>
 #endif<br>
                else {<br>
@@ -411,7 +411,7 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn<br>
 #ifdef __VOLUME__<br>
                /* enter/exit volume */<br>
                if(label & LABEL_TRANSMIT)<br>
-                       kernel_volume_enter_exit(kg, sd, &state->volume_shader);<br>
+                       kernel_volume_stack_enter_exit(kg, sd, state->volume_stack);<br>
 #endif<br>
                return true;<br>
        }<br>
@@ -429,7 +429,7 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn<br>
 #endif<br>
<br>
                /* enter/exit volume */<br>
-               kernel_volume_enter_exit(kg, sd, &state->volume_shader);<br>
+               kernel_volume_stack_enter_exit(kg, sd, state->volume_stack);<br>
                return true;<br>
        }<br>
 #endif<br>
@@ -515,10 +515,10 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,<br>
<br>
 #ifdef __VOLUME__<br>
                /* volume attenuation */<br>
-               if(state.volume_shader != SHADER_NO_ID) {<br>
+               if(state.volume_stack[0].shader != SHADER_NO_ID) {<br>
                        Ray segment_ray = ray;<br>
                        segment_ray.t = (hit)? isect.t: FLT_MAX;<br>
-                       throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);<br>
+                       throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);<br>
                }<br>
 #endif<br>
<br>
@@ -769,7 +769,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,<br>
 #ifdef __VOLUME__<br>
                        /* enter/exit volume */<br>
                        if(label & LABEL_TRANSMIT)<br>
-                               kernel_volume_enter_exit(kg, &sd, &state.volume_shader);<br>
+                               kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);<br>
 #endif<br>
<br>
                }<br>
@@ -787,7 +787,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,<br>
 #endif<br>
<br>
                        /* enter/exit volume */<br>
-                       kernel_volume_enter_exit(kg, &sd, &state.volume_shader);<br>
+                       kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);<br>
                }<br>
 #endif<br>
                else {<br>
@@ -957,7 +957,7 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *<br>
 #ifdef __VOLUME__<br>
                        /* enter/exit volume */<br>
                        if(label & LABEL_TRANSMIT)<br>
-                               kernel_volume_enter_exit(kg, sd, &ps.volume_shader);<br>
+                               kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack);<br>
 #endif<br>
<br>
                        kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,<br>
@@ -1019,10 +1019,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in<br>
<br>
 #ifdef __VOLUME__<br>
                /* volume attenuation */<br>
-               if(state.volume_shader != SHADER_NO_ID) {<br>
+               if(state.volume_stack[0].shader != SHADER_NO_ID) {<br>
                        Ray segment_ray = ray;<br>
                        segment_ray.t = (hit)? isect.t: FLT_MAX;<br>
-                       throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);<br>
+                       throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);<br>
                }<br>
 #endif<br>
<br>
@@ -1050,7 +1050,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in<br>
                ShaderData sd;<br>
                shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);<br>
                shader_eval_surface(kg, &sd, 0.0f, state.flag, SHADER_CONTEXT_MAIN);<br>
-               shader_merge_closures(kg, &sd);<br>
+               shader_merge_closures(&sd);<br>
<br>
                /* holdout */<br>
 #ifdef __HOLDOUT__<br>
@@ -1198,7 +1198,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in<br>
<br>
 #ifdef __VOLUME__<br>
                /* enter/exit volume */<br>
-               kernel_volume_enter_exit(kg, &sd, &state.volume_shader);<br>
+               kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);<br>
 #endif<br>
        }<br>
<br>
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h<br>
index 2df8f56..afca28f 100644<br>
--- a/intern/cycles/kernel/kernel_path_state.h<br>
+++ b/intern/cycles/kernel/kernel_path_state.h<br>
@@ -16,20 +16,6 @@<br>
<br>
 CCL_NAMESPACE_BEGIN<br>
<br>
-typedef struct PathState {<br>
-       int flag;<br>
-       int bounce;<br>
-<br>
-       int diffuse_bounce;<br>
-       int glossy_bounce;<br>
-       int transmission_bounce;<br>
-       int transparent_bounce;<br>
-<br>
-#ifdef __VOLUME__<br>
-       int volume_shader;<br>
-#endif<br>
-} PathState;<br>
-<br>
 ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state)<br>
 {<br>
        state->flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP;<br>
@@ -40,8 +26,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state)<br>
        state->transparent_bounce = 0;<br>
<br>
 #ifdef __VOLUME__<br>
-       /* todo: this assumes camera is always in air, need to detect when it isn't */<br>
-       state->volume_shader = kernel_data.background.volume_shader;<br>
+       kernel_volume_stack_init(kg, state->volume_stack);<br>
 #endif<br>
 }<br>
<br>
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h<br>
index a2f4e0a..685143b 100644<br>
--- a/intern/cycles/kernel/kernel_shader.h<br>
+++ b/intern/cycles/kernel/kernel_shader.h<br>
@@ -459,6 +459,41 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s<br>
        sd->ray_dP = ray->dP;<br>
 }<br>
<br>
+/* Merging */<br>
+<br>
+#if defined(__BRANCHED_PATH__) || defined(__VOLUME__)<br>
+ccl_device void shader_merge_closures(ShaderData *sd)<br>
+{<br>
+       /* merge identical closures, better when we sample a single closure at a time */<br>
+       for(int i = 0; i < sd->num_closure; i++) {<br>
+               ShaderClosure *sci = &sd->closure[i];<br>
+<br>
+               for(int j = i + 1; j < sd->num_closure; j++) {<br>
+                       ShaderClosure *scj = &sd->closure[j];<br>
+<br>
+#ifdef __OSL__<br>
+                       if(!sci->prim && !scj->prim && sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {<br>
+#else<br>
+                       if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {<br>
+#endif<br>
+                               sci->weight += scj->weight;<br>
+                               sci->sample_weight += scj->sample_weight;<br>
+<br>
+                               int size = sd->num_closure - (j+1);<br>
+                               if(size > 0) {<br>
+                                       for(int k = 0; k < size; k++) {<br>
+                                               scj[k] = scj[k+1];<br>
+                                       }<br>
+                               }<br>
+<br>
+                               sd->num_closure--;<br>
+                               j--;<br>
+                       }<br>
+               }<br>
+       }<br>
+}<br>
+#endif<br>
+<br>
 /* BSDF */<br>
<br>
 #ifdef __MULTI_CLOSURE__<br>
@@ -851,9 +886,16 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)<br>
 ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,<br>
        float randb, int path_flag, ShaderContext ctx)<br>
 {<br>
+#ifdef __MULTI_CLOSURE__<br>
+       sd->num_closure = 0;<br>
+       sd->randb_closure = randb;<br>
+#else<br>
+       sd->closure.type = NBUILTIN_CLOSURES;<br>
+#endif<br>
+<br>
 #ifdef __OSL__<br>
-       if (kg->osl)<br>
-               OSLShader::eval_surface(kg, sd, randb, path_flag, ctx);<br>
+       if(kg->osl)<br>
+               OSLShader::eval_surface(kg, sd, path_flag, ctx);<br>
        else<br>
 #endif<br>
        {<br>
@@ -871,9 +913,17 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,<br>
<br>
 ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)<br>
 {<br>
+#ifdef __MULTI_CLOSURE__<br>
+       sd->num_closure = 0;<br>
+       sd->randb_closure = 0.0f;<br>
+#else<br>
+       sd->closure.type = NBUILTIN_CLOSURES;<br>
+#endif<br>
+<br>
 #ifdef __OSL__<br>
-       if (kg->osl)<br>
+       if(kg->osl) {<br>
                return OSLShader::eval_background(kg, sd, path_flag, ctx);<br>
+       }<br>
        else<br>
 #endif<br>
<br>
@@ -907,6 +957,7 @@ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int<br>
<br>
 /* Volume */<br>
<br>
+#ifdef __VOLUME__<br>
 ccl_device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,<br>
        float3 omega_in, float3 omega_out)<br>
 {<br>
@@ -931,30 +982,77 @@ ccl_device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,<br>
 /* Volume Evaluation */<br>
<br>
 ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,<br>
-       float randb, int path_flag, ShaderContext ctx)<br>
+       VolumeStack *stack, float randb, int path_flag, ShaderContext ctx)<br>
 {<br>
+       /* reset closures once at the start, we will be accumulating the closures<br>
+        * for all volumes in the stack into a single array of closures */<br>
+#ifdef __MULTI_CLOSURE__<br>
+       sd->num_closure = 0;<br>
+       sd->randb_closure = randb;<br>
+#else<br>
+       sd->closure.type = NBUILTIN_CLOSURES;<br>
+#endif<br>
+<br>
+       for(int i = 0; stack[i].shader != SHADER_NO_ID; i++) {<br>
+               /* setup shaderdata from stack. it's mostly setup already in<br>
+                * shader_setup_from_volume, this switching should be quick */<br>
+               sd->object = stack[i].object;<br>
+               sd->shader = stack[i].shader;<br>
+<br>
+               sd->flag &= ~(SD_SHADER_FLAGS|SD_OBJECT_FLAGS);<br>
+               sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);<br>
+<br>
+               if(sd->object != ~0) {<br>
+                       sd->flag |= kernel_tex_fetch(__object_flag, sd->object);<br>
+<br>
+#ifdef __OBJECT_MOTION__<br>
+                       /* todo: this is inefficient for motion blur, we should be<br>
+                        * caching matrices instead of recomputing them each step */<br>
+                       shader_setup_object_transforms(k<br>
<br>
@@ Diff output truncated at 10240 characters. @@<br>
<br>
_______________________________________________<br>
Bf-blender-cvs mailing list<br>
<a href="mailto:Bf-blender-cvs@blender.org">Bf-blender-cvs@blender.org</a><br>
<a href="http://lists.blender.org/mailman/listinfo/bf-blender-cvs" target="_blank">http://lists.blender.org/mailman/listinfo/bf-blender-cvs</a><br>
</blockquote></div><br></div>