From 6d0b5e2ace9830eace00fb2eeee080116b8c2e6d Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Mon, 6 Nov 2023 15:45:00 +0100 Subject: [PATCH] EEVEE-Next: New shadow settings Remove `Material > Shadow Mode` and use `Object > Shadow Ray Visibility` and `Material > Transparent Shadows` instead. The versioning system auto-updates objects/materials in EEVEE scenes so their behavior is as close as possible to the previous one. Update Cycles to use the native `use_transparent_shadow` property. Note: Material changes don't set any `recalc` flag on the objects that use them, so the EEVEE Next shadow maps don't update when changing settings/nodes. Fixing this issue is required for 4.1, but it's out of the scope of this PR. Pull Request: https://projects.blender.org/blender/blender/pulls/113980 --- intern/cycles/blender/addon/properties.py | 6 -- intern/cycles/blender/addon/ui.py | 2 +- intern/cycles/blender/shader.cpp | 2 +- scripts/startup/bl_ui/properties_material.py | 2 +- scripts/startup/bl_ui/properties_object.py | 5 ++ .../blender/blenkernel/BKE_blender_version.h | 2 +- .../blenloader/intern/versioning_400.cc | 59 +++++++++++++++++++ .../draw/engines/eevee_next/eevee_material.hh | 13 ++-- .../draw/engines/eevee_next/eevee_shader.cc | 14 +++-- .../draw/engines/eevee_next/eevee_shadow.cc | 5 +- .../draw/engines/eevee_next/eevee_shadow.hh | 4 +- .../draw/engines/eevee_next/eevee_sync.cc | 17 ++---- .../blender/makesdna/DNA_material_defaults.h | 2 + source/blender/makesdna/DNA_material_types.h | 1 + .../blender/makesrna/intern/rna_material.cc | 9 +++ 15 files changed, 108 insertions(+), 35 deletions(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 7ddbb90b35a..8cbfc0a98b9 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1013,12 +1013,6 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup): default="AUTO", ) - use_transparent_shadow: BoolProperty( - name="Transparent Shadows", - description="Use transparent shadows for this material if it contains a Transparent BSDF, " - "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", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 749d32cc52a..01c88272944 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1966,7 +1966,7 @@ class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel): col = layout.column() col.prop(cmat, "displacement_method", text="Displacement") col.prop(cmat, "emission_sampling") - col.prop(cmat, "use_transparent_shadow") + col.prop(mat, "use_transparent_shadow") col.prop(cmat, "use_bump_map_correction") def draw(self, context): diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index 7e131ea9749..7c8c63299a5 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -1550,7 +1550,7 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) /* settings */ 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_transparent_shadow(b_mat.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)); diff --git a/scripts/startup/bl_ui/properties_material.py b/scripts/startup/bl_ui/properties_material.py index fb6957b2e37..74f7b3d0407 100644 --- a/scripts/startup/bl_ui/properties_material.py +++ b/scripts/startup/bl_ui/properties_material.py @@ -300,7 +300,7 @@ class EEVEE_NEXT_MATERIAL_PT_settings_surface(MaterialButtonsPanel, Panel): col.prop(mat, "use_backface_culling_shadow", text="Shadow") # TODO(fclem): Displacement option - # TODO(fclem): Transparent shadow option + layout.prop(mat, "use_transparent_shadow") col = layout.column() col.prop(mat, "surface_render_method", text="Render Method") diff --git a/scripts/startup/bl_ui/properties_object.py b/scripts/startup/bl_ui/properties_object.py index 900543c5585..095f0285ab6 100644 --- a/scripts/startup/bl_ui/properties_object.py +++ b/scripts/startup/bl_ui/properties_object.py @@ -390,6 +390,11 @@ class OBJECT_PT_visibility(ObjectButtonsPanel, Panel): col.prop(ob, "hide_render", text="Renders", toggle=False, invert_checkbox=True) if context.engine == 'BLENDER_EEVEE_NEXT': + if ob.type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'CURVES', 'POINTCLOUD', 'VOLUME'}: + layout.separator() + col = layout.column(heading="Ray Visibility") + col.prop(ob, "visible_shadow", text="Shadow", toggle=False) + if ob.type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'CURVES', 'POINTCLOUD', 'VOLUME', 'LIGHT'}: layout.separator() col = layout.column(heading="Light Probes") diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 238f9e57d08..8fbe1acd022 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -29,7 +29,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 4 +#define BLENDER_FILE_SUBVERSION 5 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index d39a370b112..eed551712d5 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -47,11 +47,13 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_attribute.h" +#include "BKE_collection.h" #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_grease_pencil.hh" #include "BKE_idprop.hh" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_mesh_legacy_convert.hh" #include "BKE_node.hh" #include "BKE_node_runtime.hh" @@ -298,6 +300,30 @@ static void version_principled_bsdf_update_animdata(ID *owner_id, bNodeTree *ntr } } +static void versioning_eevee_shadow_settings(Object *object) +{ + /** EEVEE no longer uses the Material::blend_shadow property. + * Instead, it uses Object::visibility_flag for disabling shadow casting + */ + + short *material_len = BKE_object_material_len_p(object); + if (!material_len) { + return; + } + + using namespace blender; + bool hide_shadows = *material_len > 0; + for (int i : IndexRange(*material_len)) { + Material *material = BKE_object_material_get(object, i + 1); + if (!material || material->blend_shadow != MA_BS_NONE) { + hide_shadows = false; + } + } + + /* Enable the hide_shadow flag only if there's not any shadow casting material. */ + SET_FLAG_FROM_TEST(object->visibility_flag, hide_shadows, OB_HIDE_SHADOW); +} + void do_versions_after_linking_400(FileData *fd, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 9)) { @@ -382,6 +408,16 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain) BKE_mesh_legacy_face_map_to_generic(bmain); } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 401, 5)) { + Scene *scene = static_cast(bmain->scenes.first); + bool is_cycles = scene && STREQ(scene->r.engine, RE_engine_id_CYCLES); + if (!is_cycles) { + LISTBASE_FOREACH (Object *, object, &bmain->objects) { + versioning_eevee_shadow_settings(object); + } + } + } + /** * Versioning code until next subversion bump goes here. * @@ -1783,6 +1819,29 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 401, 5)) { + /* Unify Material::blend_shadow and Cycles.use_transparent_shadows into the + * Material::blend_flag. */ + Scene *scene = static_cast(bmain->scenes.first); + bool is_cycles = scene && STREQ(scene->r.engine, RE_engine_id_CYCLES); + if (is_cycles) { + LISTBASE_FOREACH (Material *, material, &bmain->materials) { + bool transparent_shadows = true; + if (IDProperty *cmat = version_cycles_properties_from_ID(&material->id)) { + transparent_shadows = version_cycles_property_boolean( + cmat, "use_transparent_shadow", true); + } + SET_FLAG_FROM_TEST(material->blend_flag, transparent_shadows, MA_BL_TRANSPARENT_SHADOW); + } + } + else { + LISTBASE_FOREACH (Material *, material, &bmain->materials) { + bool transparent_shadow = material->blend_shadow != MA_BS_SOLID; + SET_FLAG_FROM_TEST(material->blend_flag, transparent_shadow, MA_BL_TRANSPARENT_SHADOW); + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/draw/engines/eevee_next/eevee_material.hh b/source/blender/draw/engines/eevee_next/eevee_material.hh index 439d8cb31a8..27c0c189fc9 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.hh +++ b/source/blender/draw/engines/eevee_next/eevee_material.hh @@ -69,19 +69,24 @@ enum eMaterialProbe { static inline void material_type_from_shader_uuid(uint64_t shader_uuid, eMaterialPipeline &pipeline_type, - eMaterialGeometry &geometry_type) + eMaterialGeometry &geometry_type, + bool &transparent_shadows) { const uint64_t geometry_mask = ((1u << 4u) - 1u); const uint64_t pipeline_mask = ((1u << 4u) - 1u); geometry_type = static_cast(shader_uuid & geometry_mask); pipeline_type = static_cast((shader_uuid >> 4u) & pipeline_mask); + transparent_shadows = (shader_uuid >> 8u) & 1u; } static inline uint64_t shader_uuid_from_material_type(eMaterialPipeline pipeline_type, - eMaterialGeometry geometry_type) + eMaterialGeometry geometry_type, + char blend_flags) { BLI_assert(geometry_type < (1 << 4)); - return geometry_type | (pipeline_type << 4); + BLI_assert(pipeline_type < (1 << 4)); + uchar transparent_shadows = blend_flags & MA_BL_TRANSPARENT_SHADOW ? 1 : 0; + return geometry_type | (pipeline_type << 4) | (transparent_shadows << 8); } ENUM_OPERATORS(eClosureBits, CLOSURE_AMBIENT_OCCLUSION) @@ -142,7 +147,7 @@ struct MaterialKey { MaterialKey(::Material *mat_, eMaterialGeometry geometry, eMaterialPipeline pipeline) : mat(mat_) { - options = shader_uuid_from_material_type(pipeline, geometry); + options = shader_uuid_from_material_type(pipeline, geometry, mat_->blend_flag); } uint64_t hash() const diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index d44e97fd485..4f8d9c3dca4 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -311,7 +311,8 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu eMaterialPipeline pipeline_type; eMaterialGeometry geometry_type; - material_type_from_shader_uuid(shader_uuid, pipeline_type, geometry_type); + bool transparent_shadows; + material_type_from_shader_uuid(shader_uuid, pipeline_type, geometry_type, transparent_shadows); GPUCodegenOutput &codegen = *codegen_; ShaderCreateInfo &info = *reinterpret_cast(codegen.create_info); @@ -356,7 +357,9 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu } if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) { - info.define("MAT_TRANSPARENT"); + if (pipeline_type != MAT_PIPE_SHADOW || transparent_shadows) { + info.define("MAT_TRANSPARENT"); + } /* Transparent material do not have any velocity specific pipeline. */ if (pipeline_type == MAT_PIPE_PREPASS_FORWARD_VELOCITY) { pipeline_type = MAT_PIPE_PREPASS_FORWARD; @@ -641,7 +644,8 @@ GPUMaterial *ShaderModule::material_shader_get(::Material *blender_mat, { bool is_volume = ELEM(pipeline_type, MAT_PIPE_VOLUME_MATERIAL, MAT_PIPE_VOLUME_OCCUPANCY); - uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type); + uint64_t shader_uuid = shader_uuid_from_material_type( + pipeline_type, geometry_type, blender_mat->blend_flag); return DRW_shader_from_material( blender_mat, nodetree, shader_uuid, is_volume, deferred_compilation, codegen_callback, this); @@ -656,7 +660,7 @@ GPUMaterial *ShaderModule::world_shader_get(::World *blender_world, eMaterialGeometry geometry_type = is_volume ? MAT_GEOM_VOLUME_WORLD : MAT_GEOM_WORLD; - uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type); + uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type, 0); return DRW_shader_from_world( blender_world, nodetree, shader_uuid, is_volume, defer_compilation, codegen_callback, this); @@ -671,7 +675,7 @@ GPUMaterial *ShaderModule::material_shader_get(const char *name, eMaterialGeometry geometry_type, bool is_lookdev) { - uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type); + uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type, 0); bool is_volume = ELEM(pipeline_type, MAT_PIPE_VOLUME_MATERIAL, MAT_PIPE_VOLUME_OCCUPANCY); diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 66df398a22b..60639f7878b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -893,11 +893,12 @@ void ShadowModule::begin_sync() } } -void ShadowModule::sync_object(const ObjectHandle &handle, +void ShadowModule::sync_object(const Object *ob, + const ObjectHandle &handle, const ResourceHandle &resource_handle, - bool is_shadow_caster, bool is_alpha_blend) { + bool is_shadow_caster = !(ob->visibility_flag & OB_HIDE_SHADOW); if (!is_shadow_caster && !is_alpha_blend) { return; } diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.hh b/source/blender/draw/engines/eevee_next/eevee_shadow.hh index 81a88e54975..4808df6d01e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.hh @@ -328,9 +328,9 @@ class ShadowModule { void begin_sync(); /** Register a shadow caster or receiver. */ - void sync_object(const ObjectHandle &handle, + void sync_object(const Object *ob, + const ObjectHandle &handle, const ResourceHandle &resource_handle, - bool is_shadow_caster, bool is_alpha_blend); void end_sync(); diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc index 5b179c963c4..4184c99b4bf 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -140,7 +140,6 @@ void SyncModule::sync_mesh(Object *ob, return; } - bool is_shadow_caster = false; bool is_alpha_blend = false; for (auto i : material_array.gpu_materials.index_range()) { GPUBatch *geom = mat_geom[i]; @@ -173,7 +172,6 @@ void SyncModule::sync_mesh(Object *ob, geometry_call(material.reflection_probe_prepass.sub_pass, geom, res_handle); geometry_call(material.reflection_probe_shading.sub_pass, geom, res_handle); - is_shadow_caster = is_shadow_caster || material.shadow.sub_pass != nullptr; is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent; ::Material *mat = GPU_material_get_material(gpu_material); @@ -182,7 +180,7 @@ void SyncModule::sync_mesh(Object *ob, inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials); - inst_.shadows.sync_object(ob_handle, res_handle, is_shadow_caster, is_alpha_blend); + inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend); inst_.cryptomatte.sync_object(ob, res_handle); } @@ -215,7 +213,6 @@ bool SyncModule::sync_sculpt(Object *ob, bool has_motion = false; MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion); - bool is_shadow_caster = false; bool is_alpha_blend = false; for (SculptBatch &batch : sculpt_batches_per_material_get(ob_ref.object, material_array.gpu_materials)) @@ -249,7 +246,6 @@ bool SyncModule::sync_sculpt(Object *ob, geometry_call(material.reflection_probe_prepass.sub_pass, geom, res_handle); geometry_call(material.reflection_probe_shading.sub_pass, geom, res_handle); - is_shadow_caster = is_shadow_caster || material.shadow.sub_pass != nullptr; is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent; GPUMaterial *gpu_material = material_array.gpu_materials[batch.material_slot]; @@ -259,7 +255,7 @@ bool SyncModule::sync_sculpt(Object *ob, inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials); - inst_.shadows.sync_object(ob_handle, res_handle, is_shadow_caster, is_alpha_blend); + inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend); inst_.cryptomatte.sync_object(ob, res_handle); return true; @@ -322,9 +318,8 @@ void SyncModule::sync_point_cloud(Object *ob, ::Material *mat = GPU_material_get_material(gpu_material); inst_.cryptomatte.sync_material(mat); - bool is_caster = material.shadow.sub_pass != nullptr; bool is_alpha_blend = material.is_alpha_blend_transparent; - inst_.shadows.sync_object(ob_handle, res_handle, is_caster, is_alpha_blend); + inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend); } /** \} */ @@ -486,9 +481,8 @@ void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandl gpencil_drawcall_flush(iter); - bool is_caster = true; /* TODO material.shadow.sub_pass. */ bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */ - inst_.shadows.sync_object(ob_handle, res_handle, is_caster, is_alpha_blend); + inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend); } /** \} */ @@ -557,9 +551,8 @@ void SyncModule::sync_curves(Object *ob, ::Material *mat = GPU_material_get_material(gpu_material); inst_.cryptomatte.sync_material(mat); - bool is_caster = material.shadow.sub_pass != nullptr; bool is_alpha_blend = material.is_alpha_blend_transparent; - inst_.shadows.sync_object(ob_handle, res_handle, is_caster, is_alpha_blend); + inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend); } /** \} */ diff --git a/source/blender/makesdna/DNA_material_defaults.h b/source/blender/makesdna/DNA_material_defaults.h index 1681d732d60..83dcff68efb 100644 --- a/source/blender/makesdna/DNA_material_defaults.h +++ b/source/blender/makesdna/DNA_material_defaults.h @@ -33,6 +33,8 @@ .alpha_threshold = 0.5f, \ \ .blend_shadow = MA_BS_SOLID, \ + \ + .blend_flag = MA_BL_TRANSPARENT_SHADOW,\ \ .lineart.mat_occlusion = 1, \ } diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 57b3c5e0324..159c34335ea 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -360,6 +360,7 @@ enum { MA_BL_TRANSLUCENCY = (1 << 3), MA_BL_LIGHTPROBE_VOLUME_DOUBLE_SIDED = (1 << 4), MA_BL_CULL_BACKFACE_SHADOW = (1 << 5), + MA_BL_TRANSPARENT_SHADOW = (1 << 6), }; /** #Material::blend_shadow */ diff --git a/source/blender/makesrna/intern/rna_material.cc b/source/blender/makesrna/intern/rna_material.cc index a41401cabfc..c11d0ea30d8 100644 --- a/source/blender/makesrna/intern/rna_material.cc +++ b/source/blender/makesrna/intern/rna_material.cc @@ -909,6 +909,15 @@ void RNA_def_material(BlenderRNA *brna) prop, "Shadow Backface Culling", "Use back face culling when casting shadows"); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + prop = RNA_def_property(srna, "use_transparent_shadow", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "blend_flag", MA_BL_TRANSPARENT_SHADOW); + RNA_def_property_ui_text( + prop, + "Transparent Shadows", + "Use transparent shadows for this material if it contains a Transparent BSDF, " + "disabling will render faster but not give accurate shadows"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + prop = RNA_def_property(srna, "lightprobe_volume_single_sided", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna( prop, nullptr, "blend_flag", MA_BL_LIGHTPROBE_VOLUME_DOUBLE_SIDED);