Cycles: First implementation of shadow catcher

It uses an idea of accumulating all possible light reachable across the
light path (without taking shadow blocked into account) and accumulating
total shaded light across the path. Dividing second figure by first one
seems to be giving good estimate of the shadow.

In fact, to my knowledge, it's something really similar to what is
happening in the denoising branch, so we are aligned here which is good.

The workflow is following:

- Create an object which matches real-life object on which shadow is
  to be catched.

- Create approximate similar material on that object.

  This is needed to make indirect light properly affecting CG objects
  in the scene.

- Mark object as Shadow Catcher in the Object properties.

Ideally, after doing that it will be possible to render the image and
simply alpha-over it on top of real footage.
This commit is contained in:
Sergey Sharybin 2017-02-09 14:19:01 +01:00
parent 5aaa643947
commit d14e39622a
Notes: blender-bot 2023-02-14 00:58:37 +01:00
Referenced by issue #69410, Shadow catcher receive shadows even if there is no light in the scene
18 changed files with 411 additions and 47 deletions

View File

@ -1096,6 +1096,12 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
default=1.0,
)
cls.is_shadow_catcher = BoolProperty(
name="Shadow Catcher",
description="Only render shadows on this object, for compositing renders into real footage",
default=False,
)
@classmethod
def unregister(cls):
del bpy.types.Object.cycles

View File

@ -797,6 +797,9 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel):
sub.active = scene.render.use_simplify and cscene.use_distance_cull
sub.prop(cob, "use_distance_cull")
col = layout.column()
col.prop(cob, "is_shadow_catcher")
class CYCLES_OT_use_shading_nodes(Operator):
"""Enable nodes on a material, world or lamp"""

View File

@ -343,6 +343,13 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
object_updated = true;
}
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher");
if(is_shadow_catcher != object->is_shadow_catcher) {
object->is_shadow_catcher = is_shadow_catcher;
object_updated = true;
}
/* object sync
* transform comparison should not be needed, but duplis don't work perfect
* in the depsgraph and may not signal changes, so this is a workaround */

View File

@ -230,30 +230,63 @@ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg,
#endif
#ifdef __SHADOW_RECORD_ALL__
ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, const Ray *ray, Intersection *isect, uint max_hits, uint *num_hits)
ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg,
const Ray *ray,
Intersection *isect,
int skip_object,
uint max_hits,
uint *num_hits)
{
# ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
# ifdef __HAIR__
if(kernel_data.bvh.have_curves)
return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, max_hits, num_hits);
if(kernel_data.bvh.have_curves) {
return bvh_intersect_shadow_all_hair_motion(kg,
ray,
isect,
skip_object,
max_hits,
num_hits);
}
# endif /* __HAIR__ */
return bvh_intersect_shadow_all_motion(kg, ray, isect, max_hits, num_hits);
return bvh_intersect_shadow_all_motion(kg,
ray,
isect,
skip_object,
max_hits,
num_hits);
}
# endif /* __OBJECT_MOTION__ */
# ifdef __HAIR__
if(kernel_data.bvh.have_curves)
return bvh_intersect_shadow_all_hair(kg, ray, isect, max_hits, num_hits);
if(kernel_data.bvh.have_curves) {
return bvh_intersect_shadow_all_hair(kg,
ray,
isect,
skip_object,
max_hits,
num_hits);
}
# endif /* __HAIR__ */
# ifdef __INSTANCING__
if(kernel_data.bvh.have_instancing)
return bvh_intersect_shadow_all_instancing(kg, ray, isect, max_hits, num_hits);
if(kernel_data.bvh.have_instancing) {
return bvh_intersect_shadow_all_instancing(kg,
ray,
isect,
skip_object,
max_hits,
num_hits);
}
# endif /* __INSTANCING__ */
return bvh_intersect_shadow_all(kg, ray, isect, max_hits, num_hits);
return bvh_intersect_shadow_all(kg,
ray,
isect,
skip_object,
max_hits,
num_hits);
}
#endif /* __SHADOW_RECORD_ALL__ */

View File

@ -45,6 +45,7 @@ ccl_device_inline
bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
const int skip_object,
const uint max_hits,
uint *num_hits)
{
@ -189,6 +190,16 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
while(prim_addr < prim_addr2) {
kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type);
#ifdef __SHADOW_TRICKS__
uint tri_object = (object == OBJECT_NONE)
? kernel_tex_fetch(__prim_object, prim_addr)
: object;
if(tri_object == skip_object) {
++prim_addr;
continue;
}
#endif
bool hit;
/* todo: specialized intersect functions which don't fill in
@ -398,6 +409,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
const int skip_object,
const uint max_hits,
uint *num_hits)
{
@ -406,6 +418,7 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
return BVH_FUNCTION_FULL_NAME(QBVH)(kg,
ray,
isect_array,
skip_object,
max_hits,
num_hits);
}
@ -416,6 +429,7 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
return BVH_FUNCTION_FULL_NAME(BVH)(kg,
ray,
isect_array,
skip_object,
max_hits,
num_hits);
}

View File

@ -33,6 +33,7 @@
ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
const int skip_object,
const uint max_hits,
uint *num_hits)
{
@ -270,6 +271,16 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
while(prim_addr < prim_addr2) {
kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type);
#ifdef __SHADOW_TRICKS__
uint tri_object = (object == OBJECT_NONE)
? kernel_tex_fetch(__prim_object, prim_addr)
: object;
if(tri_object == skip_object) {
++prim_addr;
continue;
}
#endif
bool hit;
/* todo: specialized intersect functions which don't fill in

View File

@ -52,10 +52,17 @@ ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 v
{
eval->diffuse = value;
}
#ifdef __SHADOW_TRICKS__
eval->sum_no_mis = make_float3(0.0f, 0.0f, 0.0f);
#endif
}
ccl_device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value)
ccl_device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value, float mis_weight)
{
#ifdef __SHADOW_TRICKS__
eval->sum_no_mis += value;
#endif
value *= mis_weight;
#ifdef __PASSES__
if(eval->use_light_pass) {
if(CLOSURE_IS_BSDF_DIFFUSE(type))
@ -96,7 +103,7 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval)
}
}
ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value)
ccl_device_inline void bsdf_eval_mis(BsdfEval *eval, float value)
{
#ifdef __PASSES__
if(eval->use_light_pass) {
@ -115,8 +122,19 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value)
}
}
ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value)
{
#ifdef __SHADOW_TRICKS__
eval->sum_no_mis *= value;
#endif
bsdf_eval_mis(eval, value);
}
ccl_device_inline void bsdf_eval_mul3(BsdfEval *eval, float3 value)
{
#ifdef __SHADOW_TRICKS__
eval->sum_no_mis *= value;
#endif
#ifdef __PASSES__
if(eval->use_light_pass) {
eval->diffuse *= value;
@ -134,7 +152,7 @@ ccl_device_inline void bsdf_eval_mul3(BsdfEval *eval, float3 value)
#endif
}
ccl_device_inline float3 bsdf_eval_sum(BsdfEval *eval)
ccl_device_inline float3 bsdf_eval_sum(const BsdfEval *eval)
{
#ifdef __PASSES__
if(eval->use_light_pass) {
@ -198,6 +216,12 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
{
L->emission = make_float3(0.0f, 0.0f, 0.0f);
}
#ifdef __SHADOW_TRICKS__
L->path_total = make_float3(0.0f, 0.0f, 0.0f);
L->path_total_shaded = make_float3(0.0f, 0.0f, 0.0f);
L->shadow_color = make_float3(0.0f, 0.0f, 0.0f);
#endif
}
ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space float3 *throughput,
@ -252,7 +276,12 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 thro
}
}
ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput, float3 alpha, float3 bsdf, float3 ao, int bounce)
ccl_device_inline void path_radiance_accum_ao(PathRadiance *L,
float3 throughput,
float3 alpha,
float3 bsdf,
float3 ao,
int bounce)
{
#ifdef __PASSES__
if(L->use_light_pass) {
@ -271,6 +300,26 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput
{
L->emission += throughput*bsdf*ao;
}
#ifdef __SHADOW_TRICKS__
float3 light = throughput * bsdf;
L->path_total += light;
L->path_total_shaded += ao * light;
#endif
}
ccl_device_inline void path_radiance_accum_total_ao(
PathRadiance *L,
float3 throughput,
float3 bsdf)
{
#ifdef __SHADOW_TRICKS__
L->path_total += throughput * bsdf;
#else
(void) L;
(void) throughput;
(void) bsdf;
#endif
}
ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughput, BsdfEval *bsdf_eval, float3 shadow, float shadow_fac, int bounce, bool is_lamp)
@ -301,15 +350,38 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through
{
L->emission += throughput*bsdf_eval->diffuse*shadow;
}
#ifdef __SHADOW_TRICKS__
float3 light = throughput * bsdf_eval->sum_no_mis;
L->path_total += light;
L->path_total_shaded += shadow * light;
#endif
}
ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 throughput, float3 value, int bounce)
ccl_device_inline void path_radiance_accum_total_light(
PathRadiance *L,
float3 throughput,
const BsdfEval *bsdf_eval)
{
#ifdef __SHADOW_TRICKS__
L->path_total += throughput * bsdf_eval->sum_no_mis;
#else
(void) L;
(void) throughput;
(void) bsdf_eval;
#endif
}
ccl_device_inline void path_radiance_accum_background(PathRadiance *L,
ccl_addr_space PathState *state,
float3 throughput,
float3 value)
{
#ifdef __PASSES__
if(L->use_light_pass) {
if(bounce == 0)
if(state->bounce == 0)
L->background += throughput*value;
else if(bounce == 1)
else if(state->bounce == 1)
L->direct_emission += throughput*value;
else
L->indirect += throughput*value;
@ -319,6 +391,13 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 th
{
L->emission += throughput*value;
}
#ifdef __SHADOW_TRICKS__
L->path_total += throughput * value;
if(state->flag & PATH_RAY_SHADOW_CATCHER_ONLY) {
L->path_total_shaded += throughput * value;
}
#endif
}
ccl_device_inline void path_radiance_sum_indirect(PathRadiance *L)
@ -501,5 +580,34 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance
L->emission += L_sample->emission * fac;
}
CCL_NAMESPACE_END
#ifdef __SHADOW_TRICKS__
/* Calculate current shadow of the path. */
ccl_device_inline float path_radiance_sum_shadow(const PathRadiance *L)
{
float path_total = average(L->path_total);
float path_total_shaded = average(L->path_total_shaded);
if(path_total != 0.0f) {
return path_total_shaded / path_total;
}
return 1.0f;
}
/* Calculate final light sum and transparency for shadow catcher object. */
ccl_device_inline float3 path_radiance_sum_shadowcatcher(KernelGlobals *kg,
const PathRadiance *L,
ccl_addr_space float* L_transparent)
{
const float shadow = path_radiance_sum_shadow(L);
float3 L_sum;
if(kernel_data.background.transparent) {
*L_transparent = shadow;
L_sum = make_float3(0.0f, 0.0f, 0.0f);
}
else {
L_sum = L->shadow_color * shadow;
}
return L_sum;
}
#endif
CCL_NAMESPACE_END

View File

@ -156,7 +156,12 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg,
if(bsdf_eval_is_zero(eval))
return false;
if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) {
if(kernel_data.integrator.light_inv_rr_threshold > 0.0f
#ifdef __SHADOW_TRICKS__
&& (state->flag & PATH_RAY_SHADOW_CATCHER) == 0
#endif
)
{
float probability = max3(fabs(bsdf_eval_sum(eval))) * kernel_data.integrator.light_inv_rr_threshold;
if(probability < 1.0f) {
if(rand_terminate >= probability) {

View File

@ -92,6 +92,9 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) {
path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
}
else {
path_radiance_accum_total_ao(L, throughput, ao_bsdf);
}
}
}
@ -290,9 +293,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* sample background shader */
float3 L_background = indirect_background(kg, emission_sd, state, ray);
path_radiance_accum_background(L,
state,
throughput,
L_background,
state->bounce);
L_background);
#endif /* __BACKGROUND__ */
break;
@ -312,6 +315,12 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
shader_merge_closures(sd);
#endif /* __BRANCHED_PATH__ */
#ifdef __SHADOW_TRICKS__
if(!(sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) {
state->flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY;
}
#endif /* __SHADOW_TRICKS__ */
/* blurring of bsdf after bounces, for rays that have a small likelihood
* of following this particular path (diffuse, rough glossy) */
if(kernel_data.integrator.filter_glossy != FLT_MAX) {
@ -396,7 +405,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
#if defined(__EMISSION__) && defined(__BRANCHED_PATH__)
if(kernel_data.integrator.use_direct_light) {
int all = kernel_data.integrator.sample_all_lights_indirect;
int all = (kernel_data.integrator.sample_all_lights_indirect) ||
(state->flag & PATH_RAY_SHADOW_CATCHER);
kernel_branched_path_surface_connect_light(kg,
rng,
sd,
@ -611,7 +621,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#ifdef __BACKGROUND__
/* sample background shader */
float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
path_radiance_accum_background(&L, &state, throughput, L_background);
#endif /* __BACKGROUND__ */
break;
@ -625,6 +635,21 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
#ifdef __SHADOW_TRICKS__
if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) {
if(state.flag & PATH_RAY_CAMERA) {
state.flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY);
state.catcher_object = sd.object;
if(!kernel_data.background.transparent) {
L.shadow_color = indirect_background(kg, &emission_sd, &state, &ray);
}
}
}
else {
state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY;
}
#endif /* __SHADOW_TRICKS__ */
/* holdout */
#ifdef __HOLDOUT__
if(((sd.flag & SD_HOLDOUT) ||
@ -742,7 +767,16 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
}
#endif /* __SUBSURFACE__ */
float3 L_sum = path_radiance_clamp_and_sum(kg, &L);
float3 L_sum;
#ifdef __SHADOW_TRICKS__
if(state.flag & PATH_RAY_SHADOW_CATCHER) {
L_sum = path_radiance_sum_shadowcatcher(kg, &L, &L_transparent);
}
else
#endif /* __SHADOW_TRICKS__ */
{
L_sum = path_radiance_clamp_and_sum(kg, &L);
}
kernel_write_light_passes(kg, buffer, &L, sample);

View File

@ -55,8 +55,12 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg,
light_ray.dP = sd->dP;
light_ray.dD = differential3_zero();
if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow))
if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) {
path_radiance_accum_ao(L, throughput*num_samples_inv, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
}
else {
path_radiance_accum_total_ao(L, throughput*num_samples_inv, ao_bsdf);
}
}
}
}
@ -206,7 +210,8 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
#ifdef __EMISSION__
/* direct light */
if(kernel_data.integrator.use_direct_light) {
int all = kernel_data.integrator.sample_all_lights_direct;
int all = (kernel_data.integrator.sample_all_lights_direct) ||
(state->flag & PATH_RAY_SHADOW_CATCHER);
kernel_branched_path_surface_connect_light(
kg,
rng,
@ -461,7 +466,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __BACKGROUND__
/* sample background shader */
float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
path_radiance_accum_background(&L, &state, throughput, L_background);
#endif /* __BACKGROUND__ */
break;
@ -472,6 +477,21 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
shader_merge_closures(&sd);
#ifdef __SHADOW_TRICKS__
if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) {
if(state.flag & PATH_RAY_CAMERA) {
state.flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY);
state.catcher_object = sd.object;
if(!kernel_data.background.transparent) {
L.shadow_color = indirect_background(kg, &emission_sd, &state, &ray);
}
}
}
else {
state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY;
}
#endif /* __SHADOW_TRICKS__ */
/* holdout */
#ifdef __HOLDOUT__
if((sd.flag & SD_HOLDOUT) || (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) {
@ -544,7 +564,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __EMISSION__
/* direct light */
if(kernel_data.integrator.use_direct_light) {
int all = kernel_data.integrator.sample_all_lights_direct;
int all = (kernel_data.integrator.sample_all_lights_direct) ||
(state.flag & PATH_RAY_SHADOW_CATCHER);
kernel_branched_path_surface_connect_light(kg, rng,
&sd, &emission_sd, &hit_state, throughput, 1.0f, &L, all);
}
@ -581,7 +602,16 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#endif /* __VOLUME__ */
}
float3 L_sum = path_radiance_clamp_and_sum(kg, &L);
float3 L_sum;
#ifdef __SHADOW_TRICKS__
if(state.flag & PATH_RAY_SHADOW_CATCHER) {
L_sum = path_radiance_sum_shadowcatcher(kg, &L, &L_transparent);
}
else
#endif /* __SHADOW_TRICKS__ */
{
L_sum = path_radiance_clamp_and_sum(kg, &L);
}
kernel_write_light_passes(kg, buffer, &L, sample);

View File

@ -54,6 +54,10 @@ ccl_device_inline void path_state_init(KernelGlobals *kg,
state->volume_stack[0].shader = SHADER_NONE;
}
#endif
#ifdef __SHADOW_TRICKS__
state->catcher_object = OBJECT_NONE;
#endif
}
ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathState *state, int label)

View File

@ -16,8 +16,7 @@
CCL_NAMESPACE_BEGIN
#if (defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__)) && !defined(__SPLIT_KERNEL__)
#if (defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__) || defined(__SHADOW_TRICKS__)) && !defined(__SPLIT_KERNEL__)
/* branched path tracing: connect path directly to position on one or more lights and add it to L */
ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RNG *rng,
ShaderData *sd, ShaderData *emission_sd, PathState *state, float3 throughput,
@ -66,6 +65,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
/* accumulate */
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
}
else {
path_radiance_accum_total_light(L, throughput*num_samples_inv, &L_light);
}
}
}
}
@ -100,6 +102,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
/* accumulate */
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
}
else {
path_radiance_accum_total_light(L, throughput*num_samples_inv, &L_light);
}
}
}
}
@ -123,6 +128,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
/* accumulate */
path_radiance_accum_light(L, throughput*num_samples_adjust, &L_light, shadow, num_samples_adjust, state->bounce, is_lamp);
}
else {
path_radiance_accum_total_light(L, throughput*num_samples_adjust, &L_light);
}
}
}
}
@ -197,6 +205,21 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_
if(!(kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL)))
return;
#ifdef __SHADOW_TRICKS__
if(state->flag & PATH_RAY_SHADOW_CATCHER) {
kernel_branched_path_surface_connect_light(kg,
rng,
sd,
emission_sd,
state,
throughput,
1.0f,
L,
1);
return;
}
#endif
/* sample illumination from lights to find path contribution */
float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT);
float light_u, light_v;
@ -221,6 +244,9 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_
/* accumulate */
path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
}
else {
path_radiance_accum_total_light(L, throughput, &L_light);
}
}
}
#endif

View File

@ -516,7 +516,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd
float3 eval = bsdf_eval(kg, sd, sc, omega_in, &bsdf_pdf);
if(bsdf_pdf != 0.0f) {
bsdf_eval_accum(result_eval, sc->type, eval*sc->weight);
bsdf_eval_accum(result_eval, sc->type, eval*sc->weight, 1.0f);
sum_pdf += bsdf_pdf*sc->sample_weight;
}
@ -544,7 +544,8 @@ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg,
float mis_weight = use_mis? power_heuristic(light_pdf, bsdf_pdf): 1.0f;
bsdf_eval_accum(result_eval,
sc->type,
eval * sc->weight * mis_weight);
eval * sc->weight,
mis_weight);
}
}
}
@ -576,7 +577,7 @@ void shader_bsdf_eval(KernelGlobals *kg,
_shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, -1, eval, 0.0f, 0.0f);
if(use_mis) {
float weight = power_heuristic(light_pdf, pdf);
bsdf_eval_mul(eval, weight);
bsdf_eval_mis(eval, weight);
}
}
}
@ -944,7 +945,7 @@ ccl_device_inline void _shader_volume_phase_multi_eval(const ShaderData *sd, con
float3 eval = volume_phase_eval(sd, sc, omega_in, &phase_pdf);
if(phase_pdf != 0.0f) {
bsdf_eval_accum(result_eval, sc->type, eval);
bsdf_eval_accum(result_eval, sc->type, eval, 1.0f);
sum_pdf += phase_pdf*sc->sample_weight;
}

View File

@ -128,6 +128,7 @@ ccl_device bool shadow_blocked_opaque(KernelGlobals *kg,
ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg,
ShaderData *shadow_sd,
ccl_addr_space PathState *state,
const int skip_object,
Ray *ray,
Intersection *hits,
uint max_hits,
@ -140,6 +141,7 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg,
const bool blocked = scene_intersect_shadow_all(kg,
ray,
hits,
skip_object,
max_hits,
&num_hits);
/* If no opaque surface found but we did find transparent hits,
@ -216,6 +218,7 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg,
ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg,
ShaderData *shadow_sd,
ccl_addr_space PathState *state,
const int skip_object,
Ray *ray,
uint max_hits,
float3 *shadow)
@ -250,6 +253,7 @@ ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg,
return shadow_blocked_transparent_all_loop(kg,
shadow_sd,
state,
skip_object,
ray,
hits,
max_hits,
@ -274,13 +278,14 @@ ccl_device bool shadow_blocked_transparent_stepped_loop(
KernelGlobals *kg,
ShaderData *shadow_sd,
ccl_addr_space PathState *state,
const int skip_object,
Ray *ray,
Intersection *isect,
const bool blocked,
const bool is_transparent_isect,
float3 *shadow)
{
if(blocked && is_transparent_isect) {
if((blocked && is_transparent_isect) || skip_object != OBJECT_NONE) {
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
float3 Pend = ray->P + ray->D*ray->t;
int bounce = state->transparent_bounce;
@ -306,6 +311,23 @@ ccl_device bool shadow_blocked_transparent_stepped_loop(
{
break;
}
#ifdef __SHADOW_TRICKS__
if(skip_object != OBJECT_NONE) {
const int isect_object = (isect->object == PRIM_NONE)
? kernel_tex_fetch(__prim_object, isect->prim)
: isect->object;
if(isect_object == skip_object) {
shader_setup_from_ray(kg, shadow_sd, isect, ray);
/* Move ray forward. */
ray->P = ray_offset(shadow_sd->P, -shadow_sd->Ng);
if(ray->t != FLT_MAX) {
ray->D = normalize_len(Pend - ray->P, &ray->t);
}
bounce++;
continue;
}
}
#endif
if(!shader_transparent_shadow(kg, isect)) {
return true;
}
@ -351,22 +373,31 @@ ccl_device bool shadow_blocked_transparent_stepped(
KernelGlobals *kg,
ShaderData *shadow_sd,
ccl_addr_space PathState *state,
const int skip_object,
Ray *ray,
Intersection *isect,
float3 *shadow)
{
const bool blocked = scene_intersect(kg,
*ray,
PATH_RAY_SHADOW_OPAQUE,
isect,
NULL,
0.0f, 0.0f);
const bool is_transparent_isect = blocked
? shader_transparent_shadow(kg, isect)
: false;
bool blocked, is_transparent_isect;
if (skip_object == OBJECT_NONE) {
blocked = scene_intersect(kg,
*ray,
PATH_RAY_SHADOW_OPAQUE,
isect,
NULL,
0.0f, 0.0f);
is_transparent_isect = blocked
? shader_transparent_shadow(kg, isect)
: false;
}
else {
blocked = false;
is_transparent_isect = false;
}
return shadow_blocked_transparent_stepped_loop(kg,
shadow_sd,
state,
skip_object,
ray,
isect,
blocked,
@ -390,12 +421,21 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg,
if(ray->t == 0.0f) {
return false;
}
#ifdef __SHADOW_TRICKS__
const int skip_object = state->catcher_object;
#else
const int skip_object = OBJECT_NONE;
#endif
/* Do actual shadow shading. */
/* First of all, we check if integrator requires transparent shadows.
* if not, we use simplest and fastest ever way to calculate occlusion.
*
* NOTE: We can't do quick opaque test here if we are on shadow-catcher
* path because we don't want catcher object to be casting shadow here.
*/
#ifdef __TRANSPARENT_SHADOWS__
if(!kernel_data.integrator.transparent_shadows)
if(!kernel_data.integrator.transparent_shadows &&
skip_object == OBJECT_NONE)
#endif
{
return shadow_blocked_opaque(kg,
@ -440,6 +480,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg,
return shadow_blocked_transparent_stepped_loop(kg,
shadow_sd,
state,
skip_object,
ray,
&isect,
blocked,
@ -450,6 +491,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg,
return shadow_blocked_transparent_all(kg,
shadow_sd,
state,
skip_object,
ray,
max_hits,
shadow);
@ -458,6 +500,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg,
return shadow_blocked_transparent_stepped(kg,
shadow_sd,
state,
skip_object,
ray,
&isect,
shadow);

View File

@ -158,6 +158,10 @@ CCL_NAMESPACE_BEGIN
#define __CLAMP_SAMPLE__
#define __PATCH_EVAL__
#ifndef __SPLIT_KERNEL__
# define __SHADOW_TRICKS__
#endif
#ifdef __KERNEL_SHADING__
# define __SVM__
# define __EMISSION__
@ -316,6 +320,8 @@ enum PathRayFlag {
PATH_RAY_MIS_SKIP = 4096,
PATH_RAY_DIFFUSE_ANCESTOR = 8192,
PATH_RAY_SINGLE_PASS_DONE = 16384,
PATH_RAY_SHADOW_CATCHER = 32768,
PATH_RAY_SHADOW_CATCHER_ONLY = 65536,
};
/* Closure Label */
@ -445,6 +451,20 @@ typedef ccl_addr_space struct PathRadiance {
float4 shadow;
float mist;
#endif
#ifdef __SHADOW_TRICKS__
/* Total light reachable across the path, ignoring shadow blocked queries. */
float3 path_total;
/* Total light reachable across the path with shadow blocked queries
* applied here.
*
* Dividing this figure by path_total will give estimate of shadow pass.
*/
float3 path_total_shaded;
/* Color of the background on which shadow is alpha-overed. */
float3 shadow_color;
#endif
} PathRadiance;
typedef struct BsdfEval {
@ -460,6 +480,9 @@ typedef struct BsdfEval {
float3 subsurface;
float3 scatter;
#endif
#ifdef __SHADOW_TRICKS__
float3 sum_no_mis;
#endif
} BsdfEval;
/* Shader Flag */
@ -805,13 +828,16 @@ enum ShaderDataObjectFlag {
SD_OBJECT_INTERSECTS_VOLUME = (1 << 5),
/* Has position for motion vertices. */
SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6),
/* object is used to catch shadows */
SD_OBJECT_SHADOW_CATCHER = (1 << 7),
SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK |
SD_OBJECT_MOTION |
SD_OBJECT_TRANSFORM_APPLIED |
SD_OBJECT_NEGATIVE_SCALE_APPLIED |
SD_OBJECT_HAS_VOLUME |
SD_OBJECT_INTERSECTS_VOLUME)
SD_OBJECT_INTERSECTS_VOLUME |
SD_OBJECT_SHADOW_CATCHER)
};
typedef ccl_addr_space struct ShaderData {
@ -930,6 +956,10 @@ typedef struct PathState {
RNG rng_congruential;
VolumeStack volume_stack[VOLUME_STACK_SIZE];
#endif
#ifdef __SHADOW_TRICKS__
int catcher_object;
#endif
} PathState;
/* Subsurface */

View File

@ -70,7 +70,7 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg)
#ifdef __BACKGROUND__
/* sample background shader */
float3 L_background = indirect_background(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, ray);
path_radiance_accum_background(L, (*throughput), L_background, state->bounce);
path_radiance_accum_background(L, state, (*throughput), L_background);
#endif
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
}

View File

@ -49,6 +49,8 @@ NODE_DEFINE(Object)
SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
return type;
}
@ -597,6 +599,12 @@ void ObjectManager::device_update_flags(Device *device,
else {
object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME;
}
if(object->is_shadow_catcher) {
object_flag[object_index] |= SD_OBJECT_SHADOW_CATCHER;
}
else {
object_flag[object_index] &= ~SD_OBJECT_SHADOW_CATCHER;
}
if(bounds_valid) {
foreach(Object *volume_object, volume_objects) {

View File

@ -53,6 +53,7 @@ public:
bool use_motion;
bool hide_on_missing_motion;
bool use_holdout;
bool is_shadow_catcher;
float3 dupli_generated;
float2 dupli_uv;