Cycles: Add option to control smoothing when using bump map

Cycles implements the "Taming the Shadow Terminator" paper by Matt Jen-Yuan
Chiang to solve shadow terminator issues when a bump map is applied, as well
as similar approach for the glossy reflection to ensure ray does not get
reflected to inside of the object.

This correction term is applied unconditionally, which makes it harder to have
full control over shading via normals for stylistic reasons.

This change exposes this corrective term as an option called "Bump Map
Correction" which is available in the shader settings next to the
"Transparent Shadows".

The reason to make it per-shader rather than per-object is to allow flexibility
of a control: it is possible that an object has multiple shaders attached to it,
and only some of them used for bump mapping. Another, and possibly stronger
reason to have it per-shader is ease of assets control: shader brings settings
which are needed for its proper behavior. So if material at some point
decides to take over normals, artists would not need to update settings on
every asset which uses that material.

The option is enabled by default, so there is no changes for existing setups.

Pull Request: https://projects.blender.org/blender/blender/pulls/113480
This commit is contained in:
Sergey Sharybin
2023-10-11 15:07:21 +02:00
committed by Sergey Sharybin
parent 82d86cbd8c
commit 36e603c430
9 changed files with 20 additions and 3 deletions

View File

@@ -1019,6 +1019,11 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
"disabling will render faster but not give accurate shadows",
default=True,
)
use_bump_map_correction: BoolProperty(
name="Bump Map Correction",
description="Apply corrections to solve shadow terminator artifacts caused by bump mapping",
default=True,
)
homogeneous_volume: BoolProperty(
name="Homogeneous Volume",
description="When using volume rendering, assume volume has the same density everywhere "

View File

@@ -1967,6 +1967,7 @@ class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel):
col.prop(cmat, "displacement_method", text="Displacement")
col.prop(cmat, "emission_sampling")
col.prop(cmat, "use_transparent_shadow")
col.prop(cmat, "use_bump_map_correction")
def draw(self, context):
self.draw_shared(self, context.material)

View File

@@ -1551,6 +1551,7 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles");
shader->set_emission_sampling_method(get_emission_sampling(cmat));
shader->set_use_transparent_shadow(get_boolean(cmat, "use_transparent_shadow"));
shader->set_use_bump_map_correction(get_boolean(cmat, "use_bump_map_correction"));
shader->set_heterogeneous_volume(!get_boolean(cmat, "homogeneous_volume"));
shader->set_volume_sampling_method(get_volume_sampling(cmat));
shader->set_volume_interpolation_method(get_volume_interpolation(cmat));

View File

@@ -233,7 +233,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
*eval *= shift_cos_in(cosNO, frequency_multiplier);
}
if (label & LABEL_DIFFUSE) {
if (!isequal(sc->N, sd->N)) {
if ((sd->flag & SD_USE_BUMP_MAP_CORRECTION) && !isequal(sc->N, sd->N)) {
*eval *= bump_shadowing_term(sd->N, sc->N, *wo);
}
}
@@ -521,7 +521,7 @@ ccl_device_inline
}
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
if (!isequal(sc->N, sd->N)) {
if ((sd->flag & SD_USE_BUMP_MAP_CORRECTION) && !isequal(sc->N, sd->N)) {
eval *= bump_shadowing_term(sd->N, sc->N, wo);
}
}

View File

@@ -191,6 +191,9 @@ ccl_device float3 ensure_valid_specular_reflection(float3 Ng, float3 I, float3 N
* normal and the shading normal is the same. */
ccl_device float3 maybe_ensure_valid_specular_reflection(ccl_private ShaderData *sd, float3 N)
{
if ((sd->flag & SD_USE_BUMP_MAP_CORRECTION) == 0) {
return N;
}
if ((sd->type & PRIMITIVE_CURVE) || isequal(sd->Ng, N)) {
return N;
}

View File

@@ -492,7 +492,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
/* Update path state */
if (!(label & LABEL_TRANSPARENT)) {
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = mis_pdf;
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = sd->N;
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = sc->N;
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
unguided_bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
}

View File

@@ -831,6 +831,8 @@ enum ShaderDataFlag {
/* Shader flags. */
/* Apply a correction term to smooth illumination on grazing angles when using bump mapping.. */
SD_USE_BUMP_MAP_CORRECTION = (1 << 15),
/* Use front side for direct light sampling. */
SD_MIS_FRONT = (1 << 16),
/* Has transparent shadow. */

View File

@@ -54,6 +54,7 @@ NODE_DEFINE(Shader)
EMISSION_SAMPLING_AUTO);
SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true);
SOCKET_BOOLEAN(use_bump_map_correction, "Bump Map Correction", true);
SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true);
static NodeEnum volume_sampling_method_enum;
@@ -581,6 +582,9 @@ void ShaderManager::device_update_common(Device * /*device*/,
if (shader->get_displacement_method() != DISPLACE_BUMP) {
flag |= SD_HAS_DISPLACEMENT;
}
if (shader->get_use_bump_map_correction()) {
flag |= SD_USE_BUMP_MAP_CORRECTION;
}
/* constant emission check */
if (shader->emission_is_constant) {

View File

@@ -77,6 +77,7 @@ class Shader : public Node {
/* sampling */
NODE_SOCKET_API(EmissionSampling, emission_sampling_method)
NODE_SOCKET_API(bool, use_transparent_shadow)
NODE_SOCKET_API(bool, use_bump_map_correction)
NODE_SOCKET_API(bool, heterogeneous_volume)
NODE_SOCKET_API(VolumeSampling, volume_sampling_method)
NODE_SOCKET_API(int, volume_interpolation_method)