Skip to content
Permalink
Browse files

Cycles: Added Shadow terminator offset.

This copies the approach taken by the Appleseed renderer. A per-object
factor that pushes the shadow terminator in the BSDF towards the light
source.
  • Loading branch information
skwerner committed Nov 27, 2019
1 parent 4fd99c9 commit 5de4c6371d8f772e04e6c0383dfd8f1be6a29bd1
@@ -1138,6 +1138,13 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
default=1.0,
)

terminator_offset: FloatProperty(
name="Shadow Termiantor Offset",
description="Push the shadow terminator towards the light to hide artifacts on low poly geometry",
min=0.0, max=1.0,
default=0.0,
)

is_shadow_catcher: BoolProperty(
name="Shadow Catcher",
description="Only render shadows on this object, for compositing renders into real footage",
@@ -1212,8 +1212,11 @@ def draw(self, context):
col = flow.column()
col.prop(ob, "hide_select", text="Selectable", invert_checkbox=True, toggle=False)

cob = ob.cycles
col = flow.column()
col.prop(cob, "terminator_offset")

if has_geometry_visibility(ob):
cob = ob.cycles
col = flow.column()
col.prop(cob, "is_shadow_catcher")
col = flow.column()
@@ -430,6 +430,12 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
object_updated = true;
}

float terminator_offset = get_float(cobject, "terminator_offset");
if (terminator_offset != object->terminator_offset) {
object->terminator_offset = terminator_offset;
object_updated = true;
}

/* sync the asset name for Cryptomatte */
BL::Object parent = b_ob.parent();
ustring parent_name;
@@ -95,6 +95,34 @@ ccl_device_inline float bump_shadowing_term(float3 Ng, float3 N, float3 I)
return -g2 * g + g2 + g;
}

/* Another shadow terminator fix, this time taken from Appleseed.
* Original code is unter the MIT License
* Copyright (c) 2019 Francois Beaune, The appleseedhq Organization */
ccl_device_inline float shift_cos_in(const float cos_in, const float correction_factor)
{
assert(std::abs(cos_in) <= 1.0f);
assert(correction_factor >= 0.0f && correction_factor < 1.0f);

if (correction_factor == 0.0f)
return cos_in;

const float angle = fast_acosf(cos_in);
const float frequency_multiplier = 1.0f / (1.0f - correction_factor);
return max(cosf(angle * frequency_multiplier), 0.0f);
}

ccl_device_inline float shift_cos_in_fast(const float cos_in, const float frequency_multiplier)
{
assert(fabsf(cos_in) <= 1.0f);
assert(frequency_multiplier >= 1.0f);

if (frequency_multiplier == 1.0f)
return cos_in;

const float angle = fast_acosf(cos_in);
return max(cosf(angle * frequency_multiplier), 0.0f);
}

ccl_device_inline int bsdf_sample(KernelGlobals *kg,
ShaderData *sd,
const ShaderClosure *sc,
@@ -450,6 +478,12 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
if (!isequal_float3(sc->N, sd->N)) {
*eval *= bump_shadowing_term((label & LABEL_TRANSMIT) ? -sd->N : sd->N, sc->N, *omega_in);
}
if (!(label & LABEL_TRANSMIT) && !isequal_float3(sd->Ng, sd->N)) {
const float frequency_multiplier = kernel_tex_fetch(__objects, sd->object).terminator_offset;
if(frequency_multiplier > 0.0f) {
*eval *= shift_cos_in_fast(dot(*omega_in, sd->N), frequency_multiplier);
}
}
}

return label;
@@ -566,6 +600,12 @@ ccl_device_inline
if (!isequal_float3(sc->N, sd->N)) {
eval *= bump_shadowing_term(sd->N, sc->N, omega_in);
}
if (!isequal_float3(sd->Ng, sd->N)) {
const float frequency_multiplier = kernel_tex_fetch(__objects, sd->object).terminator_offset;
if(frequency_multiplier > 0.0f) {
eval *= shift_cos_in_fast(dot(omega_in, sd->N), frequency_multiplier);
}
}
}
}
else {
@@ -657,6 +697,12 @@ ccl_device_inline
if (!isequal_float3(sc->N, sd->N)) {
eval *= bump_shadowing_term(-sd->N, sc->N, omega_in);
}
if (isequal_float3(sd->Ng, sd->N)) {
const float frequency_multiplier = kernel_tex_fetch(__objects, sd->object).terminator_offset;
if(frequency_multiplier > 0.0f) {
eval *= shift_cos_in_fast(dot(omega_in, -sd->N), frequency_multiplier);
}
}
}
}

@@ -1459,6 +1459,9 @@ typedef struct KernelObject {

float cryptomatte_object;
float cryptomatte_asset;

float terminator_offset;
float pad1, pad2, pad3;
} KernelObject;
static_assert_align(KernelObject, 16);

@@ -98,6 +98,7 @@ 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_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
SOCKET_FLOAT(terminator_offset, "Terminator Offset", 0.0f);

SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);

@@ -497,6 +498,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
kobject.cryptomatte_object = util_hash_to_float(hash_name);
kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
kobject.terminator_offset = 1.0f / (1.0f - ob->terminator_offset);

/* Object flag. */
if (ob->use_holdout) {
@@ -59,6 +59,7 @@ class Object : public Node {
bool hide_on_missing_motion;
bool use_holdout;
bool is_shadow_catcher;
float terminator_offset;

float3 dupli_generated;
float2 dupli_uv;

0 comments on commit 5de4c63

Please sign in to comment.
You can’t perform that action at this time.