EEVEE: Add support for view layer overrides

This was a missing features in EEVEE for ages which
was in fact very easy to implement.

EEVEE implements the sample override like the default
`Use` value in Cycles. It always override the sample
count if not 0. Adding a new option for changing this
behavior just like Cycles can be done later while
at the same time making the option more understandable
and its value moved to the blender's DNA.

This PR moves the UI panel to the Blender side to
be shared between Cycles and EEVEE.

Pull Request: https://projects.blender.org/blender/blender/pulls/140219
This commit is contained in:
Clément Foucault 2025-06-12 14:18:29 +02:00 committed by Clément Foucault
parent 735f531cc0
commit e16b6ac3da
6 changed files with 39 additions and 21 deletions

View File

@ -978,23 +978,6 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
sub.active = scene.cycles.use_denoising
class CYCLES_RENDER_PT_override(CyclesButtonsPanel, Panel):
bl_label = "Override"
bl_options = {'DEFAULT_CLOSED'}
bl_context = "view_layer"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
layout.prop(view_layer, "material_override")
layout.prop(view_layer, "world_override")
layout.prop(view_layer, "samples")
class CYCLES_RENDER_PT_passes(CyclesButtonsPanel, Panel):
bl_label = "Passes"
bl_context = "view_layer"
@ -2566,7 +2549,6 @@ classes = (
CYCLES_RENDER_PT_passes_aov,
CYCLES_RENDER_PT_passes_lightgroups,
CYCLES_RENDER_PT_filter,
CYCLES_RENDER_PT_override,
CYCLES_PT_post_processing,
CYCLES_CAMERA_PT_dof,
CYCLES_CAMERA_PT_dof_aperture,

View File

@ -271,6 +271,26 @@ class VIEWLAYER_PT_filter(ViewLayerButtonsPanel, Panel):
sub.active = scene.render.use_motion_blur
class VIEWLAYER_PT_override(ViewLayerButtonsPanel, Panel):
bl_label = "Override"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_EEVEE_NEXT',
'CYCLES',
}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
layout.prop(view_layer, "material_override")
layout.prop(view_layer, "world_override")
layout.prop(view_layer, "samples")
class VIEWLAYER_PT_layer_custom_props(PropertyPanel, Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
@ -290,6 +310,7 @@ classes = (
VIEWLAYER_PT_layer_passes_aov,
VIEWLAYER_PT_layer_passes_lightgroups,
VIEWLAYER_PT_filter,
VIEWLAYER_PT_override,
VIEWLAYER_PT_layer_custom_props,
VIEWLAYER_UL_aov,
)

View File

@ -164,6 +164,8 @@ void MaterialModule::begin_sync()
queued_textures_count = 0;
queued_optimize_shaders_count = 0;
material_override = DEG_get_evaluated(inst_.depsgraph, inst_.view_layer->mat_override);
uint64_t next_update = GPU_pass_global_compilation_count();
gpu_pass_last_update_ = gpu_pass_next_update_;
gpu_pass_next_update_ = next_update;
@ -530,7 +532,7 @@ MaterialArray &MaterialModule::material_array_get(Object *ob, bool has_motion)
const int materials_len = BKE_object_material_used_with_fallback_eval(*ob);
for (auto i : IndexRange(materials_len)) {
::Material *blender_mat = material_from_slot(ob, i);
::Material *blender_mat = (material_override) ? material_override : material_from_slot(ob, i);
Material &mat = material_sync(ob, blender_mat, to_material_geometry(ob), has_motion);
/* \note Perform a whole copy since next material_sync() can move the Material memory location
* (i.e: because of its container growing) */
@ -545,7 +547,8 @@ Material &MaterialModule::material_get(Object *ob,
int mat_nr,
eMaterialGeometry geometry_type)
{
::Material *blender_mat = material_from_slot(ob, mat_nr);
::Material *blender_mat = (material_override) ? material_override :
material_from_slot(ob, mat_nr);
Material &mat = material_sync(ob, blender_mat, geometry_type, has_motion);
return mat;
}

View File

@ -355,6 +355,8 @@ class MaterialModule {
::Material *default_surface;
::Material *default_volume;
::Material *material_override = nullptr;
int64_t queued_shaders_count = 0;
int64_t queued_textures_count = 0;
int64_t queued_optimize_shaders_count = 0;

View File

@ -27,7 +27,12 @@ namespace blender::eevee {
void Sampling::init(const Scene *scene)
{
sample_count_ = inst_.is_viewport() ? scene->eevee.taa_samples : scene->eevee.taa_render_samples;
/* Note: Cycles have different option for view layers sample overrides. The current behavior
* matches the default `Use`, which simply override if non-zero. */
uint64_t render_sample_count = (inst_.view_layer->samples > 0) ? inst_.view_layer->samples :
scene->eevee.taa_render_samples;
sample_count_ = inst_.is_viewport() ? scene->eevee.taa_samples : render_sample_count;
if (inst_.is_image_render) {
sample_count_ = math::max(uint64_t(1), sample_count_);

View File

@ -126,6 +126,11 @@ void World::sync()
bl_world = scene_world_get();
}
::World *world_override = DEG_get_evaluated(inst_.depsgraph, inst_.view_layer->world_override);
if (world_override) {
bl_world = world_override;
}
bNodeTree *ntree = (bl_world->nodetree && bl_world->use_nodes) ?
bl_world->nodetree :
default_tree.nodetree_get(bl_world);