Cycles / SSS:
authorThomas Dinges <blender@dingto.org>
Sat, 3 Aug 2013 13:12:09 +0000 (13:12 +0000)
committerThomas Dinges <blender@dingto.org>
Sat, 3 Aug 2013 13:12:09 +0000 (13:12 +0000)
* Render Passes are now available for Subsurface Scattering (Direct, Indirect and Color pass).

This is part of my GSoC project, SVN merge of r58587, r58828 and r58835.

17 files changed:
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_session.cpp
intern/cycles/kernel/closure/bsdf.h
intern/cycles/kernel/kernel_accumulate.h
intern/cycles/kernel/kernel_passes.h
intern/cycles/kernel/kernel_path.h
intern/cycles/kernel/kernel_shader.h
intern/cycles/kernel/kernel_subsurface.h
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/film.cpp
source/blender/blenkernel/BKE_node.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_render.c
source/blender/makesrna/intern/rna_scene.c
source/blender/nodes/composite/nodes/node_composite_image.c
source/blender/render/intern/source/render_result.c

index 411bd5b..551a0f8 100644 (file)
@@ -373,7 +373,13 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
         row.prop(rl, "use_pass_transmission_direct", text="Direct", toggle=True)
         row.prop(rl, "use_pass_transmission_indirect", text="Indirect", toggle=True)
         row.prop(rl, "use_pass_transmission_color", text="Color", toggle=True)
-
+        col.label(text="Subsurface:")
+        row = col.row(align=True)
+        row.prop(rl, "use_pass_subsurface_direct", text="Direct", toggle=True)
+        row.prop(rl, "use_pass_subsurface_indirect", text="Indirect", toggle=True)
+        row.prop(rl, "use_pass_subsurface_color", text="Color", toggle=True)
+        
+        col.separator()
         col.prop(rl, "use_pass_emit", text="Emission")
         col.prop(rl, "use_pass_environment")
         col.prop(rl, "use_pass_ambient_occlusion")
index 3a46897..fb743ac 100644 (file)
@@ -216,6 +216,8 @@ static PassType get_pass_type(BL::RenderPass b_pass)
                        return PASS_GLOSSY_DIRECT;
                case BL::RenderPass::type_TRANSMISSION_DIRECT:
                        return PASS_TRANSMISSION_DIRECT;
+               case BL::RenderPass::type_SUBSURFACE_DIRECT:
+                       return PASS_SUBSURFACE_DIRECT;
 
                case BL::RenderPass::type_DIFFUSE_INDIRECT:
                        return PASS_DIFFUSE_INDIRECT;
@@ -223,6 +225,8 @@ static PassType get_pass_type(BL::RenderPass b_pass)
                        return PASS_GLOSSY_INDIRECT;
                case BL::RenderPass::type_TRANSMISSION_INDIRECT:
                        return PASS_TRANSMISSION_INDIRECT;
+               case BL::RenderPass::type_SUBSURFACE_INDIRECT:
+                       return PASS_SUBSURFACE_INDIRECT;
 
                case BL::RenderPass::type_DIFFUSE_COLOR:
                        return PASS_DIFFUSE_COLOR;
@@ -230,6 +234,8 @@ static PassType get_pass_type(BL::RenderPass b_pass)
                        return PASS_GLOSSY_COLOR;
                case BL::RenderPass::type_TRANSMISSION_COLOR:
                        return PASS_TRANSMISSION_COLOR;
+               case BL::RenderPass::type_SUBSURFACE_COLOR:
+                       return PASS_SUBSURFACE_COLOR;
 
                case BL::RenderPass::type_EMIT:
                        return PASS_EMISSION;
index b288495..5e7b845 100644 (file)
@@ -45,6 +45,7 @@ __device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderCl
 
        switch(sc->type) {
                case CLOSURE_BSDF_DIFFUSE_ID:
+               case CLOSURE_BSDF_BSSRDF_ID:
                        label = bsdf_diffuse_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
                                eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
                        break;
@@ -134,6 +135,7 @@ __device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderC
        if(dot(sd->Ng, omega_in) >= 0.0f) {
                switch(sc->type) {
                        case CLOSURE_BSDF_DIFFUSE_ID:
+                       case CLOSURE_BSDF_BSSRDF_ID:
                                eval = bsdf_diffuse_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
 #ifdef __SVM__
@@ -195,6 +197,7 @@ __device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderC
        else {
                switch(sc->type) {
                        case CLOSURE_BSDF_DIFFUSE_ID:
+                       case CLOSURE_BSDF_BSSRDF_ID:
                                eval = bsdf_diffuse_eval_transmit(sc, sd->I, omega_in, pdf);
                                break;
 #ifdef __SVM__
@@ -262,6 +265,7 @@ __device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
 
        switch(sc->type) {
                case CLOSURE_BSDF_DIFFUSE_ID:
+               case CLOSURE_BSDF_BSSRDF_ID:
                        bsdf_diffuse_blur(sc, roughness);
                        break;
 #ifdef __SVM__
index e6307f2..ca42090 100644 (file)
@@ -33,6 +33,7 @@ __device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 val
                eval->glossy = make_float3(0.0f, 0.0f, 0.0f);
                eval->transmission = make_float3(0.0f, 0.0f, 0.0f);
                eval->transparent = make_float3(0.0f, 0.0f, 0.0f);
+               eval->subsurface = make_float3(0.0f, 0.0f, 0.0f);
 
                if(type == CLOSURE_BSDF_TRANSPARENT_ID)
                        eval->transparent = value;
@@ -40,8 +41,10 @@ __device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 val
                        eval->diffuse = value;
                else if(CLOSURE_IS_BSDF_GLOSSY(type))
                        eval->glossy = value;
-               else
+               else if(CLOSURE_IS_BSDF_TRANSMISSION(type))
                        eval->transmission = value;
+               else if(CLOSURE_IS_BSDF_BSSRDF(type))
+                       eval->subsurface = value;
        }
        else
                eval->diffuse = value;
@@ -58,8 +61,10 @@ __device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 va
                        eval->diffuse += value;
                else if(CLOSURE_IS_BSDF_GLOSSY(type))
                        eval->glossy += value;
-               else
+               else if(CLOSURE_IS_BSDF_TRANSMISSION(type))
                        eval->transmission += value;
+               else if(CLOSURE_IS_BSDF_BSSRDF(type))
+                       eval->subsurface += value;
 
                /* skipping transparent, this function is used by for eval(), will be zero then */
        }
@@ -77,7 +82,8 @@ __device_inline bool bsdf_eval_is_zero(BsdfEval *eval)
                return is_zero(eval->diffuse)
                        && is_zero(eval->glossy)
                        && is_zero(eval->transmission)
-                       && is_zero(eval->transparent);
+                       && is_zero(eval->transparent)
+                       && is_zero(eval->subsurface);
        }
        else
                return is_zero(eval->diffuse);
@@ -93,6 +99,7 @@ __device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value)
                eval->diffuse *= value;
                eval->glossy *= value;
                eval->transmission *= value;
+               eval->subsurface *= value;
 
                /* skipping transparent, this function is used by for eval(), will be zero then */
        }
@@ -124,18 +131,22 @@ __device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
                L->color_diffuse = make_float3(0.0f, 0.0f, 0.0f);
                L->color_glossy = make_float3(0.0f, 0.0f, 0.0f);
                L->color_transmission = make_float3(0.0f, 0.0f, 0.0f);
+               L->color_subsurface = make_float3(0.0f, 0.0f, 0.0f);
 
                L->direct_diffuse = make_float3(0.0f, 0.0f, 0.0f);
                L->direct_glossy = make_float3(0.0f, 0.0f, 0.0f);
                L->direct_transmission = make_float3(0.0f, 0.0f, 0.0f);
+               L->direct_subsurface = make_float3(0.0f, 0.0f, 0.0f);
 
                L->indirect_diffuse = make_float3(0.0f, 0.0f, 0.0f);
                L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
                L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
+               L->indirect_subsurface = make_float3(0.0f, 0.0f, 0.0f);
 
                L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f);
                L->path_glossy = make_float3(0.0f, 0.0f, 0.0f);
                L->path_transmission = make_float3(0.0f, 0.0f, 0.0f);
+               L->path_subsurface = make_float3(0.0f, 0.0f, 0.0f);
 
                L->emission = make_float3(0.0f, 0.0f, 0.0f);
                L->background = make_float3(0.0f, 0.0f, 0.0f);
@@ -164,14 +175,15 @@ __device_inline void path_radiance_bsdf_bounce(PathRadiance *L, float3 *throughp
                        L->path_diffuse = bsdf_eval->diffuse*value;
                        L->path_glossy = bsdf_eval->glossy*value;
                        L->path_transmission = bsdf_eval->transmission*value;
+                       L->path_subsurface = bsdf_eval->subsurface*value;
 
-                       *throughput = L->path_diffuse + L->path_glossy + L->path_transmission;
+                       *throughput = L->path_diffuse + L->path_glossy + L->path_transmission + L->path_subsurface;
                        
                        L->direct_throughput = *throughput;
                }
                else {
                        /* transparent bounce before first hit, or indirectly visible through BSDF */
-                       float3 sum = (bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission + bsdf_eval->transparent)*inverse_pdf;
+                       float3 sum = (bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission + bsdf_eval->transparent + bsdf_eval->subsurface)*inverse_pdf;
                        *throughput *= sum;
                }
        }
@@ -230,6 +242,7 @@ __device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughpu
                        L->direct_diffuse += throughput*bsdf_eval->diffuse*shadow;
                        L->direct_glossy += throughput*bsdf_eval->glossy*shadow;
                        L->direct_transmission += throughput*bsdf_eval->transmission*shadow;
+                       L->direct_subsurface += throughput*bsdf_eval->subsurface*shadow;
 
                        if(is_lamp) {
                                L->shadow.x += shadow.x*shadow_fac;
@@ -239,7 +252,7 @@ __device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughpu
                }
                else {
                        /* indirectly visible lighting after BSDF bounce */
-                       float3 sum = bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission;
+                       float3 sum = bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission + bsdf_eval->subsurface;
                        L->indirect += throughput*sum*shadow;
                }
        }
@@ -279,11 +292,13 @@ __device_inline void path_radiance_sum_indirect(PathRadiance *L)
                L->direct_diffuse += L->path_diffuse*L->direct_emission;
                L->direct_glossy += L->path_glossy*L->direct_emission;
                L->direct_transmission += L->path_transmission*L->direct_emission;
+               L->direct_subsurface += L->path_subsurface*L->direct_emission;
 
                L->indirect = safe_divide_color(L->indirect, L->direct_throughput);
                L->indirect_diffuse += L->path_diffuse*L->indirect;
                L->indirect_glossy += L->path_glossy*L->indirect;
                L->indirect_transmission += L->path_transmission*L->indirect;
+               L->indirect_subsurface += L->path_subsurface*L->indirect;
        }
 #endif
 }
@@ -295,6 +310,7 @@ __device_inline void path_radiance_reset_indirect(PathRadiance *L)
                L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f);
                L->path_glossy = make_float3(0.0f, 0.0f, 0.0f);
                L->path_transmission = make_float3(0.0f, 0.0f, 0.0f);
+               L->path_subsurface = make_float3(0.0f, 0.0f, 0.0f);
 
                L->direct_emission = make_float3(0.0f, 0.0f, 0.0f);
                L->indirect = make_float3(0.0f, 0.0f, 0.0f);
@@ -309,8 +325,8 @@ __device_inline float3 path_radiance_sum(KernelGlobals *kg, PathRadiance *L)
                path_radiance_sum_indirect(L);
 
                float3 L_sum = L->emission
-                       + L->direct_diffuse + L->direct_glossy + L->direct_transmission
-                       + L->indirect_diffuse + L->indirect_glossy + L->indirect_transmission;
+                       + L->direct_diffuse + L->direct_glossy + L->direct_transmission + L->direct_subsurface
+                       + L->indirect_diffuse + L->indirect_glossy + L->indirect_transmission + L->indirect_subsurface;
 
                if(!kernel_data.background.transparent)
                        L_sum += L->background;
@@ -337,10 +353,12 @@ __device_inline void path_radiance_clamp(PathRadiance *L, float3 *L_sum, float c
                        L->direct_diffuse = make_float3(0.0f, 0.0f, 0.0f);
                        L->direct_glossy = make_float3(0.0f, 0.0f, 0.0f);
                        L->direct_transmission = make_float3(0.0f, 0.0f, 0.0f);
+                       L->direct_subsurface = make_float3(0.0f, 0.0f, 0.0f);
 
                        L->indirect_diffuse = make_float3(0.0f, 0.0f, 0.0f);
                        L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
                        L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
+                       L->indirect_subsurface = make_float3(0.0f, 0.0f, 0.0f);
 
                        L->emission = make_float3(0.0f, 0.0f, 0.0f);
                }
@@ -357,10 +375,12 @@ __device_inline void path_radiance_clamp(PathRadiance *L, float3 *L_sum, float c
                        L->direct_diffuse *= scale;
                        L->direct_glossy *= scale;
                        L->direct_transmission *= scale;
+                       L->direct_subsurface *= scale;
 
                        L->indirect_diffuse *= scale;
                        L->indirect_glossy *= scale;
                        L->indirect_transmission *= scale;
+                       L->indirect_subsurface *= scale;
 
                        L->emission *= scale;
                }
index f07e1b1..0b45e24 100644 (file)
@@ -86,6 +86,8 @@ __device_inline void kernel_write_data_passes(KernelGlobals *kg, __global float
                L->color_glossy += shader_bsdf_glossy(kg, sd)*throughput;
        if(flag & (PASS_TRANSMISSION_INDIRECT|PASS_TRANSMISSION_COLOR|PASS_TRANSMISSION_DIRECT))
                L->color_transmission += shader_bsdf_transmission(kg, sd)*throughput;
+       if(flag & (PASS_SUBSURFACE_INDIRECT|PASS_SUBSURFACE_COLOR|PASS_SUBSURFACE_DIRECT))
+               L->color_subsurface += shader_bsdf_subsurface(kg, sd)*throughput;
 
        if(flag & PASS_MIST) {
                /* bring depth into 0..1 range */
@@ -128,12 +130,16 @@ __device_inline void kernel_write_light_passes(KernelGlobals *kg, __global float
                kernel_write_pass_float3(buffer + kernel_data.film.pass_glossy_indirect, sample, L->indirect_glossy);
        if(flag & PASS_TRANSMISSION_INDIRECT)
                kernel_write_pass_float3(buffer + kernel_data.film.pass_transmission_indirect, sample, L->indirect_transmission);
+       if(flag & PASS_SUBSURFACE_INDIRECT)
+               kernel_write_pass_float3(buffer + kernel_data.film.pass_subsurface_indirect, sample, L->indirect_subsurface);
        if(flag & PASS_DIFFUSE_DIRECT)
                kernel_write_pass_float3(buffer + kernel_data.film.pass_diffuse_direct, sample, L->direct_diffuse);
        if(flag & PASS_GLOSSY_DIRECT)
                kernel_write_pass_float3(buffer + kernel_data.film.pass_glossy_direct, sample, L->direct_glossy);
        if(flag & PASS_TRANSMISSION_DIRECT)
                kernel_write_pass_float3(buffer + kernel_data.film.pass_transmission_direct, sample, L->direct_transmission);
+       if(flag & PASS_SUBSURFACE_DIRECT)
+               kernel_write_pass_float3(buffer + kernel_data.film.pass_subsurface_direct, sample, L->direct_subsurface);
 
        if(flag & PASS_EMISSION)
                kernel_write_pass_float3(buffer + kernel_data.film.pass_emission, sample, L->emission);
@@ -148,6 +154,8 @@ __device_inline void kernel_write_light_passes(KernelGlobals *kg, __global float
                kernel_write_pass_float3(buffer + kernel_data.film.pass_glossy_color, sample, L->color_glossy);
        if(flag & PASS_TRANSMISSION_COLOR)
                kernel_write_pass_float3(buffer + kernel_data.film.pass_transmission_color, sample, L->color_transmission);
+       if(flag & PASS_SUBSURFACE_COLOR)
+               kernel_write_pass_float3(buffer + kernel_data.film.pass_subsurface_color, sample, L->color_subsurface);
        if(flag & PASS_SHADOW) {
                float4 shadow = L->shadow;
                shadow.w = kernel_data.film.pass_shadow_scale;
index 40ecb1b..2806296 100644 (file)
@@ -892,7 +892,7 @@ __device_noinline void kernel_path_non_progressive_lighting(KernelGlobals *kg, R
 
                int num_samples;
 
-               if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
+               if(CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSDF_BSSRDF(sc->type))
                        num_samples = kernel_data.integrator.diffuse_samples;
                else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
                        num_samples = kernel_data.integrator.glossy_samples;
index b902230..111f3ca 100644 (file)
@@ -685,6 +685,27 @@ __device float3 shader_bsdf_transmission(KernelGlobals *kg, ShaderData *sd)
 #endif
 }
 
+__device float3 shader_bsdf_subsurface(KernelGlobals *kg, ShaderData *sd)
+{
+#ifdef __MULTI_CLOSURE__
+       float3 eval = make_float3(0.0f, 0.0f, 0.0f);
+
+       for(int i = 0; i< sd->num_closure; i++) {
+               ShaderClosure *sc = &sd->closure[i];
+
+               if(CLOSURE_IS_BSSRDF(sc->type))
+                       eval += sc->weight;
+       }
+
+       return eval;
+#else
+       if(CLOSURE_IS_BSSRDF(sd->closure.type))
+               return sd->closure.weight;
+       else
+               return make_float3(0.0f, 0.0f, 0.0f);
+#endif
+}
+
 __device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_factor, float3 *N)
 {
 #ifdef __MULTI_CLOSURE__
index f7bccf7..4fae961 100644 (file)
@@ -163,6 +163,10 @@ __device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 weigh
        sd->flag |= bsdf_diffuse_setup(sc);
        sd->randb_closure = 0.0f;
 
+       /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
+        * can recognize it as not being a regular diffuse closure */
+       sc->type = CLOSURE_BSDF_BSSRDF_ID;
+
        /* todo: evaluate shading to get blurred textures and bump mapping */
        /* shader_eval_surface(kg, sd, 0.0f, state_flag, SHADER_CONTEXT_SSS); */
 }
index 1010fde..c32ccac 100644 (file)
@@ -268,7 +268,10 @@ typedef enum PassType {
        PASS_SHADOW = 262144,
        PASS_MOTION = 524288,
        PASS_MOTION_WEIGHT = 1048576,
-       PASS_MIST = 2097152
+       PASS_MIST = 2097152,
+       PASS_SUBSURFACE_DIRECT = 4194304,
+       PASS_SUBSURFACE_INDIRECT = 8388608,
+       PASS_SUBSURFACE_COLOR = 16777216
 } PassType;
 
 #define PASS_ALL (~0)
@@ -291,18 +294,22 @@ typedef struct PathRadiance {
        float3 color_diffuse;
        float3 color_glossy;
        float3 color_transmission;
+       float3 color_subsurface;
 
        float3 direct_diffuse;
        float3 direct_glossy;
        float3 direct_transmission;
+       float3 direct_subsurface;
 
        float3 indirect_diffuse;
        float3 indirect_glossy;
        float3 indirect_transmission;
+       float3 indirect_subsurface;
 
        float3 path_diffuse;
        float3 path_glossy;
        float3 path_transmission;
+       float3 path_subsurface;
 
        float4 shadow;
        float mist;
@@ -315,6 +322,7 @@ typedef struct BsdfEval {
        float3 glossy;
        float3 transmission;
        float3 transparent;
+       float3 subsurface;
 } BsdfEval;
 
 #else
@@ -672,22 +680,27 @@ typedef struct KernelFilm {
        int pass_diffuse_color;
        int pass_glossy_color;
        int pass_transmission_color;
+       int pass_subsurface_color;
+       
        int pass_diffuse_indirect;
-
        int pass_glossy_indirect;
        int pass_transmission_indirect;
+       int pass_subsurface_indirect;
+       
        int pass_diffuse_direct;
        int pass_glossy_direct;
-
        int pass_transmission_direct;
+       int pass_subsurface_direct;
+       
        int pass_emission;
        int pass_background;
        int pass_ao;
+       int pass_pad1;
 
        int pass_shadow;
        float pass_shadow_scale;
        int filter_table_offset;
-       int pass_pad1;
+       int pass_pad2;
 
        int pass_mist;
        float mist_start;
index dbfb8d4..dd95f19 100644 (file)
@@ -371,7 +371,8 @@ typedef enum ClosureType {
        CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
        CLOSURE_BSDF_SHARP_GLASS_ID,
        
-       /* Transparent */
+       /* Special cases */
+       CLOSURE_BSDF_BSSRDF_ID,
        CLOSURE_BSDF_TRANSPARENT_ID,
 
        /* Other */
@@ -395,6 +396,7 @@ typedef enum ClosureType {
 #define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_DIFFUSE_TOON_ID)
 #define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_GLOSSY_TOON_ID)
 #define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
+#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID)
 #define CLOSURE_IS_BSSRDF(type) (type == CLOSURE_BSSRDF_ID)
 #define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID)
 #define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
index 2a16b7b..4b48ee1 100644 (file)
@@ -98,6 +98,9 @@ void Pass::add(PassType type, vector<Pass>& passes)
                case PASS_TRANSMISSION_COLOR:
                        pass.components = 4;
                        break;
+               case PASS_SUBSURFACE_COLOR:
+                       pass.components = 4;
+                       break;
                case PASS_DIFFUSE_INDIRECT:
                        pass.components = 4;
                        pass.exposure = true;
@@ -113,6 +116,11 @@ void Pass::add(PassType type, vector<Pass>& passes)
                        pass.exposure = true;
                        pass.divide_type = PASS_TRANSMISSION_COLOR;
                        break;
+               case PASS_SUBSURFACE_INDIRECT:
+                       pass.components = 4;
+                       pass.exposure = true;
+                       pass.divide_type = PASS_SUBSURFACE_COLOR;
+                       break;
                case PASS_DIFFUSE_DIRECT:
                        pass.components = 4;
                        pass.exposure = true;
@@ -128,6 +136,11 @@ void Pass::add(PassType type, vector<Pass>& passes)
                        pass.exposure = true;
                        pass.divide_type = PASS_TRANSMISSION_COLOR;
                        break;
+               case PASS_SUBSURFACE_DIRECT:
+                       pass.components = 4;
+                       pass.exposure = true;
+                       pass.divide_type = PASS_SUBSURFACE_COLOR;
+                       break;
 
                case PASS_EMISSION:
                        pass.components = 4;
@@ -327,6 +340,10 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
                                kfilm->pass_transmission_color = kfilm->pass_stride;
                                kfilm->use_light_pass = 1;
                                break;
+                       case PASS_SUBSURFACE_COLOR:
+                               kfilm->pass_subsurface_color = kfilm->pass_stride;
+                               kfilm->use_light_pass = 1;
+                               break;
                        case PASS_DIFFUSE_INDIRECT:
                                kfilm->pass_diffuse_indirect = kfilm->pass_stride;
                                kfilm->use_light_pass = 1;
@@ -339,6 +356,10 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
                                kfilm->pass_transmission_indirect = kfilm->pass_stride;
                                kfilm->use_light_pass = 1;
                                break;
+                       case PASS_SUBSURFACE_INDIRECT:
+                               kfilm->pass_subsurface_indirect = kfilm->pass_stride;
+                               kfilm->use_light_pass = 1;
+                               break;
                        case PASS_DIFFUSE_DIRECT:
                                kfilm->pass_diffuse_direct = kfilm->pass_stride;
                                kfilm->use_light_pass = 1;
@@ -351,6 +372,10 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
                                kfilm->pass_transmission_direct = kfilm->pass_stride;
                                kfilm->use_light_pass = 1;
                                break;
+                       case PASS_SUBSURFACE_DIRECT:
+                               kfilm->pass_subsurface_direct = kfilm->pass_stride;
+                               kfilm->use_light_pass = 1;
+                               break;
 
                        case PASS_EMISSION:
                                kfilm->pass_emission = kfilm->pass_stride;
index c151d47..4e9e18d 100644 (file)
@@ -778,34 +778,37 @@ void            ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
 /* ************** COMPOSITE NODES *************** */
 
 /* output socket defines */
-#define RRES_OUT_IMAGE                         0
-#define RRES_OUT_ALPHA                         1
-#define RRES_OUT_Z                                     2
-#define RRES_OUT_NORMAL                                3
-#define RRES_OUT_UV                                    4
-#define RRES_OUT_VEC                           5
-#define RRES_OUT_RGBA                          6
-#define RRES_OUT_DIFF                          7
-#define RRES_OUT_SPEC                          8
-#define RRES_OUT_SHADOW                                9
-#define RRES_OUT_AO                                    10
-#define RRES_OUT_REFLECT                       11
-#define RRES_OUT_REFRACT                       12
-#define RRES_OUT_INDIRECT                      13
-#define RRES_OUT_INDEXOB                       14
-#define RRES_OUT_INDEXMA                       15
-#define RRES_OUT_MIST                          16
-#define RRES_OUT_EMIT                          17
-#define RRES_OUT_ENV                           18
-#define RRES_OUT_DIFF_DIRECT           19
-#define RRES_OUT_DIFF_INDIRECT         20
-#define RRES_OUT_DIFF_COLOR                    21
-#define RRES_OUT_GLOSSY_DIRECT         22
-#define RRES_OUT_GLOSSY_INDIRECT       23
-#define RRES_OUT_GLOSSY_COLOR          24
-#define RRES_OUT_TRANSM_DIRECT         25
-#define RRES_OUT_TRANSM_INDIRECT       26
-#define RRES_OUT_TRANSM_COLOR          27
+#define RRES_OUT_IMAGE                                 0
+#define RRES_OUT_ALPHA                                 1
+#define RRES_OUT_Z                                             2
+#define RRES_OUT_NORMAL                                        3
+#define RRES_OUT_UV                                            4
+#define RRES_OUT_VEC                                   5
+#define RRES_OUT_RGBA                                  6
+#define RRES_OUT_DIFF                                  7
+#define RRES_OUT_SPEC                                  8
+#define RRES_OUT_SHADOW                                        9
+#define RRES_OUT_AO                                            10
+#define RRES_OUT_REFLECT                               11
+#define RRES_OUT_REFRACT                               12
+#define RRES_OUT_INDIRECT                              13
+#define RRES_OUT_INDEXOB                               14
+#define RRES_OUT_INDEXMA                               15
+#define RRES_OUT_MIST                                  16
+#define RRES_OUT_EMIT                                  17
+#define RRES_OUT_ENV                                   18
+#define RRES_OUT_DIFF_DIRECT                   19
+#define RRES_OUT_DIFF_INDIRECT                 20
+#define RRES_OUT_DIFF_COLOR                            21
+#define RRES_OUT_GLOSSY_DIRECT                 22
+#define RRES_OUT_GLOSSY_INDIRECT               23
+#define RRES_OUT_GLOSSY_COLOR                  24
+#define RRES_OUT_TRANSM_DIRECT                 25
+#define RRES_OUT_TRANSM_INDIRECT               26
+#define RRES_OUT_TRANSM_COLOR                  27
+#define RRES_OUT_SUBSURFACE_DIRECT             28
+#define RRES_OUT_SUBSURFACE_INDIRECT   29
+#define RRES_OUT_SUBSURFACE_COLOR              30
 
 /* note: types are needed to restore callbacks, don't change values */
 #define CMP_NODE_VIEWER                201
index dd194ed..ceb745c 100644 (file)
@@ -209,34 +209,37 @@ typedef struct SceneRenderLayer {
 #define SCE_LAY_NEG_ZMASK      0x80000
 
 /* srl->passflag */
-#define SCE_PASS_COMBINED                      (1<<0)
-#define SCE_PASS_Z                                     (1<<1)
-#define SCE_PASS_RGBA                          (1<<2)
-#define SCE_PASS_DIFFUSE                       (1<<3)
-#define SCE_PASS_SPEC                          (1<<4)
-#define SCE_PASS_SHADOW                                (1<<5)
-#define SCE_PASS_AO                                    (1<<6)
-#define SCE_PASS_REFLECT                       (1<<7)
-#define SCE_PASS_NORMAL                                (1<<8)
-#define SCE_PASS_VECTOR                                (1<<9)
-#define SCE_PASS_REFRACT                       (1<<10)
-#define SCE_PASS_INDEXOB                       (1<<11)
-#define SCE_PASS_UV                                    (1<<12)
-#define SCE_PASS_INDIRECT                      (1<<13)
-#define SCE_PASS_MIST                          (1<<14)
-#define SCE_PASS_RAYHITS                       (1<<15)
-#define SCE_PASS_EMIT                          (1<<16)
-#define SCE_PASS_ENVIRONMENT           (1<<17)
-#define SCE_PASS_INDEXMA                       (1<<18)
-#define SCE_PASS_DIFFUSE_DIRECT                (1<<19)
-#define SCE_PASS_DIFFUSE_INDIRECT      (1<<20)
-#define SCE_PASS_DIFFUSE_COLOR         (1<<21)
-#define SCE_PASS_GLOSSY_DIRECT         (1<<22)
-#define SCE_PASS_GLOSSY_INDIRECT       (1<<23)
-#define SCE_PASS_GLOSSY_COLOR          (1<<24)
-#define SCE_PASS_TRANSM_DIRECT         (1<<25)
-#define SCE_PASS_TRANSM_INDIRECT       (1<<26)
-#define SCE_PASS_TRANSM_COLOR          (1<<27)
+#define SCE_PASS_COMBINED                              (1<<0)
+#define SCE_PASS_Z                                             (1<<1)
+#define SCE_PASS_RGBA                                  (1<<2)
+#define SCE_PASS_DIFFUSE                               (1<<3)
+#define SCE_PASS_SPEC                                  (1<<4)
+#define SCE_PASS_SHADOW                                        (1<<5)
+#define SCE_PASS_AO                                            (1<<6)
+#define SCE_PASS_REFLECT                               (1<<7)
+#define SCE_PASS_NORMAL                                        (1<<8)
+#define SCE_PASS_VECTOR                                        (1<<9)
+#define SCE_PASS_REFRACT                               (1<<10)
+#define SCE_PASS_INDEXOB                               (1<<11)
+#define SCE_PASS_UV                                            (1<<12)
+#define SCE_PASS_INDIRECT                              (1<<13)
+#define SCE_PASS_MIST                                  (1<<14)
+#define SCE_PASS_RAYHITS                               (1<<15)
+#define SCE_PASS_EMIT                                  (1<<16)
+#define SCE_PASS_ENVIRONMENT                   (1<<17)
+#define SCE_PASS_INDEXMA                               (1<<18)
+#define SCE_PASS_DIFFUSE_DIRECT                        (1<<19)
+#define SCE_PASS_DIFFUSE_INDIRECT              (1<<20)
+#define SCE_PASS_DIFFUSE_COLOR                 (1<<21)
+#define SCE_PASS_GLOSSY_DIRECT                 (1<<22)
+#define SCE_PASS_GLOSSY_INDIRECT               (1<<23)
+#define SCE_PASS_GLOSSY_COLOR                  (1<<24)
+#define SCE_PASS_TRANSM_DIRECT                 (1<<25)
+#define SCE_PASS_TRANSM_INDIRECT               (1<<26)
+#define SCE_PASS_TRANSM_COLOR                  (1<<27)
+#define SCE_PASS_SUBSURFACE_DIRECT             (1<<28)
+#define SCE_PASS_SUBSURFACE_INDIRECT   (1<<29)
+#define SCE_PASS_SUBSURFACE_COLOR              (1<<30)
 
 /* note, srl->passflag is treestore element 'nr' in outliner, short still... */
 
index 64b4e01..82cdfcd 100644 (file)
@@ -570,6 +570,9 @@ static void rna_def_render_pass(BlenderRNA *brna)
                {SCE_PASS_TRANSM_DIRECT, "TRANSMISSION_DIRECT", 0, "Transmission Direct", ""},
                {SCE_PASS_TRANSM_INDIRECT, "TRANSMISSION_INDIRECT", 0, "Transmission Indirect", ""},
                {SCE_PASS_TRANSM_COLOR, "TRANSMISSION_COLOR", 0, "Transmission Color", ""},
+               {SCE_PASS_SUBSURFACE_DIRECT, "SUBSURFACE_DIRECT", 0, "Subsurface Direct", ""},
+               {SCE_PASS_SUBSURFACE_INDIRECT, "SUBSURFACE_INDIRECT", 0, "Subsurface Indirect", ""},
+               {SCE_PASS_SUBSURFACE_COLOR, "SUBSURFACE_COLOR", 0, "Subsurface Color", ""},
                {0, NULL, 0, NULL, NULL}
        };
        
index a0e1e29..9e580b1 100644 (file)
@@ -2555,6 +2555,24 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
        RNA_def_property_ui_text(prop, "Transmission Color", "Deliver transmission color pass");
        if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
        else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       
+       prop = RNA_def_property(srna, "use_pass_subsurface_direct", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_SUBSURFACE_DIRECT);
+       RNA_def_property_ui_text(prop, "Subsurface Direct", "Deliver subsurface direct pass");
+       if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+       else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+       prop = RNA_def_property(srna, "use_pass_subsurface_indirect", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_SUBSURFACE_INDIRECT);
+       RNA_def_property_ui_text(prop, "Subsurface Indirect", "Deliver subsurface indirect pass");
+       if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+       else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+       prop = RNA_def_property(srna, "use_pass_subsurface_color", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_SUBSURFACE_COLOR);
+       RNA_def_property_ui_text(prop, "Subsurface Color", "Deliver subsurface color pass");
+       if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+       else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 }
 
 static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
index 0d68b99..d073abf 100644 (file)
@@ -72,6 +72,9 @@ static bNodeSocketTemplate cmp_node_rlayers_out[] = {
        {       SOCK_RGBA, 0, N_("Transmission Direct"),        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {       SOCK_RGBA, 0, N_("Transmission Indirect"),      0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {       SOCK_RGBA, 0, N_("Transmission Color"),         0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+       {       SOCK_RGBA, 0, N_("Subsurface Direct"),          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+       {       SOCK_RGBA, 0, N_("Subsurface Indirect"),        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+       {       SOCK_RGBA, 0, N_("Subsurface Color"),           0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {       -1, 0, ""       }
 };
 
@@ -152,6 +155,13 @@ static void cmp_node_image_add_render_pass_outputs(bNodeTree *ntree, bNode *node
                cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_INDIRECT, RRES_OUT_TRANSM_INDIRECT);
        if (passflag & SCE_PASS_TRANSM_COLOR)
                cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_COLOR, RRES_OUT_TRANSM_COLOR);
+               
+       if (passflag & SCE_PASS_SUBSURFACE_DIRECT)
+               cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_DIRECT, RRES_OUT_SUBSURFACE_DIRECT);
+       if (passflag & SCE_PASS_SUBSURFACE_INDIRECT)
+               cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_INDIRECT, RRES_OUT_SUBSURFACE_INDIRECT);
+       if (passflag & SCE_PASS_SUBSURFACE_COLOR)
+               cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_COLOR, RRES_OUT_SUBSURFACE_COLOR);
 }
 
 static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node, RenderLayer *rl)
@@ -385,35 +395,38 @@ void node_cmp_rlayers_force_hidden_passes(bNode *node)
        for (sock = node->outputs.first; sock; sock = sock->next)
                sock->flag &= ~SOCK_UNAVAIL;
        
-       set_output_visible(node, passflag, RRES_OUT_IMAGE,            SCE_PASS_COMBINED);
-       set_output_visible(node, passflag, RRES_OUT_ALPHA,            SCE_PASS_COMBINED);
-       
-       set_output_visible(node, passflag, RRES_OUT_Z,                SCE_PASS_Z);
-       set_output_visible(node, passflag, RRES_OUT_NORMAL,           SCE_PASS_NORMAL);
-       set_output_visible(node, passflag, RRES_OUT_VEC,              SCE_PASS_VECTOR);
-       set_output_visible(node, passflag, RRES_OUT_UV,               SCE_PASS_UV);
-       set_output_visible(node, passflag, RRES_OUT_RGBA,             SCE_PASS_RGBA);
-       set_output_visible(node, passflag, RRES_OUT_DIFF,             SCE_PASS_DIFFUSE);
-       set_output_visible(node, passflag, RRES_OUT_SPEC,             SCE_PASS_SPEC);
-       set_output_visible(node, passflag, RRES_OUT_SHADOW,           SCE_PASS_SHADOW);
-       set_output_visible(node, passflag, RRES_OUT_AO,               SCE_PASS_AO);
-       set_output_visible(node, passflag, RRES_OUT_REFLECT,          SCE_PASS_REFLECT);
-       set_output_visible(node, passflag, RRES_OUT_REFRACT,          SCE_PASS_REFRACT);
-       set_output_visible(node, passflag, RRES_OUT_INDIRECT,         SCE_PASS_INDIRECT);
-       set_output_visible(node, passflag, RRES_OUT_INDEXOB,          SCE_PASS_INDEXOB);
-       set_output_visible(node, passflag, RRES_OUT_INDEXMA,          SCE_PASS_INDEXMA);
-       set_output_visible(node, passflag, RRES_OUT_MIST,             SCE_PASS_MIST);
-       set_output_visible(node, passflag, RRES_OUT_EMIT,             SCE_PASS_EMIT);
-       set_output_visible(node, passflag, RRES_OUT_ENV,              SCE_PASS_ENVIRONMENT);
-       set_output_visible(node, passflag, RRES_OUT_DIFF_DIRECT,      SCE_PASS_DIFFUSE_DIRECT);
-       set_output_visible(node, passflag, RRES_OUT_DIFF_INDIRECT,    SCE_PASS_DIFFUSE_INDIRECT);
-       set_output_visible(node, passflag, RRES_OUT_DIFF_COLOR,       SCE_PASS_DIFFUSE_COLOR);
-       set_output_visible(node, passflag, RRES_OUT_GLOSSY_DIRECT,    SCE_PASS_GLOSSY_DIRECT);
-       set_output_visible(node, passflag, RRES_OUT_GLOSSY_INDIRECT,  SCE_PASS_GLOSSY_INDIRECT);
-       set_output_visible(node, passflag, RRES_OUT_GLOSSY_COLOR,     SCE_PASS_GLOSSY_COLOR);
-       set_output_visible(node, passflag, RRES_OUT_TRANSM_DIRECT,    SCE_PASS_TRANSM_DIRECT);
-       set_output_visible(node, passflag, RRES_OUT_TRANSM_INDIRECT,  SCE_PASS_TRANSM_INDIRECT);
-       set_output_visible(node, passflag, RRES_OUT_TRANSM_COLOR,     SCE_PASS_TRANSM_COLOR);
+       set_output_visible(node, passflag, RRES_OUT_IMAGE,                  SCE_PASS_COMBINED);
+       set_output_visible(node, passflag, RRES_OUT_ALPHA,                  SCE_PASS_COMBINED);
+                                                                           
+       set_output_visible(node, passflag, RRES_OUT_Z,                      SCE_PASS_Z);
+       set_output_visible(node, passflag, RRES_OUT_NORMAL,                 SCE_PASS_NORMAL);
+       set_output_visible(node, passflag, RRES_OUT_VEC,                    SCE_PASS_VECTOR);
+       set_output_visible(node, passflag, RRES_OUT_UV,                     SCE_PASS_UV);
+       set_output_visible(node, passflag, RRES_OUT_RGBA,                   SCE_PASS_RGBA);
+       set_output_visible(node, passflag, RRES_OUT_DIFF,                   SCE_PASS_DIFFUSE);
+       set_output_visible(node, passflag, RRES_OUT_SPEC,                   SCE_PASS_SPEC);
+       set_output_visible(node, passflag, RRES_OUT_SHADOW,                 SCE_PASS_SHADOW);
+       set_output_visible(node, passflag, RRES_OUT_AO,                     SCE_PASS_AO);
+       set_output_visible(node, passflag, RRES_OUT_REFLECT,                SCE_PASS_REFLECT);
+       set_output_visible(node, passflag, RRES_OUT_REFRACT,                SCE_PASS_REFRACT);
+       set_output_visible(node, passflag, RRES_OUT_INDIRECT,               SCE_PASS_INDIRECT);
+       set_output_visible(node, passflag, RRES_OUT_INDEXOB,                SCE_PASS_INDEXOB);
+       set_output_visible(node, passflag, RRES_OUT_INDEXMA,                SCE_PASS_INDEXMA);
+       set_output_visible(node, passflag, RRES_OUT_MIST,                   SCE_PASS_MIST);
+       set_output_visible(node, passflag, RRES_OUT_EMIT,                   SCE_PASS_EMIT);
+       set_output_visible(node, passflag, RRES_OUT_ENV,                    SCE_PASS_ENVIRONMENT);
+       set_output_visible(node, passflag, RRES_OUT_DIFF_DIRECT,            SCE_PASS_DIFFUSE_DIRECT);
+       set_output_visible(node, passflag, RRES_OUT_DIFF_INDIRECT,          SCE_PASS_DIFFUSE_INDIRECT);
+       set_output_visible(node, passflag, RRES_OUT_DIFF_COLOR,             SCE_PASS_DIFFUSE_COLOR);
+       set_output_visible(node, passflag, RRES_OUT_GLOSSY_DIRECT,          SCE_PASS_GLOSSY_DIRECT);
+       set_output_visible(node, passflag, RRES_OUT_GLOSSY_INDIRECT,        SCE_PASS_GLOSSY_INDIRECT);
+       set_output_visible(node, passflag, RRES_OUT_GLOSSY_COLOR,           SCE_PASS_GLOSSY_COLOR);
+       set_output_visible(node, passflag, RRES_OUT_TRANSM_DIRECT,          SCE_PASS_TRANSM_DIRECT);
+       set_output_visible(node, passflag, RRES_OUT_TRANSM_INDIRECT,        SCE_PASS_TRANSM_INDIRECT);
+       set_output_visible(node, passflag, RRES_OUT_TRANSM_COLOR,           SCE_PASS_TRANSM_COLOR);
+       set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_DIRECT,      SCE_PASS_SUBSURFACE_DIRECT);
+       set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_INDIRECT,    SCE_PASS_SUBSURFACE_INDIRECT);
+       set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_COLOR,       SCE_PASS_SUBSURFACE_COLOR);
 }
 
 static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
index f719e09..ce15cc3 100644 (file)
@@ -279,6 +279,24 @@ static const char *get_pass_name(int passtype, int channel)
                if (channel == 1) return "TransCol.G";
                return "TransCol.B";
        }
+       if (passtype == SCE_PASS_SUBSURFACE_DIRECT) {
+               if (channel == -1) return "SubsurfaceDir";
+               if (channel == 0) return "SubsurfaceDir.R";
+               if (channel == 1) return "SubsurfaceDir.G";
+               return "SubsDir.B";
+       }
+       if (passtype == SCE_PASS_SUBSURFACE_INDIRECT) {
+               if (channel == -1) return "SubsurfaceInd";
+               if (channel == 0) return "SubsurfaceInd.R";
+               if (channel == 1) return "SubsurfaceInd.G";
+               return "SubsInd.B";
+       }
+       if (passtype == SCE_PASS_SUBSURFACE_COLOR) {
+               if (channel == -1) return "SubsurfaceCol";
+               if (channel == 0) return "SubsurfaceCol.R";
+               if (channel == 1) return "SubsurfaceCol.G";
+               return "SubsCol.B";
+       }
        return "Unknown";
 }
 
@@ -368,6 +386,15 @@ static int passtype_from_name(const char *str)
 
        if (strcmp(str, "TransCol") == 0)
                return SCE_PASS_TRANSM_COLOR;
+               
+       if (strcmp(str, "SubsurfaceDir") == 0)
+               return SCE_PASS_SUBSURFACE_DIRECT;
+
+       if (strcmp(str, "SubsurfaceInd") == 0)
+               return SCE_PASS_SUBSURFACE_INDIRECT;
+
+       if (strcmp(str, "SubsurfaceCol") == 0)
+               return SCE_PASS_SUBSURFACE_COLOR;
 
        return 0;
 }
@@ -538,6 +565,12 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
                        render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT);
                if (srl->passflag  & SCE_PASS_TRANSM_COLOR)
                        render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR);
+               if (srl->passflag  & SCE_PASS_SUBSURFACE_DIRECT)
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT);
+               if (srl->passflag  & SCE_PASS_SUBSURFACE_INDIRECT)
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT);
+               if (srl->passflag  & SCE_PASS_SUBSURFACE_COLOR)
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR);
        }
        /* sss, previewrender and envmap don't do layers, so we make a default one */
        if (rr->layers.first == NULL && !(layername && layername[0])) {