Cycles / Ray Depth:

* Added a Ray Depth output to the Light Path node, which returns the current ray bounce (0, 1, 2, 3...)
* This can be used to use different shaders for direct and indirect lighting and artificial effects.

Examples:
* http://www.pasteall.org/pic/show.php?id=55158 Here we use the output to apply a different shader to the third bounce. As in this example, you can use Math Nodes (Greater Than / Less Than) if you want to use values outside of the 0/1 range.

* http://www.pasteall.org/pic/show.php?id=55159 Here we restrict the maximum bounce on a per shader basis for the left sphere. This way it looks like we would only have 1 max bounce set in the scene "Light paths" panel. 
This can be used to e.g. improve performance for objects far from the camera, which do not need full GI. 

Technical notes:
* Implemented for both integrators and SVM/OSL.
* This is done by passing state.bounce to the shader_setup_from_* functions.
* Note: We don't pass state.bounce to kernel_shader_evaluate() and therefore shader_setup_from_displacement() method doesn't set the value, this is outside the path trace loop. Maybe a ToDo?
This commit is contained in:
2013-07-09 00:18:13 +00:00
parent 0b5b82bb53
commit c4fa047894
12 changed files with 56 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);
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, 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, ~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);
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);
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;
@@ -1016,7 +1016,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
@@ -1025,7 +1025,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 = (float)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 = (float)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 = (float)bounce;
#ifdef __INSTANCING__
sd->object = ~0;

View File

@@ -548,6 +548,9 @@ typedef struct ShaderData {
/* length of the ray being shaded */
float ray_length;
/* ray bounce depth */
float ray_depth;
#ifdef __RAY_DIFFERENTIALS__
/* differential of P. these are orthogonal to Ng, not N */
differential3 dP;

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 Length */
float f = sd->ray_depth;
return set_attribute_float(f, type, derivatives, val);
}
else if (name == u_ndc) {
/* NDC coordinates with special exception for otho */
OSLThreadData *tdata = kg->osl_tdata;
@@ -919,7 +925,7 @@ 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);
shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray, -1);
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,6 @@ shader node_light_path(
IsTransmissionRay = raytype("refraction");
getattribute("path:ray_length", RayLength);
getattribute("path:ray_depth", RayDepth);
}

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 = sd->ray_depth; break;
}
stack_store_float(stack, out_offset, info);

View File

@@ -157,7 +157,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)
@@ -2119,6 +2120,12 @@ void LightPathNode::compile(SVMCompiler& compiler)
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);
}
}
void LightPathNode::compile(OSLCompiler& compiler)

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