Cycles / Ray Depth:

* 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.
This commit is contained in:
Thomas Dinges
2013-07-31 20:30:37 +00:00
parent c15ae082bb
commit 3840e0b234
12 changed files with 62 additions and 31 deletions

View 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 */

View 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);

View 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);

View 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;

View 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 */

View 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;
}

View 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;

View 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;
}

View 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);

View 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 {

View 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);
}
}

View 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, "" }
};