diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 6c5bcf09305..cbf469b3a89 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -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 diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index c7b9b21e935..6136fc1ec06 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -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""" diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 637cf7abda8..968861391a2 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -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 */ diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index 598e138dbea..1358288f832 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -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__ */ diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index 8f7c005e961..b2555b3a6bb 100644 --- a/intern/cycles/kernel/bvh/bvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -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); } diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index 5d960787134..1663e23c334 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -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 diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index c589c112cc2..823d30dde78 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -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 diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index cf14a159e47..9e7d51f23f5 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -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) { diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index ebf03ad9778..74631aa98cf 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -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); diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index d58960cae4e..a2d4e347d9d 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -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); diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h index 661dc52fb31..e85f7dc06bd 100644 --- a/intern/cycles/kernel/kernel_path_state.h +++ b/intern/cycles/kernel/kernel_path_state.h @@ -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) diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h index efa23038089..d6bfe9be5f1 100644 --- a/intern/cycles/kernel/kernel_path_surface.h +++ b/intern/cycles/kernel/kernel_path_surface.h @@ -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 diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 93a92c63a40..5d942de34a2 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -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; } diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index 4efc6c8118d..0426e0a62c9 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -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); diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 245832ae163..60bb7b7a882 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -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 */ diff --git a/intern/cycles/kernel/split/kernel_indirect_background.h b/intern/cycles/kernel/split/kernel_indirect_background.h index 100f5996f83..8192528622e 100644 --- a/intern/cycles/kernel/split/kernel_indirect_background.h +++ b/intern/cycles/kernel/split/kernel_indirect_background.h @@ -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); } diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 8342f376836..a3a8c6d68e4 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -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) { diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 3495849d149..dabe0f71662 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -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;