Merge branch 'blender-v4.3-release'

This commit is contained in:
Julian Eisel
2024-10-03 19:19:48 +02:00
41 changed files with 625 additions and 194 deletions

View File

@@ -18,6 +18,8 @@ from bl_ui.properties_view_layer import (
ViewLayerLightgroupsPanelHelper,
)
from bl_ui.properties_object import has_geometry_visibility
class CyclesPresetPanel(PresetPanel, Panel):
COMPAT_ENGINES = {'CYCLES'}
@@ -1255,46 +1257,14 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
col.prop(cob, "use_deform_motion", text="Deformation")
def has_geometry_visibility(ob):
return ob and (
(ob.type in {
'MESH',
'CURVE',
'SURFACE',
'FONT',
'META',
'LIGHT',
'VOLUME',
'POINTCLOUD',
'CURVES',
}) or (ob.instance_type == 'COLLECTION' and ob.instance_collection))
class CYCLES_OBJECT_PT_shading(CyclesButtonsPanel, Panel):
bl_label = "Shading"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
if not CyclesButtonsPanel.poll(context):
return False
ob = context.object
return ob and has_geometry_visibility(ob)
def draw(self, context):
pass
class CYCLES_OBJECT_PT_shading_shadow_terminator(CyclesButtonsPanel, Panel):
bl_label = "Shadow Terminator"
bl_parent_id = "CYCLES_OBJECT_PT_shading"
bl_parent_id = "OBJECT_PT_shading"
bl_context = "object"
@classmethod
def poll(cls, context):
return context.object.type != 'LIGHT'
return CyclesButtonsPanel.poll(context) and context.object.type != 'LIGHT'
def draw(self, context):
layout = self.layout
@@ -1310,12 +1280,12 @@ class CYCLES_OBJECT_PT_shading_shadow_terminator(CyclesButtonsPanel, Panel):
class CYCLES_OBJECT_PT_shading_gi_approximation(CyclesButtonsPanel, Panel):
bl_label = "Fast GI Approximation"
bl_parent_id = "CYCLES_OBJECT_PT_shading"
bl_parent_id = "OBJECT_PT_shading"
bl_context = "object"
@classmethod
def poll(cls, context):
return context.object.type != 'LIGHT'
return CyclesButtonsPanel.poll(context) and context.object.type != 'LIGHT'
def draw(self, context):
layout = self.layout
@@ -1334,7 +1304,7 @@ class CYCLES_OBJECT_PT_shading_gi_approximation(CyclesButtonsPanel, Panel):
class CYCLES_OBJECT_PT_shading_caustics(CyclesButtonsPanel, Panel):
bl_label = "Caustics"
bl_parent_id = "CYCLES_OBJECT_PT_shading"
bl_parent_id = "OBJECT_PT_shading"
bl_context = "object"
@classmethod
@@ -1356,7 +1326,7 @@ class CYCLES_OBJECT_PT_shading_caustics(CyclesButtonsPanel, Panel):
class CYCLES_OBJECT_PT_lightgroup(CyclesButtonsPanel, Panel):
bl_label = "Light Group"
bl_parent_id = "CYCLES_OBJECT_PT_shading"
bl_parent_id = "OBJECT_PT_shading"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@@ -1379,96 +1349,6 @@ class CYCLES_OBJECT_PT_lightgroup(CyclesButtonsPanel, Panel):
sub.operator("scene.view_layer_add_lightgroup", icon='ADD', text="").name = ob.lightgroup
class CYCLES_OBJECT_MT_light_linking_context_menu(Menu):
bl_label = "Light Linking Specials"
def draw(self, _context):
layout = self.layout
layout.operator("object.light_linking_receivers_select")
class CYCLES_OBJECT_MT_shadow_linking_context_menu(Menu):
bl_label = "Shadow Linking Specials"
def draw(self, _context):
layout = self.layout
layout.operator("object.light_linking_blockers_select")
class CYCLES_OBJECT_PT_light_linking(CyclesButtonsPanel, Panel):
bl_label = "Light Linking"
bl_parent_id = "CYCLES_OBJECT_PT_shading"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
object = context.object
light_linking = object.light_linking
col = layout.column()
col.template_ID(
light_linking,
"receiver_collection",
new="object.light_linking_receiver_collection_new")
if not light_linking.receiver_collection:
return
row = layout.row()
col = row.column()
col.template_light_linking_collection(row, light_linking, "receiver_collection")
col = row.column()
sub = col.column(align=True)
prop = sub.operator("object.light_linking_receivers_link", icon='ADD', text="")
prop.link_state = 'INCLUDE'
sub.operator("object.light_linking_unlink_from_collection", icon='REMOVE', text="")
sub = col.column()
sub.menu("CYCLES_OBJECT_MT_light_linking_context_menu", icon='DOWNARROW_HLT', text="")
class CYCLES_OBJECT_PT_shadow_linking(CyclesButtonsPanel, Panel):
bl_label = "Shadow Linking"
bl_parent_id = "CYCLES_OBJECT_PT_shading"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
object = context.object
light_linking = object.light_linking
col = layout.column()
col.template_ID(
light_linking,
"blocker_collection",
new="object.light_linking_blocker_collection_new")
if not light_linking.blocker_collection:
return
row = layout.row()
col = row.column()
col.template_light_linking_collection(row, light_linking, "blocker_collection")
col = row.column()
sub = col.column(align=True)
prop = sub.operator("object.light_linking_blockers_link", icon='ADD', text="")
prop.link_state = 'INCLUDE'
sub.operator("object.light_linking_unlink_from_collection", icon='REMOVE', text="")
sub = col.column()
sub.menu("CYCLES_OBJECT_MT_shadow_linking_context_menu", icon='DOWNARROW_HLT', text="")
class CYCLES_OBJECT_PT_visibility(CyclesButtonsPanel, Panel):
bl_label = "Visibility"
bl_context = "object"
@@ -2517,14 +2397,6 @@ def draw_pause(self, context):
layout.prop(cscene, "preview_pause", icon='PLAY' if cscene.preview_pause else 'PAUSE', text="")
def draw_make_links(self, context):
if context.engine == "CYCLES":
layout = self.layout
layout.separator()
layout.operator_menu_enum("object.light_linking_receivers_link", "link_state")
layout.operator_menu_enum("object.light_linking_blockers_link", "link_state")
def get_panels():
exclude_panels = {
'DATA_PT_camera_dof',
@@ -2608,15 +2480,10 @@ classes = (
CYCLES_CAMERA_PT_dof_aperture,
CYCLES_PT_context_material,
CYCLES_OBJECT_PT_motion_blur,
CYCLES_OBJECT_PT_shading,
CYCLES_OBJECT_PT_shading_shadow_terminator,
CYCLES_OBJECT_PT_shading_gi_approximation,
CYCLES_OBJECT_PT_shading_caustics,
CYCLES_OBJECT_PT_lightgroup,
CYCLES_OBJECT_MT_light_linking_context_menu,
CYCLES_OBJECT_PT_light_linking,
CYCLES_OBJECT_MT_shadow_linking_context_menu,
CYCLES_OBJECT_PT_shadow_linking,
CYCLES_OBJECT_PT_visibility,
CYCLES_OBJECT_PT_visibility_ray_visibility,
CYCLES_OBJECT_PT_visibility_culling,
@@ -2663,7 +2530,6 @@ def register():
bpy.types.RENDER_PT_context.append(draw_device)
bpy.types.VIEW3D_HT_header.append(draw_pause)
bpy.types.VIEW3D_MT_make_links.append(draw_make_links)
for panel in get_panels():
panel.COMPAT_ENGINES.add('CYCLES')
@@ -2677,7 +2543,6 @@ def unregister():
bpy.types.RENDER_PT_context.remove(draw_device)
bpy.types.VIEW3D_HT_header.remove(draw_pause)
bpy.types.VIEW3D_MT_make_links.remove(draw_make_links)
for panel in get_panels():
if 'CYCLES' in panel.COMPAT_ENGINES:

View File

@@ -421,6 +421,128 @@ class OBJECT_PT_visibility(ObjectButtonsPanel, Panel):
col.prop(ob, "is_holdout")
def has_geometry_visibility(ob):
return ob and (
(ob.type in {
'MESH',
'CURVE',
'SURFACE',
'FONT',
'META',
'LIGHT',
'VOLUME',
'POINTCLOUD',
'CURVES',
}) or (ob.instance_type == 'COLLECTION' and ob.instance_collection))
class OBJECT_PT_shading(ObjectButtonsPanel, Panel):
bl_label = "Shading"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}
@classmethod
def poll(cls, context):
if context.engine not in cls.COMPAT_ENGINES:
return False
return has_geometry_visibility(context.object)
def draw(self, context):
pass
class OBJECT_MT_light_linking_context_menu(Menu):
bl_label = "Light Linking Specials"
def draw(self, _context):
layout = self.layout
layout.operator("object.light_linking_receivers_select")
class OBJECT_PT_light_linking(ObjectButtonsPanel, Panel):
bl_label = "Light Linking"
bl_parent_id = "OBJECT_PT_shading"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
object = context.object
light_linking = object.light_linking
col = layout.column()
col.template_ID(
light_linking,
"receiver_collection",
new="object.light_linking_receiver_collection_new")
if not light_linking.receiver_collection:
return
row = layout.row()
col = row.column()
col.template_light_linking_collection(row, light_linking, "receiver_collection")
col = row.column()
sub = col.column(align=True)
prop = sub.operator("object.light_linking_receivers_link", icon='ADD', text="")
prop.link_state = 'INCLUDE'
sub.operator("object.light_linking_unlink_from_collection", icon='REMOVE', text="")
sub = col.column()
sub.menu("OBJECT_MT_light_linking_context_menu", icon='DOWNARROW_HLT', text="")
class OBJECT_MT_shadow_linking_context_menu(Menu):
bl_label = "Shadow Linking Specials"
def draw(self, _context):
layout = self.layout
layout.operator("object.light_linking_blockers_select")
class OBJECT_PT_shadow_linking(ObjectButtonsPanel, Panel):
bl_label = "Shadow Linking"
bl_parent_id = "OBJECT_PT_shading"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
object = context.object
light_linking = object.light_linking
col = layout.column()
col.template_ID(
light_linking,
"blocker_collection",
new="object.light_linking_blocker_collection_new")
if not light_linking.blocker_collection:
return
row = layout.row()
col = row.column()
col.template_light_linking_collection(row, light_linking, "blocker_collection")
col = row.column()
sub = col.column(align=True)
prop = sub.operator("object.light_linking_blockers_link", icon='ADD', text="")
prop.link_state = 'INCLUDE'
sub.operator("object.light_linking_unlink_from_collection", icon='REMOVE', text="")
sub = col.column()
sub.menu("OBJECT_MT_shadow_linking_context_menu", icon='DOWNARROW_HLT', text="")
class OBJECT_PT_animation(ObjectButtonsPanel, PropertiesAnimationMixin, PropertyPanel, Panel):
_animated_id_context_property = "object"
@@ -443,6 +565,11 @@ classes = (
OBJECT_PT_motion_paths,
OBJECT_PT_motion_paths_display,
OBJECT_PT_display,
OBJECT_PT_shading,
OBJECT_MT_light_linking_context_menu,
OBJECT_PT_light_linking,
OBJECT_MT_shadow_linking_context_menu,
OBJECT_PT_shadow_linking,
OBJECT_PT_visibility,
OBJECT_PT_lineart,
OBJECT_PT_animation,

View File

@@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Menu
from bpy.types import Menu, Panel
class BrushAssetShelf:
@@ -18,12 +18,43 @@ class BrushAssetShelf:
def poll(cls, context):
return hasattr(context, "object") and context.object and context.object.mode == cls.mode
@classmethod
def has_tool_with_brush_type(cls, context, brush_type):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
space_type = context.space_data.type
brush_type_items = bpy.types.Brush.bl_rna.properties[cls.tool_prop].enum_items
tool_helper_cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
for item in ToolSelectPanelHelper._tools_flatten(
tool_helper_cls.tools_from_context(context, mode=context.mode),
):
if item is None:
continue
if item.idname in {
"builtin.arc",
"builtin.curve",
"builtin.line",
"builtin.box",
"builtin.circle",
"builtin.polyline",
}:
continue
if item.options is None or ('USE_BRUSHES' not in item.options):
continue
if item.brush_type is not None:
if brush_type_items[item.brush_type].value == brush_type:
return True
return False
@classmethod
def brush_type_poll(cls, context, asset):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context)
if not tool or tool.brush_type == 'ANY':
if not tool:
return True
if not cls.brush_type_prop or not cls.tool_prop:
return True
@@ -33,9 +64,14 @@ class BrushAssetShelf:
# certain brush type.
if asset_brush_type is None:
return False
brush_type_items = bpy.types.Brush.bl_rna.properties[cls.tool_prop].enum_items
return brush_type_items[asset_brush_type].identifier == tool.brush_type
# For the general brush that supports any brush type, filter out brushes that show up for
# other tools already.
if tool.brush_type == 'ANY':
return not cls.has_tool_with_brush_type(context, asset_brush_type)
brush_type_items = bpy.types.Brush.bl_rna.properties[cls.tool_prop].enum_items
return brush_type_items[tool.brush_type].value == asset_brush_type
@classmethod
def asset_poll(cls, asset):
@@ -45,12 +81,13 @@ class BrushAssetShelf:
return False
context = bpy.context
prefs = context.preferences
is_asset_shelf_region = context.region and context.region.type == 'ASSET_SHELF'
# Show all brushes in the permanent asset shelf region. Otherwise filter out brushes that
# Show all brushes in the popup asset shelves. Otherwise filter out brushes that
# are incompatible with the tool.
if not is_asset_shelf_region and not cls.brush_type_poll(context, asset):
return False
if is_asset_shelf_region and prefs.view.use_filter_brushes_by_tool:
return cls.brush_type_poll(context, asset)
return True
@@ -112,6 +149,25 @@ class BrushAssetShelf:
)
class VIEW3D_PT_brush_asset_shelf_filter(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Filter"
bl_parent_id = "ASSETSHELF_PT_display"
@classmethod
def poll(cls, context):
if context.asset_shelf is None:
return False
return context.asset_shelf.bl_idname == BrushAssetShelf.get_shelf_name_from_context(context)
def draw(self, context):
layout = self.layout
prefs = context.preferences
layout.prop(prefs.view, "use_filter_brushes_by_tool", text="By Active Tool")
class UnifiedPaintPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
@@ -1828,6 +1884,7 @@ def brush_basic_grease_pencil_vertex_settings(layout, context, brush, *, compact
classes = (
VIEW3D_PT_brush_asset_shelf_filter,
VIEW3D_MT_tools_projectpaint_clone,
)

View File

@@ -3651,6 +3651,10 @@ class VIEW3D_MT_make_links(Menu):
layout.operator("object.data_transfer")
layout.operator("object.datalayout_transfer")
layout.separator()
layout.operator_menu_enum("object.light_linking_receivers_link", "link_state")
layout.operator_menu_enum("object.light_linking_blockers_link", "link_state")
class VIEW3D_MT_paint_vertex(Menu):
bl_label = "Paint"

View File

@@ -31,7 +31,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 0
#define BLENDER_FILE_SUBVERSION 1
/* 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

View File

@@ -946,7 +946,7 @@ void blo_do_versions_userdef(UserDef *userdef)
if (!USER_VERSION_ATLEAST(400, 24)) {
/* Clear deprecated USER_MENUFIXEDORDER user flag for reuse. */
userdef->uiflag &= ~USER_UIFLAG_UNUSED_4;
userdef->uiflag &= ~(1 << 23);
}
if (!USER_VERSION_ATLEAST(400, 26)) {
@@ -1064,6 +1064,10 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->sequencer_editor_flag |= USER_SEQ_ED_CONNECT_STRIPS_BY_DEFAULT;
}
if (!USER_VERSION_ATLEAST(403, 30)) {
userdef->uiflag |= USER_FILTER_BRUSHES_BY_TOOL;
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a USER_VERSION_ATLEAST check.

View File

@@ -496,6 +496,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl
engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl
engines/eevee_next/shaders/eevee_shadow_tilemap_rendermap_comp.glsl
engines/eevee_next/shaders/eevee_shadow_visibility_comp.glsl
engines/eevee_next/shaders/eevee_spherical_harmonics_lib.glsl
engines/eevee_next/shaders/eevee_subsurface_convolve_comp.glsl
engines/eevee_next/shaders/eevee_subsurface_lib.glsl

View File

@@ -141,7 +141,7 @@ struct GBuffer {
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
GPU_TEXTURE_USAGE_ATTACHMENT;
header_tx.ensure_2d(GPU_R16UI, extent, usage);
header_tx.ensure_2d(GPU_R32UI, extent, usage);
closure_tx.ensure_2d_array(GPU_RGB10_A2, extent, data_count, usage);
normal_tx.ensure_2d_array(GPU_RG16, extent, normal_count, usage);
/* Ensure layer view for frame-buffer attachment. */

View File

@@ -19,6 +19,12 @@
namespace blender::eevee {
/* Convert by putting the least significant bits in the first component. */
static uint2 uint64_to_uint2(uint64_t data)
{
return {uint(data), uint(data >> uint64_t(32))};
}
/* -------------------------------------------------------------------- */
/** \name LightData
* \{ */
@@ -50,6 +56,7 @@ void Light::sync(ShadowModule &shadows,
float4x4 object_to_world,
char visibility_flag,
const ::Light *la,
const LightLinking *light_linking /* = nullptr */,
float threshold)
{
using namespace blender::math;
@@ -99,6 +106,16 @@ void Light::sync(ShadowModule &shadows,
shadow_discard_safe(shadows);
}
if (light_linking) {
this->light_set_membership = uint64_to_uint2(light_linking->runtime.light_set_membership);
this->shadow_set_membership = uint64_to_uint2(light_linking->runtime.shadow_set_membership);
}
else {
/* Set all bits if light linking is not used. */
this->light_set_membership = uint64_to_uint2(~uint64_t(0));
this->shadow_set_membership = uint64_to_uint2(~uint64_t(0));
}
this->initialized = true;
}
@@ -365,7 +382,7 @@ void LightModule::begin_sync()
Light &light = light_map_.lookup_or_add_default(world_sunlight_key);
light.used = true;
light.sync(inst_.shadows, float4x4::identity(), 0, &la, light_threshold_);
light.sync(inst_.shadows, float4x4::identity(), 0, &la, nullptr, light_threshold_);
sun_lights_len_ += 1;
}
@@ -388,7 +405,12 @@ void LightModule::sync_light(const Object *ob, ObjectHandle &handle)
light.used = true;
if (handle.recalc != 0 || !light.initialized) {
light.initialized = true;
light.sync(inst_.shadows, ob->object_to_world(), ob->visibility_flag, la, light_threshold_);
light.sync(inst_.shadows,
ob->object_to_world(),
ob->visibility_flag,
la,
ob->light_linking,
light_threshold_);
}
sun_lights_len_ += int(is_sun_light(light.type));
local_lights_len_ += int(!is_sun_light(light.type));

View File

@@ -80,6 +80,7 @@ struct Light : public LightData, NonCopyable {
float4x4 object_to_world,
char visibility_flag,
const ::Light *la,
const LightLinking *light_linking,
float threshold);
void shadow_ensure(ShadowModule &shadows);

View File

@@ -340,6 +340,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_shadow_page_tile_store";
case SHADOW_TILEMAP_TAG_USAGE_VOLUME:
return "eevee_shadow_tag_usage_volume";
case SHADOW_VIEW_VISIBILITY:
return "eevee_shadow_view_visibility";
case SUBSURFACE_CONVOLVE:
return "eevee_subsurface_convolve";
case SUBSURFACE_SETUP:

View File

@@ -139,6 +139,7 @@ enum eShaderType {
SHADOW_TILEMAP_TAG_USAGE_SURFELS,
SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT,
SHADOW_TILEMAP_TAG_USAGE_VOLUME,
SHADOW_VIEW_VISIBILITY,
SUBSURFACE_CONVOLVE,
SUBSURFACE_SETUP,

View File

@@ -1008,6 +1008,11 @@ struct LightData {
/* True if the light uses jittered soft shadows. */
bool32_t shadow_jitter;
float _pad2;
uint2 light_set_membership;
/** Used by shadow sync. */
/* TODO(fclem): this should be part of #eevee::Light struct. But for some reason it gets cleared
* to zero after each sync cycle. */
uint2 shadow_set_membership;
#if USE_LIGHT_UNION
union {
@@ -1337,6 +1342,9 @@ struct ShadowTileMapData {
float half_size;
/** Offset in local space to the tilemap center in world units. Used for directional winmat. */
float2 center_offset;
/** Shadow set bitmask of the light using this tilemap. */
uint2 shadow_set_membership;
uint2 _pad3;
};
BLI_STATIC_ASSERT_ALIGN(ShadowTileMapData, 16)
@@ -1362,6 +1370,9 @@ struct ShadowRenderView {
int tilemap_lod;
/** Updated region of the tilemap. */
int2 rect_min;
/** Shadow set bitmask of the light generating this view. */
uint2 shadow_set_membership;
uint2 _pad0;
};
BLI_STATIC_ASSERT_ALIGN(ShadowRenderView, 16)
@@ -1725,9 +1736,10 @@ struct Surfel {
int cluster_id;
/** True if the light can bounce or be emitted by the surfel back face. */
bool32_t double_sided;
/** Surface receiver light set for light linking. */
uint receiver_light_set;
int _pad0;
int _pad1;
int _pad2;
/** Surface radiance: Emission + Direct Lighting. */
SurfelRadiance radiance_direct;
/** Surface radiance: Indirect Lighting. Double buffered to avoid race conditions. */

View File

@@ -10,6 +10,7 @@
#include "BKE_global.hh"
#include "BLI_math_matrix.hh"
#include "GPU_compute.hh"
#include "eevee_instance.hh"
@@ -28,14 +29,18 @@ ShadowTechnique ShadowModule::shadow_technique = ShadowTechnique::ATOMIC_RASTER;
void ShadowTileMap::sync_orthographic(const float4x4 &object_mat_,
int2 origin_offset,
int clipmap_level,
eShadowProjectionType projection_type_)
eShadowProjectionType projection_type_,
uint2 shadow_set_membership_)
{
if ((projection_type != projection_type_) || (level != clipmap_level)) {
if ((projection_type != projection_type_) || (level != clipmap_level) ||
(shadow_set_membership_ != shadow_set_membership))
{
set_dirty();
}
projection_type = projection_type_;
level = clipmap_level;
light_type = eLightType::LIGHT_SUN;
shadow_set_membership = shadow_set_membership_;
grid_shift = origin_offset - grid_offset;
grid_offset = origin_offset;
@@ -63,16 +68,23 @@ void ShadowTileMap::sync_orthographic(const float4x4 &object_mat_,
1.0f);
}
void ShadowTileMap::sync_cubeface(
eLightType light_type_, const float4x4 &object_mat_, float near_, float far_, eCubeFace face)
void ShadowTileMap::sync_cubeface(eLightType light_type_,
const float4x4 &object_mat_,
float near_,
float far_,
eCubeFace face,
uint2 shadow_set_membership_)
{
if (projection_type != SHADOW_PROJECTION_CUBEFACE || (cubeface != face)) {
if (projection_type != SHADOW_PROJECTION_CUBEFACE || (cubeface != face) ||
(shadow_set_membership_ != shadow_set_membership))
{
set_dirty();
}
projection_type = SHADOW_PROJECTION_CUBEFACE;
cubeface = face;
grid_offset = int2(0);
light_type = light_type_;
shadow_set_membership = shadow_set_membership_;
if ((clip_near != near_) || (clip_far != far_)) {
set_dirty();
@@ -237,7 +249,8 @@ void ShadowPunctual::end_sync(Light &light)
float far = int_as_float(light.clip_far);
for (int i : tilemaps_.index_range()) {
eCubeFace face = eCubeFace(Z_NEG + i);
tilemaps_[face]->sync_cubeface(light.type, object_to_world, near, far, face);
tilemaps_[face]->sync_cubeface(
light.type, object_to_world, near, far, face, light.shadow_set_membership);
}
light.local.tilemaps_count = tilemaps_needed;
@@ -372,7 +385,8 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
/* Equal spacing between cascades layers since we want uniform shadow density. */
int2 level_offset = origin_offset +
shadow_cascade_grid_offset(light.sun.clipmap_base_offset_pos, i);
tilemap->sync_orthographic(object_mat, level_offset, level, SHADOW_PROJECTION_CASCADE);
tilemap->sync_orthographic(
object_mat, level_offset, level, SHADOW_PROJECTION_CASCADE, light.shadow_set_membership);
/* Add shadow tile-maps grouped by lights to the GPU buffer. */
shadows_.tilemap_pool.tilemaps_data.append(*tilemap);
@@ -429,7 +443,8 @@ void ShadowDirectional::clipmap_tilemaps_distribution(Light &light, const Camera
float2 light_space_camera_position = camera.position() * float2x3(object_mat.view<2, 3>());
int2 level_offset = int2(math::round(light_space_camera_position / tile_size));
tilemap->sync_orthographic(object_mat, level_offset, level, SHADOW_PROJECTION_CLIPMAP);
tilemap->sync_orthographic(
object_mat, level_offset, level, SHADOW_PROJECTION_CLIPMAP, light.shadow_set_membership);
/* Add shadow tile-maps grouped by lights to the GPU buffer. */
shadows_.tilemap_pool.tilemaps_data.append(*tilemap);
@@ -1215,6 +1230,44 @@ int ShadowModule::max_view_per_tilemap()
return max_view_count;
}
/* Special culling pass to take shadow linking into consideration. */
void ShadowModule::ShadowView::compute_visibility(ObjectBoundsBuf &bounds,
ObjectInfosBuf &infos,
uint resource_len,
bool /*debug_freeze*/)
{
GPU_debug_group_begin("View.compute_visibility");
uint word_per_draw = this->visibility_word_per_draw();
/* Switch between tightly packed and set of whole word per instance. */
uint words_len = (view_len_ == 1) ? divide_ceil_u(resource_len, 32) :
resource_len * word_per_draw;
words_len = ceil_to_multiple_u(max_ii(1, words_len), 4);
/* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */
visibility_buf_.resize(words_len);
const uint32_t data = 0xFFFFFFFFu;
GPU_storagebuf_clear(visibility_buf_, data);
if (do_visibility_) {
GPUShader *shader = inst_.shaders.static_shader_get(SHADOW_VIEW_VISIBILITY);
GPU_shader_bind(shader);
GPU_shader_uniform_1i(shader, "resource_len", resource_len);
GPU_shader_uniform_1i(shader, "view_len", view_len_);
GPU_shader_uniform_1i(shader, "visibility_word_per_draw", word_per_draw);
GPU_storagebuf_bind(bounds, GPU_shader_get_ssbo_binding(shader, "bounds_buf"));
GPU_storagebuf_bind(visibility_buf_, GPU_shader_get_ssbo_binding(shader, "visibility_buf"));
GPU_storagebuf_bind(render_view_buf_, GPU_shader_get_ssbo_binding(shader, "render_view_buf"));
GPU_storagebuf_bind(infos, DRW_OBJ_INFOS_SLOT);
GPU_uniformbuf_bind(data_, DRW_VIEW_UBO_SLOT);
GPU_uniformbuf_bind(culling_, DRW_VIEW_CULLING_UBO_SLOT);
GPU_compute_dispatch(shader, divide_ceil_u(resource_len, DRW_VISIBILITY_GROUP_SIZE), 1, 1);
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
}
GPU_debug_group_end();
}
void ShadowModule::set_view(View &view, int2 extent)
{
if (enabled_ == false) {

View File

@@ -93,10 +93,15 @@ struct ShadowTileMap : public ShadowTileMapData {
void sync_orthographic(const float4x4 &object_mat_,
int2 origin_offset,
int clipmap_level,
eShadowProjectionType projection_type_);
eShadowProjectionType projection_type_,
uint2 shadow_set_membership_ = ~uint2(0));
void sync_cubeface(
eLightType light_type_, const float4x4 &object_mat, float near, float far, eCubeFace face);
void sync_cubeface(eLightType light_type_,
const float4x4 &object_mat,
float near,
float far,
eCubeFace face,
uint2 shadow_set_membership_ = ~uint2(0));
void debug_draw() const;
@@ -278,8 +283,25 @@ class ShadowModule {
/** \name Rendering
* \{ */
class ShadowView : public View {
Instance &inst_;
ShadowRenderViewBuf &render_view_buf_;
public:
ShadowView(const char *name, Instance &inst, ShadowRenderViewBuf &render_view_buf)
: View(name, SHADOW_VIEW_MAX, true), inst_(inst), render_view_buf_(render_view_buf)
{
}
protected:
virtual void compute_visibility(ObjectBoundsBuf &bounds,
ObjectInfosBuf &infos,
uint resource_len,
bool debug_freeze) override;
};
/** Multi-View containing a maximum of 64 view to be rendered with the shadow pipeline. */
View shadow_multi_view_ = {"ShadowMultiView", SHADOW_VIEW_MAX, true};
ShadowView shadow_multi_view_ = {"ShadowMultiView", inst_, render_view_buf_};
/** Framebuffer with the atlas_tx attached. */
Framebuffer render_fb_ = {"shadow_write_framebuffer"};

View File

@@ -61,12 +61,13 @@ void main()
/* Direct light. */
ClosureLightStack stack;
stack.cl[0] = closure_light_new(cl, V);
light_eval_reflection(stack, P, Ng, V, vPz);
uchar receiver_light_set = gbuffer_light_link_receiver_unpack(gbuf.header);
light_eval_reflection(stack, P, Ng, V, vPz, receiver_light_set);
vec3 radiance_front = stack.cl[0].light_shadowed;
stack.cl[0] = closure_light_new(cl_transmit, V, gbuf.thickness);
light_eval_transmission(stack, P, Ng, V, vPz, gbuf.thickness);
light_eval_transmission(stack, P, Ng, V, vPz, gbuf.thickness, receiver_light_set);
vec3 radiance_back = stack.cl[0].light_shadowed;

View File

@@ -70,7 +70,8 @@ void main()
/* TODO(fclem): If transmission (no SSS) is present, we could reduce LIGHT_CLOSURE_EVAL_COUNT
* by 1 for this evaluation and skip evaluating the transmission closure twice. */
light_eval_reflection(stack, P, Ng, V, vPz);
uchar receiver_light_set = gbuffer_light_link_receiver_unpack(gbuf.header);
light_eval_reflection(stack, P, Ng, V, vPz, receiver_light_set);
if (use_transmission) {
ClosureUndetermined cl_transmit = gbuffer_closure_get(gbuf, 0);
@@ -85,7 +86,7 @@ void main()
stack.cl[0] = closure_light_new(cl_transmit, V, gbuf.thickness);
/* NOTE: Only evaluates `stack.cl[0]`. */
light_eval_transmission(stack, P, Ng, V, vPz, gbuf.thickness);
light_eval_transmission(stack, P, Ng, V, vPz, gbuf.thickness, receiver_light_set);
#if 1 /* TODO Limit to SSS. */
if (cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID) {

View File

@@ -56,12 +56,13 @@ void main()
/* Direct light. */
ClosureLightStack stack;
stack.cl[0] = closure_light_new(cl, V);
light_eval_reflection(stack, P, Ng, V, vPz);
uchar receiver_light_set = gbuffer_light_link_receiver_unpack(gbuf.header);
light_eval_reflection(stack, P, Ng, V, vPz, receiver_light_set);
vec3 radiance_front = stack.cl[0].light_shadowed;
stack.cl[0] = closure_light_new(cl_transmit, V, gbuf.thickness);
light_eval_transmission(stack, P, Ng, V, vPz, gbuf.thickness);
light_eval_transmission(stack, P, Ng, V, vPz, gbuf.thickness, receiver_light_set);
vec3 radiance_back = stack.cl[0].light_shadowed;

View File

@@ -37,7 +37,8 @@ void forward_lighting_eval(float thickness, out vec3 radiance, out vec3 transmit
/* TODO(fclem): If transmission (no SSS) is present, we could reduce LIGHT_CLOSURE_EVAL_COUNT
* by 1 for this evaluation and skip evaluating the transmission closure twice. */
light_eval_reflection(stack, g_data.P, surface_N, V, vPz);
uchar receiver_light_set = receiver_light_set_get(drw_infos[resource_id]);
light_eval_reflection(stack, g_data.P, surface_N, V, vPz, receiver_light_set);
#if defined(MAT_SUBSURFACE) || defined(MAT_REFRACTION) || defined(MAT_TRANSLUCENT)
@@ -54,7 +55,7 @@ void forward_lighting_eval(float thickness, out vec3 radiance, out vec3 transmit
stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
/* NOTE: Only evaluates `stack.cl[0]`. */
light_eval_transmission(stack, g_data.P, surface_N, V, vPz, thickness);
light_eval_transmission(stack, g_data.P, surface_N, V, vPz, thickness, receiver_light_set);
# if defined(MAT_SUBSURFACE)
if (cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID) {

View File

@@ -44,6 +44,8 @@ struct GBufferData {
uint object_id;
/* First world normal stored in the gbuffer. Only valid if `has_any_surface` is true. */
vec3 surface_N;
/* Index into `light_set_membership` bitmask of Lights for light linking. */
uchar receiver_light_set;
};
/* Result of Packing the GBuffer. */
@@ -310,6 +312,16 @@ bool gbuffer_is_refraction(vec4 gbuffer)
return gbuffer.w < 1.0;
}
uint gbuffer_light_link_receiver_pack(uchar receiver_light_set)
{
return receiver_light_set << 26u;
}
uint gbuffer_light_link_receiver_unpack(uint data)
{
return data >> 26u;
}
uint gbuffer_header_pack(GBufferMode mode, uint bin)
{
return (mode << (4u * bin));
@@ -807,6 +819,9 @@ GBufferWriter gbuffer_pack(GBufferData data_in)
gbuf.data_len = 0;
gbuf.normal_len = 0;
/* Pack light linking data into header. */
gbuf.header |= gbuffer_light_link_receiver_pack(data_in.receiver_light_set);
/* Check special configurations first. */
bool has_additional_data = false;

View File

@@ -13,6 +13,8 @@
* - utility_tx
*/
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_shadow_tracing_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_bxdf_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_light_lib.glsl)
@@ -86,6 +88,11 @@ float light_power_get(LightData light, LightingType type)
return light.power[type & 3u];
}
bool light_linking_affects_receiver(uvec2 light_set_membership, uchar receiver_light_set)
{
return bitmask64_test(light_set_membership, receiver_light_set);
}
void light_eval_single_closure(LightData light,
LightVector lv,
inout ClosureLight cl,
@@ -112,10 +119,15 @@ void light_eval_single(uint l_idx,
vec3 P,
vec3 Ng,
vec3 V,
float thickness)
float thickness,
uchar receiver_light_set)
{
LightData light = light_buf[l_idx];
if (!light_linking_affects_receiver(light.light_set_membership, receiver_light_set)) {
return;
}
#if defined(SPECIALIZED_SHADOW_PARAMS)
int ray_count = shadow_ray_count;
int ray_step_count = shadow_ray_step_count;
@@ -171,37 +183,43 @@ void light_eval_single(uint l_idx,
}
}
void light_eval_transmission(
inout ClosureLightStack stack, vec3 P, vec3 Ng, vec3 V, float vPz, float thickness)
void light_eval_transmission(inout ClosureLightStack stack,
vec3 P,
vec3 Ng,
vec3 V,
float vPz,
float thickness,
uchar receiver_light_set)
{
#ifdef SKIP_LIGHT_EVAL
return;
#endif
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
light_eval_single(l_idx, true, true, stack, P, Ng, V, thickness);
light_eval_single(l_idx, true, true, stack, P, Ng, V, thickness, receiver_light_set);
}
LIGHT_FOREACH_END
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, PIXEL, vPz, l_idx) {
light_eval_single(l_idx, false, true, stack, P, Ng, V, thickness);
light_eval_single(l_idx, false, true, stack, P, Ng, V, thickness, receiver_light_set);
}
LIGHT_FOREACH_END
}
void light_eval_reflection(inout ClosureLightStack stack, vec3 P, vec3 Ng, vec3 V, float vPz)
void light_eval_reflection(
inout ClosureLightStack stack, vec3 P, vec3 Ng, vec3 V, float vPz, uchar receiver_light_set)
{
#ifdef SKIP_LIGHT_EVAL
return;
#endif
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
light_eval_single(l_idx, true, false, stack, P, Ng, V, 0.0);
light_eval_single(l_idx, true, false, stack, P, Ng, V, 0.0, receiver_light_set);
}
LIGHT_FOREACH_END
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, PIXEL, vPz, l_idx) {
light_eval_single(l_idx, false, false, stack, P, Ng, V, 0.0);
light_eval_single(l_idx, false, false, stack, P, Ng, V, 0.0, receiver_light_set);
}
LIGHT_FOREACH_END
}

View File

@@ -135,6 +135,8 @@ void main()
render_view_buf[view_index].tilemap_tiles_index = tilemap_data.tiles_index;
render_view_buf[view_index].tilemap_lod = lod;
render_view_buf[view_index].rect_min = rect_min;
/* For shadow linking. */
render_view_buf[view_index].shadow_set_membership = tilemap_data.shadow_set_membership;
}
}
}

View File

@@ -0,0 +1,94 @@
/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* Compute visibility of each resource bounds for a given shadow view.
* Checks for shadow linking properties and issue one draw call for each view.
*/
/* TODO(fclem): Could reject bounding boxes that are covering only invalid tiles. */
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_intersect_lib.glsl)
#pragma BLENDER_REQUIRE(common_intersect_lib.glsl)
bool shadow_linking_affects_caster(uint view_id, uint resource_id)
{
return bitmask64_test(render_view_buf[view_id].shadow_set_membership,
blocker_shadow_set_get(drw_infos[resource_id]));
}
void mask_visibility_bit(uint view_id)
{
if (view_len > 1) {
uint index = gl_GlobalInvocationID.x * uint(visibility_word_per_draw) + (view_id / 32u);
visibility_buf[index] &= ~(1u << view_id);
}
else {
atomicAnd(visibility_buf[gl_WorkGroupID.x], ~(1u << gl_LocalInvocationID.x));
}
}
/* Returns true if visibility needs to be disabled. */
bool non_culling_tests(uint view_id, uint resource_id)
{
if (shadow_linking_affects_caster(view_id, resource_id) == false) {
/* Object doesn't cast shadow from this light. */
return true;
}
else if (drw_view_culling.bound_sphere.w == -1.0) {
/* View disabled. */
return true;
}
return false;
}
void main()
{
if (int(gl_GlobalInvocationID.x) >= resource_len) {
return;
}
ObjectBounds bounds = bounds_buf[gl_GlobalInvocationID.x];
if (drw_bounds_are_valid(bounds)) {
IsectBox box = isect_box_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
Sphere bounding_sphere = shape_sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w);
Sphere inscribed_sphere = shape_sphere(bounds.bounding_sphere.xyz,
bounds._inner_sphere_radius);
for (drw_view_id = 0u; drw_view_id < uint(view_len); drw_view_id++) {
if (non_culling_tests(drw_view_id, gl_GlobalInvocationID.x)) {
mask_visibility_bit(drw_view_id);
}
else if (drw_view_culling.bound_sphere.w == -1.0) {
/* View disabled. */
mask_visibility_bit(drw_view_id);
}
else if (intersect_view(inscribed_sphere) == true) {
/* Visible. */
}
else if (intersect_view(bounding_sphere) == false) {
/* Not visible. */
mask_visibility_bit(drw_view_id);
}
else if (intersect_view(box) == false) {
/* Not visible. */
mask_visibility_bit(drw_view_id);
}
}
}
else {
/* Culling is disabled, but we need to mask the bits for disabled views. */
for (drw_view_id = 0u; drw_view_id < uint(view_len); drw_view_id++) {
if (non_culling_tests(drw_view_id, gl_GlobalInvocationID.x)) {
mask_visibility_bit(drw_view_id);
}
}
}
}

View File

@@ -64,6 +64,7 @@ void main()
surfel_buf[surfel_id].radiance_direct.back.rgb = is_double_sided ? g_emission : vec3(0);
surfel_buf[surfel_id].radiance_direct.back.a = 0.0;
surfel_buf[surfel_id].double_sided = is_double_sided;
surfel_buf[surfel_id].receiver_light_set = receiver_light_set_get(drw_infos[resource_id]);
if (!capture_info_buf.capture_emission) {
surfel_buf[surfel_id].radiance_direct.front.rgb = vec3(0.0);

View File

@@ -93,6 +93,7 @@ void main()
gbuf_data.surface_N = g_data.N;
gbuf_data.thickness = thickness;
gbuf_data.object_id = resource_id;
gbuf_data.receiver_light_set = receiver_light_set_get(drw_infos[resource_id]);
GBufferWriter gbuf = gbuffer_pack(gbuf_data);

View File

@@ -96,6 +96,7 @@ void main()
gbuf_data.surface_N = g_data.N;
gbuf_data.thickness = g_thickness;
gbuf_data.object_id = resource_id;
gbuf_data.receiver_light_set = receiver_light_set_get(drw_infos[resource_id]);
GBufferWriter gbuf = gbuffer_pack(gbuf_data);

View File

@@ -32,7 +32,7 @@ void main()
cl_reflect.N = surfel.normal;
cl_reflect.type = CLOSURE_BSDF_DIFFUSE_ID;
stack.cl[0] = closure_light_new(cl_reflect, V);
light_eval_reflection(stack, P, Ng, V, 0.0);
light_eval_reflection(stack, P, Ng, V, 0.0, surfel.receiver_light_set);
if (capture_info_buf.capture_indirect) {
surfel_buf[index].radiance_direct.front.rgb += stack.cl[0].light_shadowed *
@@ -43,7 +43,7 @@ void main()
cl_transmit.N = -surfel.normal;
cl_transmit.type = CLOSURE_BSDF_DIFFUSE_ID;
stack.cl[0] = closure_light_new(cl_transmit, -V);
light_eval_reflection(stack, P, -Ng, -V, 0.0);
light_eval_reflection(stack, P, -Ng, -V, 0.0, surfel.receiver_light_set);
if (capture_info_buf.capture_indirect) {
surfel_buf[index].radiance_direct.back.rgb += stack.cl[0].light_shadowed * surfel.albedo_back;

View File

@@ -2,6 +2,7 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "draw_defines.hh"
#include "eevee_defines.hh"
#include "gpu_shader_create_info.hh"
@@ -270,6 +271,22 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_tile_store)
.vertex_source("eevee_shadow_page_tile_vert.glsl")
.fragment_source("eevee_shadow_page_tile_frag.glsl");
/* Custom visibility check pass. */
GPU_SHADER_CREATE_INFO(eevee_shadow_view_visibility)
.do_static_compilation(true)
.typedef_source("eevee_defines.hh")
.typedef_source("eevee_shader_shared.hh")
.local_group_size(DRW_VISIBILITY_GROUP_SIZE)
.define("DRW_VIEW_LEN", STRINGIFY(DRW_VIEW_MAX))
.storage_buf(0, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "uint", "visibility_buf[]")
.storage_buf(2, Qualifier::READ, "ShadowRenderView", "render_view_buf[SHADOW_VIEW_MAX]")
.push_constant(Type::INT, "resource_len")
.push_constant(Type::INT, "view_len")
.push_constant(Type::INT, "visibility_word_per_draw")
.compute_source("eevee_shadow_visibility_comp.glsl")
.additional_info("draw_view", "draw_view_culling", "draw_object_infos_new");
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -412,6 +412,7 @@ class ShadowPass {
protected:
virtual void compute_visibility(ObjectBoundsBuf &bounds,
ObjectInfosBuf &infos,
uint resource_len,
bool debug_freeze) override;
virtual VisibilityBuf &get_visibility_buffer() override;

View File

@@ -208,6 +208,7 @@ void ShadowPass::ShadowView::set_mode(ShadowPass::PassType type)
}
void ShadowPass::ShadowView::compute_visibility(ObjectBoundsBuf &bounds,
ObjectInfosBuf & /*infos*/,
uint resource_len,
bool /*debug_freeze*/)
{

View File

@@ -185,7 +185,8 @@ void Manager::submit(PassMain &pass, View &view)
bool freeze_culling = (U.experimental.use_viewport_debug && DST.draw_ctx.v3d &&
(DST.draw_ctx.v3d->debug_flag & V3D_DEBUG_FREEZE_CULLING) != 0);
view.compute_visibility(bounds_buf.current(), resource_len_, freeze_culling);
view.compute_visibility(
bounds_buf.current(), infos_buf.current(), resource_len_, freeze_culling);
command::RecordingState state;
state.inverted_view = view.is_inverted();

View File

@@ -73,6 +73,15 @@ inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active
{
object_attrs_len = 0;
object_attrs_offset = 0;
light_and_shadow_set_membership = 0;
LightLinking *light_linking = (ref.dupli_parent) != nullptr ? ref.dupli_parent->light_linking :
ref.object->light_linking;
if (light_linking) {
light_and_shadow_set_membership |= light_linking->runtime.receiver_light_set;
light_and_shadow_set_membership |= light_linking->runtime.blocker_shadow_set << 8;
}
bool is_holdout = (ref.object->base_flag & BASE_HOLDOUT) ||
(ref.object->visibility_flag & OB_HOLDOUT);

View File

@@ -173,7 +173,8 @@ struct ObjectInfos {
float4 ob_color;
uint index;
uint _pad2;
/** Used for Light Linking in EEVEE */
uint light_and_shadow_set_membership;
float random;
eObjectInfoFlag flag;
#endif
@@ -185,6 +186,24 @@ struct ObjectInfos {
};
BLI_STATIC_ASSERT_ALIGN(ObjectInfos, 16)
inline uint receiver_light_set_get(ObjectInfos object_infos)
{
#if defined(GPU_SHADER) && !defined(DRAW_FINALIZE_SHADER)
return floatBitsToUint(object_infos.infos.y) & 0xFFu;
#else
return object_infos.light_and_shadow_set_membership & 0xFFu;
#endif
}
inline uint blocker_shadow_set_get(ObjectInfos object_infos)
{
#if defined(GPU_SHADER) && !defined(DRAW_FINALIZE_SHADER)
return (floatBitsToUint(object_infos.infos.y) >> 8u) & 0xFFu;
#else
return (object_infos.light_and_shadow_set_membership >> 8u) & 0xFFu;
#endif
}
struct ObjectBounds {
/**
* Uploaded as vertex (0, 4, 3, 1) of the bbox in local space, matching XYZ axis order.

View File

@@ -244,7 +244,10 @@ void View::compute_procedural_bounds()
GPU_debug_group_end();
}
void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool debug_freeze)
void View::compute_visibility(ObjectBoundsBuf &bounds,
ObjectInfosBuf & /*infos*/,
uint resource_len,
bool debug_freeze)
{
if (debug_freeze && frozen_ == false) {
data_freeze_[0] = static_cast<ViewMatrices>(data_[0]);

View File

@@ -28,6 +28,7 @@ class Manager;
/* TODO: de-duplicate. */
using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>;
using ObjectInfosBuf = StorageArrayBuffer<ObjectInfos, 128>;
using VisibilityBuf = StorageArrayBuffer<uint, 4, true>;
class View {
@@ -173,7 +174,10 @@ class View {
protected:
/** Called from draw manager. */
void bind();
virtual void compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool debug_freeze);
virtual void compute_visibility(ObjectBoundsBuf &bounds,
ObjectInfosBuf &infos,
uint resource_len,
bool debug_freeze);
virtual VisibilityBuf &get_visibility_buffer();
void update_viewport_size();

View File

@@ -11,8 +11,6 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_intersect_lib.glsl)
shared uint shared_result;
void mask_visibility_bit(uint view_id)
{
if (view_len > 1) {

View File

@@ -76,6 +76,16 @@ void set_flag_from_test(inout int value, bool test, int flag)
/* Keep define to match C++ implementation. */
#define SET_FLAG_FROM_TEST(value, test, flag) set_flag_from_test(value, test, flag)
/**
* Return true if the bit inside bitmask at bit_index is set high.
* Assume the lower bits are inside first component of bitmask,
*/
bool bitmask64_test(uvec2 bitmask, uint bit_index)
{
uint bitmask32 = (bit_index >= 32u) ? bitmask.y : bitmask.x;
return flag_test(bitmask32, 1u << (bit_index & 0x1Fu));
}
/**
* Pack two 16-bit uint into one 32-bit uint.
*/

View File

@@ -1294,7 +1294,8 @@ typedef enum eUserpref_UI_Flag {
USER_ZOOM_TO_MOUSEPOS = (1 << 20),
USER_SHOW_FPS = (1 << 21),
USER_REGISTER_ALL_USERS = (1 << 22),
USER_UIFLAG_UNUSED_4 = (1 << 23), /* Cleared. */
/** Actually implemented in .py. */
USER_FILTER_BRUSHES_BY_TOOL = (1 << 23),
USER_CONTINUOUS_MOUSE = (1 << 24),
USER_ZOOM_INVERT = (1 << 25),
USER_ZOOM_HORIZ = (1 << 26), /* for CONTINUE and DOLLY zoom */

View File

@@ -170,6 +170,32 @@ static GreasePencilFrame *rna_Frames_frame_copy(ID *id,
return layer.frame_at(to_frame_number);
}
static GreasePencilFrame *rna_Frames_frame_move(ID *id,
GreasePencilLayer *layer_in,
ReportList *reports,
int from_frame_number,
int to_frame_number)
{
using namespace blender::bke::greasepencil;
GreasePencil &grease_pencil = *reinterpret_cast<GreasePencil *>(id);
Layer &layer = static_cast<GreasePencilLayer *>(layer_in)->wrap();
if (!layer.frames().contains(from_frame_number)) {
BKE_reportf(reports, RPT_ERROR, "Frame doesn't exists on frame number %d", from_frame_number);
return nullptr;
}
if (layer.frames().contains(to_frame_number)) {
BKE_reportf(reports, RPT_ERROR, "Frame already exists on frame number %d", to_frame_number);
return nullptr;
}
grease_pencil.insert_duplicate_frame(layer, from_frame_number, to_frame_number, true);
grease_pencil.remove_frames(layer, {from_frame_number});
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, &grease_pencil);
return layer.frame_at(to_frame_number);
}
static GreasePencilFrame *rna_GreasePencilLayer_get_frame_at(GreasePencilLayer *layer,
int frame_number)
{
@@ -520,6 +546,32 @@ void RNA_api_grease_pencil_frames(StructRNA *srna)
"Let the copied frame use the same drawing as the source");
parm = RNA_def_pointer(func, "copy", "GreasePencilFrame", "", "The newly copied frame");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "move", "rna_Frames_frame_move");
RNA_def_function_ui_description(func, "Move a Grease Pencil frame");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
parm = RNA_def_int(func,
"from_frame_number",
1,
MINAFRAME,
MAXFRAME,
"Source Frame Number",
"The frame number of the source frame",
MINAFRAME,
MAXFRAME);
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
parm = RNA_def_int(func,
"to_frame_number",
2,
MINAFRAME,
MAXFRAME,
"Target Frame Number",
"The frame number to move the frame to",
MINAFRAME,
MAXFRAME);
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
parm = RNA_def_pointer(func, "moved", "GreasePencilFrame", "", "The moved frame");
RNA_def_function_return(func, parm);
}
void RNA_api_grease_pencil_layer(StructRNA *srna)

View File

@@ -5323,6 +5323,14 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, nullptr, "uiflag", USER_PLAINMENUS);
RNA_def_property_ui_text(prop, "Toolbox Column Layout", "Use a column layout for toolbox");
prop = RNA_def_property(srna, "use_filter_brushes_by_tool", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "uiflag", USER_FILTER_BRUSHES_BY_TOOL);
RNA_def_property_ui_text(prop,
"Filter Brushes by Tool",
"Only show brushes applicable for the currently active tool in the "
"asset shelf. Stored in the Preferences, which may have to be saved "
"manually if Auto-Save Preferences is disabled");
static const EnumPropertyItem header_align_items[] = {
{0, "NONE", 0, "Keep Existing", "Keep existing header alignment"},
{USER_HEADER_FROM_PREF, "TOP", 0, "Top", "Top aligned on load"},

View File

@@ -746,7 +746,7 @@ if(WITH_CYCLES OR WITH_GPU_RENDER_TESTS)
if(WITH_GPU_RENDER_TESTS)
list(APPEND gpu_render_tests ${render_tests})
list(FILTER gpu_render_tests EXCLUDE REGEX light_group|light_linking|shadow_catcher|denoise|guiding|reports)
list(FILTER gpu_render_tests EXCLUDE REGEX light_group|shadow_catcher|denoise|guiding|reports)
set(_gpu_render_tests_arguments)
if(WITH_GPU_RENDER_TESTS_SILENT)