Cycles / Ray Depth:
authorThomas Dinges <blender@dingto.org>
Wed, 31 Jul 2013 20:30:37 +0000 (20:30 +0000)
committerThomas Dinges <blender@dingto.org>
Wed, 31 Jul 2013 20:30:37 +0000 (20:30 +0000)
* Added a Ray Depth output to the Light Path node, which gives the user access to the current bounce.
This can be used to limit the maximum ray bounce on a per shader basis. Another use case is to restrict light influence with this, to have a lamp only contribute to the direct lighting.

http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/More#Light_Path

This is part of my GSoC 2013 project. SVN merge of r58091 and r58772 from soc-2013-dingto.

12 files changed:
intern/cycles/kernel/kernel_displace.h
intern/cycles/kernel/kernel_emission.h
intern/cycles/kernel/kernel_path.h
intern/cycles/kernel/kernel_shader.h
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/osl/osl_services.cpp
intern/cycles/kernel/osl/osl_services.h
intern/cycles/kernel/shaders/node_light_path.osl
intern/cycles/kernel/svm/svm_light_path.h
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/nodes.cpp
source/blender/nodes/shader/nodes/node_shader_light_path.c

index ae2e35e8d93be2d1e75dd3d06844576578455866..b4ece1610beee096528a887d8feb6f7fa4e95f29 100644 (file)
@@ -57,7 +57,7 @@ __device void kernel_shader_evaluate(KernelGlobals *kg, __global uint4 *input, _
 #endif
 
                /* setup shader data */
-               shader_setup_from_background(kg, &sd, &ray);
+               shader_setup_from_background(kg, &sd, &ray, 0);
 
                /* evaluate */
                int flag = 0; /* we can't know which type of BSDF this is for */
index 77dc59d2691fe4fed592e19141fe4007ad35f043..a6bd3ed2850dc53a4ab31965a95ab496c1a913ee 100644 (file)
@@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN
 /* Direction Emission */
 
 __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
-       LightSample *ls, float u, float v, float3 I, differential3 dI, float t, float time)
+       LightSample *ls, float u, float v, float3 I, differential3 dI, float t, float time, int bounce)
 {
        /* setup shading at emitter */
        ShaderData sd;
@@ -41,7 +41,7 @@ __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
 #ifdef __CAMERA_MOTION__
                ray.time = time;
 #endif
-               shader_setup_from_background(kg, &sd, &ray);
+               shader_setup_from_background(kg, &sd, &ray, bounce+1);
                eval = shader_eval_background(kg, &sd, 0, SHADER_CONTEXT_EMISSION);
        }
        else
@@ -49,10 +49,10 @@ __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
        {
 #ifdef __HAIR__
                if(ls->type == LIGHT_STRAND)
-                       shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ls->prim);
+                       shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, bounce+1, ls->prim);
                else
 #endif
-                       shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ~0);
+                       shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, bounce+1, ~0);
 
                ls->Ng = sd.Ng;
 
@@ -74,7 +74,7 @@ __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
 
 __device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
        float randt, float rando, float randu, float randv, Ray *ray, BsdfEval *eval,
-       bool *is_lamp)
+       bool *is_lamp, int bounce)
 {
        LightSample ls;
 
@@ -97,7 +97,7 @@ __device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd, int li
        differential3 dD = differential3_zero();
 
        /* evaluate closure */
-       float3 light_eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D, dD, ls.t, sd->time);
+       float3 light_eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D, dD, ls.t, sd->time, bounce);
 
        if(is_zero(light_eval))
                return false;
@@ -185,7 +185,7 @@ __device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, ShaderDa
 
 /* Indirect Lamp Emission */
 
-__device_noinline bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf, float randt, float3 *emission)
+__device_noinline bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf, float randt, float3 *emission, int bounce)
 {
        LightSample ls;
        int lamp = lamp_light_eval_sample(kg, randt);
@@ -209,7 +209,7 @@ __device_noinline bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int p
        /* todo: missing texture coordinates */
        float u = 0.0f;
        float v = 0.0f;
-       float3 L = direct_emissive_eval(kg, 0.0f, &ls, u, v, -ray->D, ray->dD, ls.t, ray->time);
+       float3 L = direct_emissive_eval(kg, 0.0f, &ls, u, v, -ray->D, ray->dD, ls.t, ray->time, bounce);
 
        if(!(path_flag & PATH_RAY_MIS_SKIP)) {
                /* multiple importance sampling, get regular light pdf,
@@ -224,7 +224,7 @@ __device_noinline bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int p
 
 /* Indirect Background */
 
-__device_noinline float3 indirect_background(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf)
+__device_noinline float3 indirect_background(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf, int bounce)
 {
 #ifdef __BACKGROUND__
        int shader = kernel_data.background.shader;
@@ -240,7 +240,7 @@ __device_noinline float3 indirect_background(KernelGlobals *kg, Ray *ray, int pa
 
        /* evaluate background closure */
        ShaderData sd;
-       shader_setup_from_background(kg, &sd, ray);
+       shader_setup_from_background(kg, &sd, ray, bounce+1);
 
        float3 L = shader_eval_background(kg, &sd, path_flag, SHADER_CONTEXT_EMISSION);
 
index 0ef255786fa66c534e39ae0258b8dab68abc5701..40ecb1be91b99bf7feb3f9e9648da5265b6b33de 100644 (file)
@@ -215,7 +215,7 @@ __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ra
                                        return true;
 
                                ShaderData sd;
-                               shader_setup_from_ray(kg, &sd, &isect, ray);
+                               shader_setup_from_ray(kg, &sd, &isect, ray, state->bounce+1);
                                shader_eval_surface(kg, &sd, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
 
                                throughput *= shader_bsdf_transparency(kg, &sd);
@@ -300,7 +300,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
                        float light_t = path_rng_1D(kg, rng, sample, num_samples, rng_offset + PRNG_LIGHT);
                        float3 emission;
 
-                       if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission))
+                       if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission, state.bounce))
                                path_radiance_accum_emission(&L, throughput, emission, state.bounce);
                }
 #endif
@@ -318,7 +318,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
 
 #ifdef __BACKGROUND__
                        /* sample background shader */
-                       float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
+                       float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce);
                        path_radiance_accum_background(&L, throughput, L_background, state.bounce);
 #endif
 
@@ -327,7 +327,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
 
                /* setup shading */
                ShaderData sd;
-               shader_setup_from_ray(kg, &sd, &isect, &ray);
+               shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
                float rbsdf = path_rng_1D(kg, rng, sample, num_samples, rng_offset + PRNG_BSDF);
                shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
 
@@ -464,7 +464,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
                                light_ray.time = sd.time;
 #endif
 
-                               if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+                               if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
                                        /* trace shadow ray */
                                        float3 shadow;
 
@@ -575,7 +575,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
                        float light_t = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT);
                        float3 emission;
 
-                       if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission))
+                       if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission, state.bounce))
                                path_radiance_accum_emission(L, throughput, emission, state.bounce);
                }
 #endif
@@ -583,7 +583,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
                if(!hit) {
 #ifdef __BACKGROUND__
                        /* sample background shader */
-                       float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
+                       float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce);
                        path_radiance_accum_background(L, throughput, L_background, state.bounce);
 #endif
 
@@ -592,7 +592,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
 
                /* setup shading */
                ShaderData sd;
-               shader_setup_from_ray(kg, &sd, &isect, &ray);
+               shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
                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);
                shader_merge_closures(kg, &sd);
@@ -706,7 +706,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
 #endif
 
                                /* sample random light */
-                               if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+                               if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
                                        /* trace shadow ray */
                                        float3 shadow;
 
@@ -838,7 +838,7 @@ __device_noinline void kernel_path_non_progressive_lighting(KernelGlobals *kg, R
                                float light_u, light_v;
                                path_rng_2D(kg, &lamp_rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_LIGHT_U, &light_u, &light_v);
 
-                               if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+                               if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
                                        /* trace shadow ray */
                                        float3 shadow;
 
@@ -867,7 +867,7 @@ __device_noinline void kernel_path_non_progressive_lighting(KernelGlobals *kg, R
                                if(kernel_data.integrator.num_all_lights)
                                        light_t = 0.5f*light_t;
 
-                               if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+                               if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
                                        /* trace shadow ray */
                                        float3 shadow;
 
@@ -1013,7 +1013,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
 
 #ifdef __BACKGROUND__
                        /* sample background shader */
-                       float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
+                       float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce);
                        path_radiance_accum_background(&L, throughput, L_background, state.bounce);
 #endif
 
@@ -1022,7 +1022,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
 
                /* setup shading */
                ShaderData sd;
-               shader_setup_from_ray(kg, &sd, &isect, &ray);
+               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);
 
index 039981a031a4c0ecf4fcbd94d9d450ee23b756c1..b902230a9b90585c20e2851deca5f6c5fb4080f3 100644 (file)
@@ -64,7 +64,7 @@ __device_noinline
 __device
 #endif
 void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
-       const Intersection *isect, const Ray *ray)
+       const Intersection *isect, const Ray *ray, int bounce)
 {
 #ifdef __INSTANCING__
        sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object;
@@ -80,6 +80,7 @@ void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
 
        sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
        sd->ray_length = isect->t;
+       sd->ray_depth = bounce;
 
 #ifdef __HAIR__
        if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) {
@@ -277,7 +278,7 @@ __device
 #endif
 void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
        const float3 P, const float3 Ng, const float3 I,
-       int shader, int object, int prim, float u, float v, float t, float time, int segment)
+       int shader, int object, int prim, float u, float v, float t, float time, int bounce, int segment)
 {
        /* vectors */
        sd->P = P;
@@ -300,6 +301,7 @@ void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
        sd->v = v;
 #endif
        sd->ray_length = t;
+       sd->ray_depth = bounce;
 
        /* detect instancing, for non-instanced the object index is -object-1 */
 #ifdef __INSTANCING__
@@ -408,12 +410,12 @@ __device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
 
        /* watch out: no instance transform currently */
 
-       shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, 0.0f, TIME_INVALID, ~0);
+       shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, 0.0f, TIME_INVALID, 0, ~0);
 }
 
 /* ShaderData setup from ray into background */
 
-__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray)
+__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int bounce)
 {
        /* vectors */
        sd->P = ray->D;
@@ -426,6 +428,7 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData
        sd->time = ray->time;
 #endif
        sd->ray_length = 0.0f;
+       sd->ray_depth = bounce;
 
 #ifdef __INSTANCING__
        sd->object = ~0;
index 38ababa96bdbb4c5e45f67ab99c1722e21dad188..733eb665860e21c812e4883b4a98f089e593e0b0 100644 (file)
@@ -540,6 +540,9 @@ typedef struct ShaderData {
        
        /* length of the ray being shaded */
        float ray_length;
+       
+       /* ray bounce depth */
+       int ray_depth;
 
 #ifdef __RAY_DIFFERENTIALS__
        /* differential of P. these are orthogonal to Ng, not N */
index e1e43b117e71e623e7e28a30f85cfb9dbd04c6a0..f3b79da88944709407c2da458d769476fffc06d9 100644 (file)
@@ -84,6 +84,7 @@ ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
 ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
 #endif
 ustring OSLRenderServices::u_path_ray_length("path:ray_length");
+ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
 ustring OSLRenderServices::u_trace("trace");
 ustring OSLRenderServices::u_hit("hit");
 ustring OSLRenderServices::u_hitdist("hitdist");
@@ -660,6 +661,11 @@ bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *
                float f = sd->ray_length;
                return set_attribute_float(f, type, derivatives, val);
        }
+       else if (name == u_path_ray_depth) {
+               /* Ray Depth */
+               int f = sd->ray_depth;
+               return set_attribute_int(f, type, derivatives, val);
+       }
        else if (name == u_ndc) {
                /* NDC coordinates with special exception for otho */
                OSLThreadData *tdata = kg->osl_tdata;
@@ -919,7 +925,10 @@ bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustri
 
                                if(!tracedata->setup) {
                                        /* lazy shader data setup */
-                                       shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray);
+                                       ShaderData *original_sd = (ShaderData *)(sg->renderstate);
+                                       int bounce = original_sd->ray_depth + 1;
+
+                                       shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray, bounce);
                                        tracedata->setup = true;
                                }
 
index ca18c85a1671c742876acb9b27410e328afed4e2..5ec4673ef3799850a53f972b484e111fa665b909 100644 (file)
@@ -135,6 +135,7 @@ public:
        static ustring u_curve_thickness;
        static ustring u_curve_tangent_normal;
        static ustring u_path_ray_length;
+       static ustring u_path_ray_depth;
        static ustring u_trace;
        static ustring u_hit;
        static ustring u_hitdist;
index 9e3f6c7b4a985c6dd14d41e367c1260046c658f9..ed3c6969970a5bd918e370753f6f4f44f8d3447c 100644 (file)
@@ -26,7 +26,8 @@ shader node_light_path(
        output float IsSingularRay = 0.0,
        output float IsReflectionRay = 0.0,
        output float IsTransmissionRay = 0.0,
-       output float RayLength = 0.0)
+       output float RayLength = 0.0,
+       output float RayDepth = 0.0)
 {
        IsCameraRay = raytype("camera");
        IsShadowRay = raytype("shadow");
@@ -37,5 +38,9 @@ shader node_light_path(
        IsTransmissionRay = raytype("refraction");
 
        getattribute("path:ray_length", RayLength);
+
+       int ray_depth;
+       getattribute("path:ray_depth", ray_depth);
+       RayDepth = (float)ray_depth;
 }
 
index b29dc9cbd45c436e8e3c287b40386a1e623fc875..0f16ef838942890a0ef15f8fda82ec7d0a79eb0a 100644 (file)
@@ -34,6 +34,7 @@ __device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uint
                case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break;
                case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break;
                case NODE_LP_ray_length: info = sd->ray_length; break;
+               case NODE_LP_ray_depth: info = (float)sd->ray_depth; break;
        }
 
        stack_store_float(stack, out_offset, info);
index e5b3e2b972f4773de09cdb8ad2fd788811d943b1..85719265292da62a935407705128592ab2c5a64b 100644 (file)
@@ -153,7 +153,8 @@ typedef enum NodeLightPath {
        NODE_LP_reflection,
        NODE_LP_transmission,
        NODE_LP_backfacing,
-       NODE_LP_ray_length
+       NODE_LP_ray_length,
+       NODE_LP_ray_depth
 } NodeLightPath;
 
 typedef enum NodeLightFalloff {
index 029b948332af8e42ec762b0e00c123778e1b6507..bd254c8e0d13f3d1eecfbcd8fe6b5ae4232ac664 100644 (file)
@@ -2064,6 +2064,7 @@ LightPathNode::LightPathNode()
        add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT);
        add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT);
        add_output("Ray Length", SHADER_SOCKET_FLOAT);
+       add_output("Ray Depth", SHADER_SOCKET_FLOAT);
 }
 
 void LightPathNode::compile(SVMCompiler& compiler)
@@ -2118,6 +2119,12 @@ void LightPathNode::compile(SVMCompiler& compiler)
                compiler.stack_assign(out);
                compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, out->stack_offset);
        }
+       
+       out = output("Ray Depth");
+       if(!out->links.empty()) {
+               compiler.stack_assign(out);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, out->stack_offset);
+       }
 
 }
 
index 63713eb1e020bd69c073b372b73e084f9a79c8a0..9d769b284b1e26d06ae534d49e944288571b400e 100644 (file)
@@ -38,6 +38,7 @@ static bNodeSocketTemplate sh_node_light_path_out[] = {
        {       SOCK_FLOAT, 0, N_("Is Reflection Ray"),         0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {       SOCK_FLOAT, 0, N_("Is Transmission Ray"),       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {       SOCK_FLOAT, 0, N_("Ray Length"),                        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+       {       SOCK_FLOAT, 0, N_("Ray Depth"),                         0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {       -1, 0, ""       }
 };