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
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Scene *>(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<Scene *>(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.
|
||||
*
|
||||
|
||||
@@ -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<eMaterialGeometry>(shader_uuid & geometry_mask);
|
||||
pipeline_type = static_cast<eMaterialPipeline>((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
|
||||
|
||||
@@ -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<ShaderCreateInfo *>(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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
.alpha_threshold = 0.5f, \
|
||||
\
|
||||
.blend_shadow = MA_BS_SOLID, \
|
||||
\
|
||||
.blend_flag = MA_BL_TRANSPARENT_SHADOW,\
|
||||
\
|
||||
.lineart.mat_occlusion = 1, \
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user