Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2017-02-09 16:19:01 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2017-03-27 11:46:03 +0300
commitd14e39622ae627c1a4329e630715c5197c762493 (patch)
treed246f7083bcc82236488d5aaec25cb2e735c4145 /intern
parent5aaa643947929cf807c349b2b5fe33d4dc669c3d (diff)
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.
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/blender/addon/properties.py6
-rw-r--r--intern/cycles/blender/addon/ui.py3
-rw-r--r--intern/cycles/blender/blender_object.cpp7
-rw-r--r--intern/cycles/kernel/bvh/bvh.h51
-rw-r--r--intern/cycles/kernel/bvh/bvh_shadow_all.h14
-rw-r--r--intern/cycles/kernel/bvh/qbvh_shadow_all.h11
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h124
-rw-r--r--intern/cycles/kernel/kernel_emission.h7
-rw-r--r--intern/cycles/kernel/kernel_path.h44
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h40
-rw-r--r--intern/cycles/kernel/kernel_path_state.h4
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h30
-rw-r--r--intern/cycles/kernel/kernel_shader.h9
-rw-r--r--intern/cycles/kernel/kernel_shadow.h65
-rw-r--r--intern/cycles/kernel/kernel_types.h32
-rw-r--r--intern/cycles/kernel/split/kernel_indirect_background.h2
-rw-r--r--intern/cycles/render/object.cpp8
-rw-r--r--intern/cycles/render/object.h1
18 files changed, 411 insertions, 47 deletions
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_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, float3 throughput, float3 value, int bounce)
+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;