UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
164 changed files with 1214 additions and 481 deletions
Showing only changes of commit 1325adfe69 - Show all commits

View File

@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
.
PUBLIC .
)
set(INC_SYS
@ -26,3 +26,4 @@ set(LIB
)
blender_add_lib(extern_curve_fit_nd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_library(bf::extern::curve_fit_nd ALIAS extern_curve_fit_nd)

View File

@ -309,6 +309,10 @@ const bTheme U_theme_default = {
.back = RGBA(0x3d3d3dff),
.sub_back = RGBA(0x0000001f),
},
.asset_shelf = {
.header_back = RGBA(0x1d1d1dff),
.back = RGBA(0x303030ff),
},
.grid = RGBA(0x54545480),
.wire = RGBA(0x000000ff),
.wire_edit = RGBA(0x000000ff),

View File

@ -244,7 +244,7 @@ class NewGeometryNodeTreeAssign(Operator):
def execute(self, context):
space = context.space_data
if space and space.type == 'NODE_EDITOR' and space.geometry_nodes_type == 'OPERATOR':
if space and space.type == 'NODE_EDITOR' and space.geometry_nodes_type == 'TOOL':
group = geometry_node_group_empty_new()
space.node_tree = group
return {'FINISHED'}

View File

@ -119,6 +119,11 @@ class DATA_PT_lightprobe_eevee_next(DataButtonsPanel, Panel):
col.separator()
col.prop(probe, "grid_surface_bias")
col.prop(probe, "grid_escape_bias")
col.separator()
col.prop(probe, "grid_dilation_threshold")
col.prop(probe, "grid_dilation_radius")

View File

@ -858,11 +858,20 @@ class RENDER_PT_eevee_next_film(RenderButtonsPanel, Panel):
scene = context.scene
rd = scene.render
props = scene.eevee
col = layout.column()
col.prop(rd, "filter_size")
col.prop(rd, "film_transparent", text="Transparent")
col = layout.column(align=False, heading="Overscan")
row = col.row(align=True)
sub = row.row(align=True)
sub.prop(props, "use_overscan", text="")
sub = sub.row(align=True)
sub.active = props.use_overscan
sub.prop(props, "overscan_size", text="")
def draw_curves_settings(self, context):
layout = self.layout

View File

@ -287,12 +287,18 @@ class TEXT_MT_text(Menu):
class TEXT_MT_templates_py(Menu):
bl_label = "Python"
def draw(self, _context):
def draw(self, context):
prefs = context.preferences
use_asset_shelf = prefs.experimental.use_asset_shelf
self.path_menu(
bpy.utils.script_paths(subdir="templates_py"),
"text.open",
props_default={"internal": True},
filter_ext=lambda ext: (ext.lower() == ".py"),
# Filter out asset shelf template depending on experimental "Asset Shelf" option.
filter_path=lambda path, use_asset_shelf=use_asset_shelf:
(use_asset_shelf or not path.endswith("ui_asset_shelf.py")),
)

View File

@ -1269,10 +1269,13 @@ class VIEW3D_MT_view(Menu):
def draw(self, context):
layout = self.layout
view = context.space_data
prefs = context.preferences
layout.prop(view, "show_region_toolbar")
layout.prop(view, "show_region_ui")
layout.prop(view, "show_region_tool_header")
if prefs.experimental.use_asset_shelf:
layout.prop(view, "show_region_asset_shelf")
layout.prop(view, "show_region_hud")

Suggestion: it would be nice if this was greyed out when the asset menu isn't shown, when first testing this patch I found it confusing that toggling the region did nothing until entering sculpt mode.

Suggestion: it would be nice if this was greyed out when the asset menu isn't shown, when first testing this patch I found it confusing that toggling the region did nothing until entering sculpt mode.

Submitted as separate PR now since I'd like to get some feedback without delaying the initial asset shelf merge: #110756.

Submitted as separate PR now since I'd like to get some feedback without delaying the initial asset shelf merge: #110756.
layout.separator()
@ -8283,6 +8286,26 @@ class VIEW3D_PT_viewport_debug(Panel):
layout.prop(overlay, "use_debug_freeze_view_culling")
class VIEW3D_AST_sculpt_brushes(bpy.types.AssetShelf):
# Experimental: Asset shelf for sculpt brushes, only shows up if both the
# "Asset Shelf" and the "Extended Asset Browser" experimental features are
# enabled.
bl_space_type = "VIEW_3D"
@classmethod
def poll(cls, context):
prefs = context.preferences
if not prefs.experimental.use_extended_asset_browser:
return False
return bool(context.object and context.object.mode == 'SCULPT')
@classmethod
def asset_poll(cls, asset):
return asset.file_data.id_type == 'BRUSH'
classes = (
VIEW3D_HT_header,
VIEW3D_HT_tool_header,
@ -8532,6 +8555,7 @@ classes = (
VIEW3D_PT_curves_sculpt_parameter_falloff,
VIEW3D_PT_curves_sculpt_grow_shrink_scaling,
VIEW3D_PT_viewport_debug,
VIEW3D_AST_sculpt_brushes,
)

View File

@ -0,0 +1,26 @@
import bpy
class MyAssetShelf(bpy.types.AssetShelf):
bl_space_type = 'VIEW_3D'
bl_idname = "my_template.my_material_asset_shelf"
@classmethod
def poll(cls, context):
return bool(context.object and context.object.mode == 'OBJECT')
@classmethod
def asset_poll(cls, asset):
return asset.file_data.id_type in {'MATERIAL', 'OBJECT'}
def register():
bpy.utils.register_class(MyAssetShelf)
def unregister():
bpy.utils.unregister_class(MyAssetShelf)
if __name__ == "__main__":
register()

View File

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

@ -157,11 +157,11 @@ struct GeometrySet {
/**
* Get the component of the given type. Might return null if the component does not exist yet.
*/
const GeometryComponent *get_component_for_read(GeometryComponent::Type component_type) const;
template<typename Component> const Component *get_component_for_read() const
const GeometryComponent *get_component(GeometryComponent::Type component_type) const;
template<typename Component> const Component *get_component() const
{
BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
return static_cast<const Component *>(get_component_for_read(Component::static_type));
return static_cast<const Component *>(get_component(Component::static_type));
}
bool has(const GeometryComponent::Type component_type) const;
@ -194,7 +194,7 @@ struct GeometrySet {
/**
* Get all geometry components in this geometry set for read-only access.
*/
Vector<const GeometryComponent *> get_components_for_read() const;
Vector<const GeometryComponent *> get_components() const;
std::optional<Bounds<float3>> compute_boundbox_without_instances() const;
@ -247,32 +247,32 @@ struct GeometrySet {
/**
* Create a new geometry set that only contains the given mesh.
*/
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
static GeometrySet from_mesh(Mesh *mesh,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/**
* Create a new geometry set that only contains the given volume.
*/
static GeometrySet create_with_volume(
Volume *volume, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
static GeometrySet from_volume(Volume *volume,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/**
* Create a new geometry set that only contains the given point cloud.
*/
static GeometrySet create_with_pointcloud(
static GeometrySet from_pointcloud(
PointCloud *pointcloud, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/**
* Create a new geometry set that only contains the given curves.
*/
static GeometrySet create_with_curves(
Curves *curves, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
static GeometrySet from_curves(Curves *curves,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/**
* Create a new geometry set that only contains the given instances.
*/
static GeometrySet create_with_instances(
static GeometrySet from_instances(
Instances *instances, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/**
* Create a new geometry set that only contains the given Grease Pencil data.
*/
static GeometrySet create_with_grease_pencil(
static GeometrySet from_grease_pencil(
GreasePencil *grease_pencil, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/* Utility methods for access. */
@ -312,31 +312,31 @@ struct GeometrySet {
/**
* Returns a read-only mesh or null.
*/
const Mesh *get_mesh_for_read() const;
const Mesh *get_mesh() const;
/**
* Returns a read-only point cloud of null.
*/
const PointCloud *get_pointcloud_for_read() const;
const PointCloud *get_pointcloud() const;
/**
* Returns a read-only volume or null.
*/
const Volume *get_volume_for_read() const;
const Volume *get_volume() const;
/**
* Returns a read-only curves data-block or null.
*/
const Curves *get_curves_for_read() const;
const Curves *get_curves() const;
/**
* Returns read-only instances or null.
*/
const Instances *get_instances_for_read() const;
const Instances *get_instances() const;
/**
* Returns read-only curve edit hints or null.
*/
const CurvesEditHints *get_curve_edit_hints_for_read() const;
const CurvesEditHints *get_curve_edit_hints() const;
/**
* Returns a read-only Grease Pencil data-block or null.
*/
const GreasePencil *get_grease_pencil_for_read() const;
const GreasePencil *get_grease_pencil() const;
/**
* Returns a mutable mesh or null. No ownership is transferred.
@ -441,7 +441,7 @@ class MeshComponent : public GeometryComponent {
* Get the mesh from this component. This method can be used by multiple threads at the same
* time. Therefore, the returned mesh should not be modified. No ownership is transferred.
*/
const Mesh *get_for_read() const;
const Mesh *get() const;
/**
* Get the mesh from this component. This method can only be used when the component is mutable,
* i.e. it is not shared. The returned mesh can be modified. No ownership is transferred.
@ -497,7 +497,7 @@ class PointCloudComponent : public GeometryComponent {
* same time. Therefore, the returned point cloud should not be modified. No ownership is
* transferred.
*/
const PointCloud *get_for_read() const;
const PointCloud *get() const;
/**
* Get the point cloud from this component. This method can only be used when the component is
* mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
@ -547,7 +547,7 @@ class CurveComponent : public GeometryComponent {
void replace(Curves *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
Curves *release();
const Curves *get_for_read() const;
const Curves *get() const;
Curves *get_for_write();
bool is_empty() const final;
@ -582,7 +582,7 @@ class InstancesComponent : public GeometryComponent {
void clear() override;
const Instances *get_for_read() const;
const Instances *get() const;
Instances *get_for_write();
void replace(Instances *instances,
@ -630,7 +630,7 @@ class VolumeComponent : public GeometryComponent {
* Get the volume from this component. This method can be used by multiple threads at the same
* time. Therefore, the returned volume should not be modified. No ownership is transferred.
*/
const Volume *get_for_read() const;
const Volume *get() const;
/**
* Get the volume from this component. This method can only be used when the component is
* mutable, i.e. it is not shared. The returned volume can be modified. No ownership is
@ -708,7 +708,7 @@ class GreasePencilComponent : public GeometryComponent {
*/
GreasePencil *release();
const GreasePencil *get_for_read() const;
const GreasePencil *get() const;
GreasePencil *get_for_write();
bool is_empty() const final;

View File

@ -321,25 +321,6 @@ void BKE_mesh_recalc_looptri(const int *corner_verts,
*/
const float (*BKE_mesh_vert_normals_ensure(const struct Mesh *mesh))[3];
/**
* Retrieve write access to the cached vertex normals, ensuring that they are allocated but *not*
* that they are calculated. The provided vertex normals should be the same as if they were
* calculated automatically.
*
* \note In order to clear the dirty flag, this function should be followed by a call to
* #BKE_mesh_vert_normals_clear_dirty. This is separate so that normals are still tagged dirty
* while they are being assigned.
*
* \warning The memory returned by this function is not initialized if it was not previously
* allocated.
*/
float (*BKE_mesh_vert_normals_for_write(struct Mesh *mesh))[3];
/**
* Mark the mesh's vertex normals non-dirty, for when they are calculated or assigned manually.
*/
void BKE_mesh_vert_normals_clear_dirty(struct Mesh *mesh);
/**
* Return true if the mesh vertex normals either are not stored or are dirty.
* This can be used to help decide whether to transfer them when copying a mesh.

View File

@ -277,6 +277,12 @@ inline int edge_other_vert(const int2 &edge, const int vert)
void mesh_flip_faces(Mesh &mesh, const IndexMask &selection);
/** Set mesh vertex normals to known-correct values, avoiding future lazy computation. */
void mesh_vert_normals_assign(Mesh &mesh, Span<float3> vert_normals);
/** Set mesh vertex normals to known-correct values, avoiding future lazy computation. */
void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals);
} // namespace blender::bke
/* -------------------------------------------------------------------- */

View File

@ -32,7 +32,6 @@ set(INC
../../../intern/memutil
../../../intern/mikktspace
../../../intern/opensubdiv
../../../extern/curve_fit_nd
../../../extern/fmtlib/include
# RNA_prototypes.h
@ -542,6 +541,7 @@ set(LIB
bf_depsgraph
PRIVATE bf::dna
bf_draw
PRIVATE bf::extern::curve_fit_nd
bf_functions
bf_gpencil_modifiers_legacy
bf_gpu

View File

@ -555,7 +555,7 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
/* Release the mesh from the geometry set again. */
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
if (mesh_component.get_for_read() != input_mesh) {
if (mesh_component.get() != input_mesh) {
/* Make sure the mesh component actually owns the mesh before taking over ownership. */
mesh_component.ensure_owns_direct_data();
}

View File

@ -690,7 +690,7 @@ static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet
{
auto io_geometry = std::make_shared<DictionaryValue>();
if (geometry.has_mesh()) {
const Mesh &mesh = *geometry.get_mesh_for_read();
const Mesh &mesh = *geometry.get_mesh();
auto io_mesh = io_geometry->append_dict("mesh");
io_mesh->append_int("num_vertices", mesh.totvert);
@ -713,7 +713,7 @@ static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet
io_mesh->append("attributes", io_attributes);
}
if (geometry.has_pointcloud()) {
const PointCloud &pointcloud = *geometry.get_pointcloud_for_read();
const PointCloud &pointcloud = *geometry.get_pointcloud();
auto io_pointcloud = io_geometry->append_dict("pointcloud");
io_pointcloud->append_int("num_points", pointcloud.totpoint);
@ -726,7 +726,7 @@ static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet
io_pointcloud->append("attributes", io_attributes);
}
if (geometry.has_curves()) {
const Curves &curves_id = *geometry.get_curves_for_read();
const Curves &curves_id = *geometry.get_curves();
const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
auto io_curves = io_geometry->append_dict("curves");
@ -751,7 +751,7 @@ static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet
io_curves->append("attributes", io_attributes);
}
if (geometry.has_instances()) {
const bke::Instances &instances = *geometry.get_instances_for_read();
const bke::Instances &instances = *geometry.get_instances();
auto io_instances = io_geometry->append_dict("instances");
io_instances->append_int("num_instances", instances.instances_num());

View File

@ -193,8 +193,7 @@ static void rename_attributes(const Span<GeometrySet *> geometries,
continue;
}
/* Avoid write access on the geometry when unnecessary to avoid copying data-blocks. */
const AttributeAccessor attributes_read_only =
*geometry->get_component_for_read(type)->attributes();
const AttributeAccessor attributes_read_only = *geometry->get_component(type)->attributes();
if (std::none_of(attribute_map.keys().begin(),
attribute_map.keys().end(),
[&](const StringRef name) { return attributes_read_only.contains(name); }))

View File

@ -626,7 +626,7 @@ GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, cons
/* If available, use deformation information generated during evaluation. */
const GeometryComponentEditData *edit_component_eval =
geometry_eval->get_component_for_read<GeometryComponentEditData>();
geometry_eval->get_component<GeometryComponentEditData>();
bool uses_extra_positions = false;
if (edit_component_eval != nullptr) {
const CurvesEditHints *edit_hints = edit_component_eval->curves_edit_hints_.get();
@ -645,10 +645,9 @@ GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, cons
/* Use the positions of the evaluated curves directly, if the number of points matches. */
if (!uses_extra_positions) {
const CurveComponent *curves_component_eval =
geometry_eval->get_component_for_read<CurveComponent>();
const CurveComponent *curves_component_eval = geometry_eval->get_component<CurveComponent>();
if (curves_component_eval != nullptr) {
const Curves *curves_id_eval = curves_component_eval->get_for_read();
const Curves *curves_id_eval = curves_component_eval->get();
if (curves_id_eval != nullptr) {
const CurvesGeometry &curves_eval = curves_id_eval->geometry.wrap();
if (curves_eval.points_num() == points_num) {

View File

@ -271,8 +271,7 @@ void BKE_curves_data_update(Depsgraph *depsgraph, Scene *scene, Object *object)
/* Evaluate modifiers. */
Curves *curves = static_cast<Curves *>(object->data);
GeometrySet geometry_set = GeometrySet::create_with_curves(curves,
GeometryOwnershipType::ReadOnly);
GeometrySet geometry_set = GeometrySet::from_curves(curves, GeometryOwnershipType::ReadOnly);
if (object->mode == OB_MODE_SCULPT_CURVES) {
/* Try to propagate deformation data through modifier evaluation, so that sculpt mode can work
* on evaluated curves. */
@ -284,7 +283,7 @@ void BKE_curves_data_update(Depsgraph *depsgraph, Scene *scene, Object *object)
curves_evaluate_modifiers(depsgraph, scene, object, geometry_set);
/* Assign evaluated object. */
Curves *curves_eval = const_cast<Curves *>(geometry_set.get_curves_for_read());
Curves *curves_eval = const_cast<Curves *>(geometry_set.get_curves());
if (curves_eval == nullptr) {
curves_eval = curves_new_nomain(0, 0);
BKE_object_eval_assign_data(object, &curves_eval->id, true);

View File

@ -1361,7 +1361,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
*/
Curve &cow_curve = *reinterpret_cast<Curve *>(
BKE_id_copy_ex(nullptr, &original_curve.id, nullptr, LIB_ID_COPY_LOCALIZE));
cow_curve.curve_eval = geometry.get_curves_for_read();
cow_curve.curve_eval = geometry.get_curves();
/* Copy edit mode pointers necessary for drawing to the duplicated curve. */
cow_curve.editnurb = original_curve.editnurb;
cow_curve.editfont = original_curve.editfont;

View File

@ -80,7 +80,7 @@ Curves *CurveComponent::release()
return curves;
}
const Curves *CurveComponent::get_for_read() const
const Curves *CurveComponent::get() const
{
return curves_;
}

View File

@ -49,7 +49,7 @@ void GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(
if (edit_component.curves_edit_hints_->positions.has_value()) {
return;
}
const Curves *curves_id = geometry.get_curves_for_read();
const Curves *curves_id = geometry.get_curves();
if (curves_id == nullptr) {
return;
}

View File

@ -61,7 +61,7 @@ GreasePencil *GreasePencilComponent::release()
return grease_pencil;
}
const GreasePencil *GreasePencilComponent::get_for_read() const
const GreasePencil *GreasePencilComponent::get() const
{
return grease_pencil_;
}

View File

@ -81,7 +81,7 @@ void InstancesComponent::ensure_owns_direct_data()
}
}
const Instances *InstancesComponent::get_for_read() const
const Instances *InstancesComponent::get() const
{
return instances_;
}

View File

@ -76,7 +76,7 @@ Mesh *MeshComponent::release()
return mesh;
}
const Mesh *MeshComponent::get_for_read() const
const Mesh *MeshComponent::get() const
{
return mesh_;
}

View File

@ -65,7 +65,7 @@ PointCloud *PointCloudComponent::release()
return pointcloud;
}
const PointCloud *PointCloudComponent::get_for_read() const
const PointCloud *PointCloudComponent::get() const
{
return pointcloud_;
}

View File

@ -63,7 +63,7 @@ Volume *VolumeComponent::release()
return volume;
}
const Volume *VolumeComponent::get_for_read() const
const Volume *VolumeComponent::get() const
{
return volume_;
}

View File

@ -53,25 +53,25 @@ GeometryFieldContext::GeometryFieldContext(const GeometryComponent &component,
switch (component.type()) {
case GeometryComponent::Type::Mesh: {
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
geometry_ = mesh_component.get_for_read();
geometry_ = mesh_component.get();
break;
}
case GeometryComponent::Type::Curve: {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
const Curves *curves = curve_component.get_for_read();
const Curves *curves = curve_component.get();
geometry_ = curves ? &curves->geometry.wrap() : nullptr;
break;
}
case GeometryComponent::Type::PointCloud: {
const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
component);
geometry_ = pointcloud_component.get_for_read();
geometry_ = pointcloud_component.get();
break;
}
case GeometryComponent::Type::Instance: {
const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
component);
geometry_ = instances_component.get_for_read();
geometry_ = instances_component.get();
break;
}
case GeometryComponent::Type::Volume:
@ -593,7 +593,7 @@ std::optional<eAttrDomain> try_detect_field_domain(const GeometryComponent &comp
};
if (component_type == GeometryComponent::Type::Mesh) {
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
const Mesh *mesh = mesh_component.get_for_read();
const Mesh *mesh = mesh_component.get();
if (mesh == nullptr) {
return std::nullopt;
}
@ -616,7 +616,7 @@ std::optional<eAttrDomain> try_detect_field_domain(const GeometryComponent &comp
}
if (component_type == GeometryComponent::Type::Curve) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
const Curves *curves = curve_component.get_for_read();
const Curves *curves = curve_component.get();
if (curves == nullptr) {
return std::nullopt;
}

View File

@ -140,8 +140,7 @@ GeometryComponent *GeometrySet::get_component_ptr(GeometryComponent::Type type)
return nullptr;
}
const GeometryComponent *GeometrySet::get_component_for_read(
GeometryComponent::Type component_type) const
const GeometryComponent *GeometrySet::get_component(GeometryComponent::Type component_type) const
{
return components_[size_t(component_type)].get();
}
@ -188,7 +187,7 @@ void GeometrySet::add(const GeometryComponent &component)
components_[size_t(component.type())] = const_cast<GeometryComponent *>(&component);
}
Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
Vector<const GeometryComponent *> GeometrySet::get_components() const
{
Vector<const GeometryComponent *> components;
for (const GeometryComponentPtr &component_ptr : components_) {
@ -202,27 +201,27 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
std::optional<Bounds<float3>> GeometrySet::compute_boundbox_without_instances() const
{
std::optional<Bounds<float3>> bounds;
if (const PointCloud *pointcloud = this->get_pointcloud_for_read()) {
if (const PointCloud *pointcloud = this->get_pointcloud()) {
bounds = bounds::merge(bounds, pointcloud->bounds_min_max());
}
if (const Mesh *mesh = this->get_mesh_for_read()) {
if (const Mesh *mesh = this->get_mesh()) {
Bounds<float3> mesh_bounds{float3(std::numeric_limits<float>::max()),
float3(std::numeric_limits<float>::lowest())};
if (BKE_mesh_wrapper_minmax(mesh, mesh_bounds.min, mesh_bounds.max)) {
bounds = bounds::merge(bounds, {mesh_bounds});
}
}
if (const Volume *volume = this->get_volume_for_read()) {
if (const Volume *volume = this->get_volume()) {
Bounds<float3> volume_bounds{float3(std::numeric_limits<float>::max()),
float3(std::numeric_limits<float>::lowest())};
if (BKE_volume_min_max(volume, volume_bounds.min, volume_bounds.max)) {
bounds = bounds::merge(bounds, {volume_bounds});
}
}
if (const Curves *curves_id = this->get_curves_for_read()) {
if (const Curves *curves_id = this->get_curves()) {
bounds = bounds::merge(bounds, curves_id->geometry.wrap().bounds_min_max());
}
if (const GreasePencil *grease_pencil = this->get_grease_pencil_for_read()) {
if (const GreasePencil *grease_pencil = this->get_grease_pencil()) {
bounds = bounds::merge(bounds, grease_pencil->bounds_min_max());
}
return bounds;
@ -231,27 +230,26 @@ std::optional<Bounds<float3>> GeometrySet::compute_boundbox_without_instances()
std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
{
Vector<std::string> parts;
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
if (const Mesh *mesh = geometry_set.get_mesh()) {
parts.append(std::to_string(mesh->totvert) + " verts");
parts.append(std::to_string(mesh->totedge) + " edges");
parts.append(std::to_string(mesh->faces_num) + " faces");
parts.append(std::to_string(mesh->totloop) + " corners");
}
if (const Curves *curves = geometry_set.get_curves_for_read()) {
if (const Curves *curves = geometry_set.get_curves()) {
parts.append(std::to_string(curves->geometry.point_num) + " control points");
parts.append(std::to_string(curves->geometry.curve_num) + " curves");
}
if (const PointCloud *point_cloud = geometry_set.get_pointcloud_for_read()) {
if (const PointCloud *point_cloud = geometry_set.get_pointcloud()) {
parts.append(std::to_string(point_cloud->totpoint) + " points");
}
if (const Volume *volume = geometry_set.get_volume_for_read()) {
if (const Volume *volume = geometry_set.get_volume()) {
parts.append(std::to_string(BKE_volume_num_grids(volume)) + " volume grids");
}
if (geometry_set.has_instances()) {
parts.append(std::to_string(geometry_set.get_instances_for_read()->instances_num()) +
" instances");
parts.append(std::to_string(geometry_set.get_instances()->instances_num()) + " instances");
}
if (geometry_set.get_curve_edit_hints_for_read()) {
if (geometry_set.get_curve_edit_hints()) {
parts.append("curve edit hints");
}
@ -307,77 +305,76 @@ bool GeometrySet::owns_direct_data() const
return true;
}
const Mesh *GeometrySet::get_mesh_for_read() const
const Mesh *GeometrySet::get_mesh() const
{
const MeshComponent *component = this->get_component_for_read<MeshComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
const MeshComponent *component = this->get_component<MeshComponent>();
return (component == nullptr) ? nullptr : component->get();
}
bool GeometrySet::has_mesh() const
{
const MeshComponent *component = this->get_component_for_read<MeshComponent>();
const MeshComponent *component = this->get_component<MeshComponent>();
return component != nullptr && component->has_mesh();
}
const PointCloud *GeometrySet::get_pointcloud_for_read() const
const PointCloud *GeometrySet::get_pointcloud() const
{
const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
const PointCloudComponent *component = this->get_component<PointCloudComponent>();
return (component == nullptr) ? nullptr : component->get();
}
const Volume *GeometrySet::get_volume_for_read() const
const Volume *GeometrySet::get_volume() const
{
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
const VolumeComponent *component = this->get_component<VolumeComponent>();
return (component == nullptr) ? nullptr : component->get();
}
const Curves *GeometrySet::get_curves_for_read() const
const Curves *GeometrySet::get_curves() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
const CurveComponent *component = this->get_component<CurveComponent>();
return (component == nullptr) ? nullptr : component->get();
}
const Instances *GeometrySet::get_instances_for_read() const
const Instances *GeometrySet::get_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
const InstancesComponent *component = this->get_component<InstancesComponent>();
return (component == nullptr) ? nullptr : component->get();
}
const CurvesEditHints *GeometrySet::get_curve_edit_hints_for_read() const
const CurvesEditHints *GeometrySet::get_curve_edit_hints() const
{
const GeometryComponentEditData *component =
this->get_component_for_read<GeometryComponentEditData>();
const GeometryComponentEditData *component = this->get_component<GeometryComponentEditData>();
return (component == nullptr) ? nullptr : component->curves_edit_hints_.get();
}
const GreasePencil *GeometrySet::get_grease_pencil_for_read() const
const GreasePencil *GeometrySet::get_grease_pencil() const
{
const GreasePencilComponent *component = this->get_component_for_read<GreasePencilComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
const GreasePencilComponent *component = this->get_component<GreasePencilComponent>();
return (component == nullptr) ? nullptr : component->get();
}
bool GeometrySet::has_pointcloud() const
{
const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
const PointCloudComponent *component = this->get_component<PointCloudComponent>();
return component != nullptr && component->has_pointcloud();
}
bool GeometrySet::has_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
return component != nullptr && component->get_for_read() != nullptr &&
component->get_for_read()->instances_num() >= 1;
const InstancesComponent *component = this->get_component<InstancesComponent>();
return component != nullptr && component->get() != nullptr &&
component->get()->instances_num() >= 1;
}
bool GeometrySet::has_volume() const
{
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
const VolumeComponent *component = this->get_component<VolumeComponent>();
return component != nullptr && component->has_volume();
}
bool GeometrySet::has_curves() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
const CurveComponent *component = this->get_component<CurveComponent>();
return component != nullptr && component->has_curves();
}
@ -395,7 +392,7 @@ bool GeometrySet::has_realized_data() const
bool GeometrySet::has_grease_pencil() const
{
const GreasePencilComponent *component = this->get_component_for_read<GreasePencilComponent>();
const GreasePencilComponent *component = this->get_component<GreasePencilComponent>();
return component != nullptr && component->has_grease_pencil();
}
@ -405,45 +402,43 @@ bool GeometrySet::is_empty() const
this->has_volume() || this->has_instances() || this->has_grease_pencil());
}
GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
GeometrySet GeometrySet::from_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
geometry_set.replace_mesh(mesh, ownership);
return geometry_set;
}
GeometrySet GeometrySet::create_with_volume(Volume *volume, GeometryOwnershipType ownership)
GeometrySet GeometrySet::from_volume(Volume *volume, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
geometry_set.replace_volume(volume, ownership);
return geometry_set;
}
GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership)
GeometrySet GeometrySet::from_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
geometry_set.replace_pointcloud(pointcloud, ownership);
return geometry_set;
}
GeometrySet GeometrySet::create_with_curves(Curves *curves, GeometryOwnershipType ownership)
GeometrySet GeometrySet::from_curves(Curves *curves, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
geometry_set.replace_curves(curves, ownership);
return geometry_set;
}
GeometrySet GeometrySet::create_with_instances(Instances *instances,
GeometryOwnershipType ownership)
GeometrySet GeometrySet::from_instances(Instances *instances, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
geometry_set.replace_instances(instances, ownership);
return geometry_set;
}
GeometrySet GeometrySet::create_with_grease_pencil(GreasePencil *grease_pencil,
GeometryOwnershipType ownership)
GeometrySet GeometrySet::from_grease_pencil(GreasePencil *grease_pencil,
GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
geometry_set.replace_grease_pencil(grease_pencil, ownership);
@ -456,7 +451,7 @@ void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
this->remove<MeshComponent>();
return;
}
if (mesh == this->get_mesh_for_read()) {
if (mesh == this->get_mesh()) {
return;
}
this->remove<MeshComponent>();
@ -470,7 +465,7 @@ void GeometrySet::replace_curves(Curves *curves, GeometryOwnershipType ownership
this->remove<CurveComponent>();
return;
}
if (curves == this->get_curves_for_read()) {
if (curves == this->get_curves()) {
return;
}
this->remove<CurveComponent>();
@ -484,7 +479,7 @@ void GeometrySet::replace_instances(Instances *instances, GeometryOwnershipType
this->remove<InstancesComponent>();
return;
}
if (instances == this->get_instances_for_read()) {
if (instances == this->get_instances()) {
return;
}
this->remove<InstancesComponent>();
@ -498,7 +493,7 @@ void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipTy
this->remove<PointCloudComponent>();
return;
}
if (pointcloud == this->get_pointcloud_for_read()) {
if (pointcloud == this->get_pointcloud()) {
return;
}
this->remove<PointCloudComponent>();
@ -512,7 +507,7 @@ void GeometrySet::replace_volume(Volume *volume, GeometryOwnershipType ownership
this->remove<VolumeComponent>();
return;
}
if (volume == this->get_volume_for_read()) {
if (volume == this->get_volume()) {
return;
}
this->remove<VolumeComponent>();
@ -527,7 +522,7 @@ void GeometrySet::replace_grease_pencil(GreasePencil *grease_pencil,
this->remove<GreasePencilComponent>();
return;
}
if (grease_pencil == this->get_grease_pencil_for_read()) {
if (grease_pencil == this->get_grease_pencil()) {
return;
}
this->remove<GreasePencilComponent>();
@ -589,7 +584,7 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponent::Type> componen
if (!this->has(component_type)) {
continue;
}
const GeometryComponent &component = *this->get_component_for_read(component_type);
const GeometryComponent &component = *this->get_component(component_type);
const std::optional<AttributeAccessor> attributes = component.attributes();
if (attributes.has_value()) {
attributes->for_all(
@ -600,7 +595,7 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponent::Type> componen
}
}
if (include_instances && this->has_instances()) {
const Instances &instances = *this->get_instances_for_read();
const Instances &instances = *this->get_instances();
instances.foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
instance_geometry_set.attribute_foreach(component_types, include_instances, callback);
});
@ -664,7 +659,7 @@ static void gather_component_types_recursive(const GeometrySet &geometry_set,
const bool ignore_empty,
Vector<GeometryComponent::Type> &r_types)
{
for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
for (const GeometryComponent *component : geometry_set.get_components()) {
if (ignore_empty) {
if (component->is_empty()) {
continue;
@ -675,7 +670,7 @@ static void gather_component_types_recursive(const GeometrySet &geometry_set,
if (!include_instances) {
return;
}
const Instances *instances = geometry_set.get_instances_for_read();
const Instances *instances = geometry_set.get_instances();
if (instances == nullptr) {
return;
}
@ -732,7 +727,7 @@ bool object_has_geometry_set_instances(const Object &object)
if (geometry_set == nullptr) {
return false;
}
for (const GeometryComponent *component : geometry_set->get_components_for_read()) {
for (const GeometryComponent *component : geometry_set->get_components()) {
if (component->is_empty()) {
continue;
}

View File

@ -57,7 +57,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
std::unique_ptr<Instances> instances = std::make_unique<Instances>();
const int handle = instances->add_reference(collection);
instances->add_instance(handle, float4x4::identity());
return GeometrySet::create_with_instances(instances.release());
return GeometrySet::from_instances(instances.release());
}
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
@ -132,7 +132,7 @@ void Instances::ensure_geometry_instances()
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
instances->ensure_geometry_instances();
new_references.add_new(GeometrySet::create_with_instances(instances.release()));
new_references.add_new(GeometrySet::from_instances(instances.release()));
break;
}
}

View File

@ -1189,8 +1189,8 @@ void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/* Evaluate modifiers. */
GreasePencil *grease_pencil = static_cast<GreasePencil *>(object->data);
GeometrySet geometry_set = GeometrySet::create_with_grease_pencil(
grease_pencil, GeometryOwnershipType::ReadOnly);
GeometrySet geometry_set = GeometrySet::from_grease_pencil(grease_pencil,
GeometryOwnershipType::ReadOnly);
grease_pencil_evaluate_modifiers(depsgraph, scene, object, geometry_set);
if (!geometry_set.has_grease_pencil()) {
@ -1199,8 +1199,7 @@ void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/* For now the evaluated data is not const. We could use #get_grease_pencil_for_write, but that
* would result in a copy when it's shared. So for now, we use a const_cast here. */
GreasePencil *grease_pencil_eval = const_cast<GreasePencil *>(
geometry_set.get_grease_pencil_for_read());
GreasePencil *grease_pencil_eval = const_cast<GreasePencil *>(geometry_set.get_grease_pencil());
/* Assign evaluated object. */
BKE_object_eval_assign_data(object, &grease_pencil_eval->id, false);

View File

@ -173,6 +173,7 @@ static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader,
cache->baking.L1_a = nullptr;
cache->baking.L1_b = nullptr;
cache->baking.L1_c = nullptr;
cache->baking.virtual_offset = nullptr;
cache->baking.validity = nullptr;
cache->surfels = nullptr;
cache->surfels_len = 0;
@ -230,6 +231,7 @@ void BKE_lightprobe_grid_cache_frame_free(LightProbeGridCacheFrame *cache)
MEM_SAFE_FREE(cache->baking.validity);
MEM_SAFE_FREE(cache->connectivity.validity);
MEM_SAFE_FREE(cache->surfels);
MEM_SAFE_FREE(cache->baking.virtual_offset);
MEM_SAFE_FREE(cache);
}

View File

@ -677,7 +677,7 @@ void BKE_mball_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
BKE_mesh_tag_positions_changed(mesh);
}
ob->runtime.geometry_set_eval = new GeometrySet(GeometrySet::create_with_mesh(mesh));
ob->runtime.geometry_set_eval = new GeometrySet(GeometrySet::from_mesh(mesh));
BKE_object_boundbox_calc_from_evaluated_geometry(ob);
};

View File

@ -1488,10 +1488,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
for (int i = 0; i < mesh->totvert; i++) {
normalize_v3(process.no[i]);
}
memcpy(BKE_mesh_vert_normals_for_write(mesh),
process.no.data(),
sizeof(float[3]) * size_t(mesh->totvert));
BKE_mesh_vert_normals_clear_dirty(mesh);
blender::bke::mesh_vert_normals_assign(*mesh, std::move(process.no));
BKE_mesh_calc_edges(mesh, false, false);

View File

@ -575,7 +575,7 @@ void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/
Mesh *mesh = BKE_mesh_add(bmain, ob->id.name + 2);
if (const PointCloud *points = geometry.get_pointcloud_for_read()) {
if (const PointCloud *points = geometry.get_pointcloud()) {
mesh->totvert = points->totpoint;
CustomData_merge(&points->pdata, &mesh->vert_data, CD_MASK_PROP_ALL, points->totpoint);
}
@ -689,7 +689,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
static const Curves *get_evaluated_curves_from_object(const Object *object)
{
if (blender::bke::GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval) {
return geometry_set_eval->get_curves_for_read();
return geometry_set_eval->get_curves();
}
return nullptr;
}

View File

@ -89,18 +89,23 @@ static void add_v3_v3_atomic(float r[3], const float a[3])
* Related to managing normals but not directly related to calculating normals.
* \{ */
float (*BKE_mesh_vert_normals_for_write(Mesh *mesh))[3]
namespace blender::bke {
void mesh_vert_normals_assign(Mesh &mesh, Span<float3> vert_normals)
{
mesh->runtime->vert_normals.reinitialize(mesh->totvert);
return reinterpret_cast<float(*)[3]>(mesh->runtime->vert_normals.data());
mesh.runtime->vert_normals.clear();
mesh.runtime->vert_normals.extend(vert_normals);
mesh.runtime->vert_normals_dirty = false;
}
void BKE_mesh_vert_normals_clear_dirty(Mesh *mesh)
void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals)
{
mesh->runtime->vert_normals_dirty = false;
BLI_assert(mesh->runtime->vert_normals.size() == mesh->totvert);
mesh.runtime->vert_normals = std::move(vert_normals);
mesh.runtime->vert_normals_dirty = false;
}
} // namespace blender::bke
bool BKE_mesh_vert_normals_are_dirty(const Mesh *mesh)
{
return mesh->runtime->vert_normals_dirty;

View File

@ -390,7 +390,7 @@ BaryWeightFromPositionFn::BaryWeightFromPositionFn(GeometrySet geometry)
return signature;
}();
this->set_signature(&signature);
const Mesh &mesh = *source_.get_mesh_for_read();
const Mesh &mesh = *source_.get_mesh();
vert_positions_ = mesh.vert_positions();
corner_verts_ = mesh.corner_verts();
looptris_ = mesh.looptris();
@ -426,7 +426,7 @@ CornerBaryWeightFromPositionFn::CornerBaryWeightFromPositionFn(GeometrySet geome
return signature;
}();
this->set_signature(&signature);
const Mesh &mesh = *source_.get_mesh_for_read();
const Mesh &mesh = *source_.get_mesh();
vert_positions_ = mesh.vert_positions();
corner_verts_ = mesh.corner_verts();
looptris_ = mesh.looptris();
@ -478,7 +478,7 @@ void BaryWeightSampleFn::call(const IndexMask &mask,
void BaryWeightSampleFn::evaluate_source(fn::GField src_field)
{
const Mesh &mesh = *source_.get_mesh_for_read();
const Mesh &mesh = *source_.get_mesh();
looptris_ = mesh.looptris();
/* Use the most complex domain for now, ensuring no information is lost. In the future, it should
* be possible to use the most complex domain required by the field inputs, to simplify sampling

View File

@ -4491,7 +4491,7 @@ Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const Object *object)
* this should be avoided, or at least protected with a lock, so a const mesh could be returned
* from this function. We use a const_cast instead of #get_mesh_for_write, because that might
* result in a copy of the mesh when it is shared. */
Mesh *mesh = const_cast<Mesh *>(geometry_set_eval->get_mesh_for_read());
Mesh *mesh = const_cast<Mesh *>(geometry_set_eval->get_mesh());
if (mesh) {
return mesh;
}

View File

@ -893,21 +893,21 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
{
int component_index = 0;
if (ctx->object->type != OB_MESH || geometry_set_is_instance) {
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
if (const Mesh *mesh = geometry_set.get_mesh()) {
make_dupli(ctx, ctx->object, &mesh->id, parent_transform, component_index++);
}
}
if (ctx->object->type != OB_VOLUME || geometry_set_is_instance) {
if (const Volume *volume = geometry_set.get_volume_for_read()) {
if (const Volume *volume = geometry_set.get_volume()) {
make_dupli(ctx, ctx->object, &volume->id, parent_transform, component_index++);
}
}
if (!ELEM(ctx->object->type, OB_CURVES_LEGACY, OB_FONT, OB_CURVES) || geometry_set_is_instance) {
if (const blender::bke::CurveComponent *component =
geometry_set.get_component_for_read<blender::bke::CurveComponent>())
geometry_set.get_component<blender::bke::CurveComponent>())
{
if (use_new_curves_type) {
if (const Curves *curves = component->get_for_read()) {
if (const Curves *curves = component->get()) {
make_dupli(ctx, ctx->object, &curves->id, parent_transform, component_index++);
}
}
@ -919,13 +919,13 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
}
}
if (ctx->object->type != OB_POINTCLOUD || geometry_set_is_instance) {
if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) {
if (const PointCloud *pointcloud = geometry_set.get_pointcloud()) {
make_dupli(ctx, ctx->object, &pointcloud->id, parent_transform, component_index++);
}
}
const bool creates_duplis_for_components = component_index >= 1;
const Instances *instances = geometry_set.get_instances_for_read();
const Instances *instances = geometry_set.get_instances();
if (instances == nullptr) {
return;
}
@ -1838,7 +1838,7 @@ static bool find_geonode_attribute_rgba(const DupliObject *dupli,
}
const InstancesComponent *component =
dupli->instance_data[i]->get_component_for_read<InstancesComponent>();
dupli->instance_data[i]->get_component<InstancesComponent>();
if (component == nullptr) {
continue;

View File

@ -385,7 +385,7 @@ void BKE_pointcloud_data_update(Depsgraph *depsgraph, Scene *scene, Object *obje
/* Evaluate modifiers. */
PointCloud *pointcloud = static_cast<PointCloud *>(object->data);
blender::bke::GeometrySet geometry_set = blender::bke::GeometrySet::create_with_pointcloud(
blender::bke::GeometrySet geometry_set = blender::bke::GeometrySet::from_pointcloud(
pointcloud, blender::bke::GeometryOwnershipType::ReadOnly);
pointcloud_evaluate_modifiers(depsgraph, scene, object, geometry_set);

View File

@ -463,6 +463,13 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "grid_surface_bias")) {
LISTBASE_FOREACH (LightProbe *, lightprobe, &bmain->lightprobes) {
lightprobe->grid_surface_bias = 0.05f;
lightprobe->grid_escape_bias = 0.1f;
}
}
/* Clear removed "Z Buffer" flag. */
{
const int R_IMF_FLAG_ZBUF_LEGACY = 1 << 0;
@ -523,19 +530,7 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - #do_versions_after_linking_400 in this file.
* - `versioning_userdef.cc`, #blo_do_versions_userdef
* - `versioning_userdef.cc`, #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 14)) {
if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "RaytraceEEVEE", "reflection_options")) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
scene->eevee.reflection_options.flag = RAYTRACE_EEVEE_USE_DENOISE;
@ -553,5 +548,51 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
scene->eevee.ray_tracing_method = RAYTRACE_EEVEE_METHOD_SCREEN;
}
}
if (!DNA_struct_find(fd->filesdna, "RegionAssetShelf")) {
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype != SPACE_VIEW3D) {
continue;
}
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
&sl->regionbase;
if (ARegion *new_shelf_region = do_versions_add_region_if_not_found(
regionbase,
RGN_TYPE_ASSET_SHELF,
"asset shelf for view3d (versioning)",
RGN_TYPE_TOOL_HEADER))
{
new_shelf_region->alignment = RGN_ALIGN_BOTTOM;
}
if (ARegion *new_shelf_header = do_versions_add_region_if_not_found(
regionbase,
RGN_TYPE_ASSET_SHELF_HEADER,
"asset shelf header for view3d (versioning)",
RGN_TYPE_ASSET_SHELF))
{
new_shelf_header->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
}
}
}
}
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - #do_versions_after_linking_400 in this file.
* - `versioning_userdef.cc`, #blo_do_versions_userdef
* - `versioning_userdef.cc`, #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
}
}

View File

@ -110,6 +110,11 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_node.node_zone_repeat);
}
if (!USER_VERSION_ATLEAST(400, 14)) {
FROM_DEFAULT_V4_UCHAR(space_view3d.asset_shelf.back);
FROM_DEFAULT_V4_UCHAR(space_view3d.asset_shelf.header_back);
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -473,6 +473,8 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_cubemap_lib.glsl
engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl
engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl
engines/eevee_next/shaders/eevee_debug_irradiance_grid_vert.glsl
engines/eevee_next/shaders/eevee_debug_irradiance_grid_frag.glsl
engines/eevee_next/shaders/eevee_deferred_light_frag.glsl
engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl
engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl
@ -514,6 +516,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_lightprobe_eval_lib.glsl
engines/eevee_next/shaders/eevee_lightprobe_irradiance_bounds_comp.glsl
engines/eevee_next/shaders/eevee_lightprobe_irradiance_ray_comp.glsl
engines/eevee_next/shaders/eevee_lightprobe_irradiance_offset_comp.glsl
engines/eevee_next/shaders/eevee_lightprobe_irradiance_load_comp.glsl
engines/eevee_next/shaders/eevee_lightprobe_lib.glsl
engines/eevee_next/shaders/eevee_ltc_lib.glsl
@ -567,6 +570,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_surf_lib.glsl
engines/eevee_next/shaders/eevee_surf_shadow_frag.glsl
engines/eevee_next/shaders/eevee_surf_world_frag.glsl
engines/eevee_next/shaders/eevee_surfel_cluster_build_comp.glsl
engines/eevee_next/shaders/eevee_surfel_light_comp.glsl
engines/eevee_next/shaders/eevee_surfel_list_build_comp.glsl
engines/eevee_next/shaders/eevee_surfel_list_lib.glsl

View File

@ -15,7 +15,9 @@
#include "BKE_camera.h"
#include "DEG_depsgraph_query.h"
#include "ED_view3d.h"
#include "RE_pipeline.h"
#include "render_types.h"
#include "eevee_camera.hh"
#include "eevee_instance.hh"
@ -70,6 +72,12 @@ void Camera::init()
/* Light-probe baking. */
data.type = CAMERA_PERSP;
}
float overscan = 0.0f;
if ((inst_.scene->eevee.flag & SCE_EEVEE_OVERSCAN) && (inst_.drw_view || inst_.render)) {
overscan = inst_.scene->eevee.overscan / 100.0f;
}
overscan_changed_ = assign_if_different(overscan_, overscan);
}
void Camera::sync()
@ -78,17 +86,15 @@ void Camera::sync()
CameraData &data = data_;
data.uv_scale = float2(1.0f);
data.uv_bias = float2(0.0f);
if (inst_.is_baking()) {
/* Any view so that shadows and light culling works during irradiance bake. */
draw::View &view = inst_.irradiance_cache.bake.view_z_;
data.viewmat = view.viewmat();
data.viewinv = view.viewinv();
data.winmat = view.winmat();
data.wininv = view.wininv();
data.persmat = data.winmat * data.viewmat;
data.persinv = math::invert(data.persmat);
data.uv_scale = float2(1.0f);
data.uv_bias = float2(0.0f);
data.type = CAMERA_ORTHO;
/* \note: Follow camera parameters where distances are positive in front of the camera. */
@ -101,37 +107,47 @@ void Camera::sync()
else if (inst_.drw_view) {
DRW_view_viewmat_get(inst_.drw_view, data.viewmat.ptr(), false);
DRW_view_viewmat_get(inst_.drw_view, data.viewinv.ptr(), true);
DRW_view_winmat_get(inst_.drw_view, data.winmat.ptr(), false);
DRW_view_winmat_get(inst_.drw_view, data.wininv.ptr(), true);
DRW_view_persmat_get(inst_.drw_view, data.persmat.ptr(), false);
DRW_view_persmat_get(inst_.drw_view, data.persinv.ptr(), true);
if (overscan_ == 0.0f) {
DRW_view_winmat_get(inst_.drw_view, data.winmat.ptr(), false);
}
else {
rctf viewplane;
float clip_start;
float clip_end;
bool is_ortho = ED_view3d_viewplane_get(inst_.depsgraph,
inst_.v3d,
inst_.rv3d,
UNPACK2(inst_.film.display_extent_get()),
&viewplane,
&clip_start,
&clip_end,
nullptr);
RE_GetWindowMatrixWithOverscan(
is_ortho, clip_start, clip_end, viewplane, overscan_, data.winmat.ptr());
}
/* TODO(fclem): Derive from rv3d instead. */
data.uv_scale = float2(1.0f);
data.uv_bias = float2(0.0f);
}
else if (inst_.render) {
/* TODO(@fclem): Over-scan. */
// RE_GetCameraWindowWithOverscan(inst_.render->re, g_data->overscan, data.winmat);
RE_GetCameraWindow(inst_.render->re, camera_eval, data.winmat.ptr());
RE_GetCameraModelMatrix(inst_.render->re, camera_eval, data.viewinv.ptr());
invert_m4_m4(data.viewmat.ptr(), data.viewinv.ptr());
invert_m4_m4(data.wininv.ptr(), data.winmat.ptr());
mul_m4_m4m4(data.persmat.ptr(), data.winmat.ptr(), data.viewmat.ptr());
invert_m4_m4(data.persinv.ptr(), data.persmat.ptr());
data.uv_scale = float2(1.0f);
data.uv_bias = float2(0.0f);
data.viewmat = math::invert(data.viewinv);
RE_GetCameraWindow(inst_.render->re, camera_eval, data.winmat.ptr());
if (overscan_ != 0.0f) {
RE_GetCameraWindowWithOverscan(inst_.render->re, overscan_, data.winmat.ptr());
}
}
else {
data.viewmat = float4x4::identity();
data.viewinv = float4x4::identity();
data.winmat = math::projection::perspective(-0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f);
data.wininv = math::invert(data.winmat);
data.persmat = data.winmat * data.viewmat;
data.persinv = math::invert(data.persmat);
data.uv_scale = float2(1.0f);
data.uv_bias = float2(0.0f);
}
data.wininv = math::invert(data.winmat);
data.persmat = data.winmat * data.viewmat;
data.persinv = math::invert(data.persmat);
if (camera_eval && camera_eval->type == OB_CAMERA) {
const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
data.clip_near = cam->clip_start;

View File

@ -100,6 +100,9 @@ class Camera {
float radius;
} bound_sphere;
float overscan_;
bool overscan_changed_;
public:
Camera(Instance &inst) : inst_(inst){};
~Camera(){};
@ -147,6 +150,14 @@ class Camera {
{
return bound_sphere.radius;
}
float overscan() const
{
return overscan_;
}
bool overscan_changed() const
{
return overscan_changed_;
}
private:
void update_bounds();

View File

@ -64,8 +64,11 @@ static void eevee_engine_init(void *vedata)
camera = v3d->camera;
}
if (v3d->flag2 & V3D_RENDER_BORDER) {
if (camera) {
if (camera) {
rctf default_border;
BLI_rctf_init(&default_border, 0.0f, 1.0f, 0.0f, 1.0f);
bool is_default_border = BLI_rctf_compare(&scene->r.border, &default_border, 0.0f);
if (!is_default_border) {
rctf viewborder;
/* TODO(fclem) Might be better to get it from DRW. */
ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &viewborder, false);
@ -76,12 +79,12 @@ static void eevee_engine_init(void *vedata)
rect.xmax = floorf(viewborder.xmin + (scene->r.border.xmax * viewborder_sizex));
rect.ymax = floorf(viewborder.ymin + (scene->r.border.ymax * viewborder_sizey));
}
else {
rect.xmin = v3d->render_border.xmin * size[0];
rect.ymin = v3d->render_border.ymin * size[1];
rect.xmax = v3d->render_border.xmax * size[0];
rect.ymax = v3d->render_border.ymax * size[1];
}
}
else if (v3d->flag2 & V3D_RENDER_BORDER) {
rect.xmin = v3d->render_border.xmin * size[0];
rect.ymin = v3d->render_border.ymin * size[1];
rect.xmax = v3d->render_border.xmax * size[0];
rect.ymax = v3d->render_border.ymax * size[1];
}
}

View File

@ -248,16 +248,26 @@ void Film::init(const int2 &extent, const rcti *output_rect)
output_rect = &fallback_rect;
}
display_offset = int2(output_rect->xmin, output_rect->ymin);
FilmData data = data_;
data.extent = int2(BLI_rcti_size_x(output_rect), BLI_rcti_size_y(output_rect));
data.offset = int2(output_rect->xmin, output_rect->ymin);
data.offset = display_offset;
data.extent_inv = 1.0f / float2(data.extent);
/* Disable filtering if sample count is 1. */
data.filter_radius = (sampling.sample_count() == 1) ? 0.0f :
clamp_f(scene.r.gauss, 0.0f, 100.0f);
/* TODO(fclem): parameter hidden in experimental.
* We need to figure out LOD bias first in order to preserve texture crispiness. */
data.scaling_factor = 1;
data.render_extent = math::divide_ceil(extent, int2(data.scaling_factor));
if (inst_.camera.overscan() != 0.0f) {
int2 overscan = int2(inst_.camera.overscan() * math::max(UNPACK2(data.render_extent)));
data.render_extent += overscan * 2;
data.offset += overscan;
}
/* Disable filtering if sample count is 1. */
data.filter_radius = (sampling.sample_count() == 1) ? 0.0f :
clamp_f(scene.r.gauss, 0.0f, 100.0f);
data.cryptomatte_samples_len = inst_.view_layer->cryptomatte_levels;
data.background_opacity = (scene.r.alphamode == R_ALPHAPREMUL) ? 0.0f : 1.0f;
@ -355,9 +365,6 @@ void Film::init(const int2 &extent, const rcti *output_rect)
data_.cryptomatte_material_id = cryptomatte_index_get(EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL);
}
{
/* TODO(@fclem): Over-scans. */
data_.render_extent = math::divide_ceil(extent, int2(data_.scaling_factor));
int2 weight_extent = inst_.camera.is_panoramic() ? data_.extent : int2(data_.scaling_factor);
eGPUTextureFormat color_format = GPU_RGBA16F;
@ -629,7 +636,7 @@ void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx)
float4 clear_color = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(dfbl->default_fb, clear_color);
}
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data_.offset), UNPACK2(data_.extent));
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(display_offset), UNPACK2(data_.extent));
}
update_sample_table();
@ -661,7 +668,7 @@ void Film::display()
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data_.offset), UNPACK2(data_.extent));
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(display_offset), UNPACK2(data_.extent));
combined_final_tx_ = inst_.render_buffers.combined_tx;

View File

@ -64,6 +64,7 @@ class Film {
PassSimple cryptomatte_post_ps_ = {"Film.Cryptomatte.Post"};
FilmDataBuf data_;
int2 display_offset;
eViewLayerEEVEEPassType enabled_passes_ = eViewLayerEEVEEPassType(0);
@ -94,6 +95,12 @@ class Film {
return data_.render_extent;
}
/** Returns render output resolution. */
int2 display_extent_get() const
{
return data_.extent;
}
float2 pixel_jitter_get() const;
float background_opacity_get() const

View File

@ -554,6 +554,9 @@ void Instance::light_bake_irradiance(
irradiance_cache.bake.surfels_create(probe);
irradiance_cache.bake.surfels_lights_eval();
irradiance_cache.bake.clusters_build();
irradiance_cache.bake.irradiance_offset();
});
sampling.init(probe);

View File

@ -320,9 +320,15 @@ void IrradianceCache::debug_pass_draw(View &view, GPUFrameBuffer *view_fb)
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL:
inst_.info = "Debug Mode: Surfels Normal";
break;
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_CLUSTER:
inst_.info = "Debug Mode: Surfels Cluster";
break;
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE:
inst_.info = "Debug Mode: Surfels Irradiance";
break;
case eDebugMode::DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET:
inst_.info = "Debug Mode: Virtual Offset";
break;
default:
/* Nothing to display. */
return;
@ -335,29 +341,64 @@ void IrradianceCache::debug_pass_draw(View &view, GPUFrameBuffer *view_fb)
LightProbeGridCacheFrame *cache = grid.cache->grid_static_cache;
if (cache->surfels == nullptr || cache->surfels_len == 0) {
continue;
switch (inst_.debug_mode) {
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL:
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_CLUSTER:
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE: {
if (cache->surfels == nullptr || cache->surfels_len == 0) {
continue;
}
debug_ps_.init();
debug_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
DRW_STATE_DEPTH_LESS_EQUAL);
debug_ps_.framebuffer_set(&view_fb);
debug_ps_.shader_set(inst_.shaders.static_shader_get(DEBUG_SURFELS));
debug_ps_.push_constant("surfel_radius", 0.5f / grid.surfel_density);
debug_ps_.push_constant("debug_mode", static_cast<int>(inst_.debug_mode));
debug_surfels_buf_.resize(cache->surfels_len);
/* TODO(fclem): Cleanup: Could have a function in draw::StorageArrayBuffer that takes an
* input data. */
Span<Surfel> grid_surfels(static_cast<Surfel *>(cache->surfels), cache->surfels_len);
MutableSpan<Surfel>(debug_surfels_buf_.data(), cache->surfels_len).copy_from(grid_surfels);
debug_surfels_buf_.push_update();
debug_ps_.bind_ssbo("surfels_buf", debug_surfels_buf_);
debug_ps_.draw_procedural(GPU_PRIM_TRI_STRIP, cache->surfels_len, 4);
inst_.manager->submit(debug_ps_, view);
break;
}
case eDebugMode::DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET: {
if (cache->baking.virtual_offset == nullptr) {
continue;
}
int3 grid_size = int3(cache->size);
debug_ps_.init();
debug_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
DRW_STATE_DEPTH_LESS_EQUAL);
debug_ps_.framebuffer_set(&view_fb);
debug_ps_.shader_set(inst_.shaders.static_shader_get(DEBUG_IRRADIANCE_GRID));
debug_ps_.push_constant("debug_mode", static_cast<int>(inst_.debug_mode));
debug_ps_.push_constant("grid_mat", grid.object_to_world);
float4 *data = (float4 *)cache->baking.virtual_offset;
Texture debug_data_tx = {"debug_data_tx"};
debug_data_tx.ensure_3d(
GPU_RGBA16F, grid_size, GPU_TEXTURE_USAGE_SHADER_READ, (float *)data);
debug_ps_.bind_texture("debug_data_tx", debug_data_tx);
debug_ps_.draw_procedural(GPU_PRIM_LINES, 1, grid_size.x * grid_size.y * grid_size.z * 2);
inst_.manager->submit(debug_ps_, view);
break;
}
default:
break;
}
debug_surfels_ps_.init();
debug_surfels_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
DRW_STATE_DEPTH_LESS_EQUAL);
display_grids_ps_.framebuffer_set(&view_fb);
debug_surfels_ps_.shader_set(inst_.shaders.static_shader_get(DEBUG_SURFELS));
debug_surfels_ps_.push_constant("surfel_radius", 1.5f / 4.0f);
debug_surfels_ps_.push_constant("debug_mode", int(inst_.debug_mode));
debug_surfels_buf_.resize(cache->surfels_len);
/* TODO(fclem): Cleanup: Could have a function in draw::StorageArrayBuffer that takes an input
* data. */
Span<Surfel> grid_surfels(static_cast<Surfel *>(cache->surfels), cache->surfels_len);
MutableSpan<Surfel>(debug_surfels_buf_.data(), cache->surfels_len).copy_from(grid_surfels);
debug_surfels_buf_.push_update();
debug_surfels_ps_.bind_ssbo("surfels_buf", debug_surfels_buf_);
debug_surfels_ps_.draw_procedural(GPU_PRIM_TRI_STRIP, cache->surfels_len, 4);
inst_.manager->submit(debug_surfels_ps_, view);
}
}
@ -465,6 +506,8 @@ void IrradianceBake::init(const Object &probe_object)
{
const ::LightProbe *lightprobe = static_cast<::LightProbe *>(probe_object.data);
surfel_density_ = lightprobe->surfel_density;
min_distance_to_surface_ = lightprobe->grid_surface_bias;
max_virtual_offset_ = lightprobe->grid_escape_bias;
}
void IrradianceBake::sync()
@ -485,6 +528,17 @@ void IrradianceBake::sync()
pass.barrier(GPU_BARRIER_TEXTURE_FETCH);
pass.dispatch(&dispatch_per_surfel_);
}
{
PassSimple &pass = surfel_cluster_build_ps_;
pass.init();
pass.shader_set(inst_.shaders.static_shader_get(SURFEL_CLUSTER_BUILD));
pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
pass.bind_image("cluster_list_img", &cluster_list_tx_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
pass.dispatch(&dispatch_per_surfel_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_TEXTURE_FETCH);
}
{
PassSimple &pass = surfel_ray_build_ps_;
pass.init();
@ -539,6 +593,19 @@ void IrradianceBake::sync()
pass.bind_image("irradiance_L1_b_img", &irradiance_L1_b_tx_);
pass.bind_image("irradiance_L1_c_img", &irradiance_L1_c_tx_);
pass.bind_image("validity_img", &validity_tx_);
pass.bind_image("virtual_offset_img", &virtual_offset_tx_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_SHADER_IMAGE_ACCESS);
pass.dispatch(&dispatch_per_grid_sample_);
}
{
PassSimple &pass = irradiance_offset_ps_;
pass.init();
pass.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_OFFSET));
pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
pass.bind_ssbo("list_info_buf", &list_info_buf_);
pass.bind_image("cluster_list_img", &cluster_list_tx_);
pass.bind_image("virtual_offset_img", &virtual_offset_tx_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_SHADER_IMAGE_ACCESS);
pass.dispatch(&dispatch_per_grid_sample_);
}
@ -586,11 +653,21 @@ void IrradianceBake::surfels_create(const Object &probe_object)
dispatch_per_grid_sample_ = math::divide_ceil(grid_resolution, int3(IRRADIANCE_GRID_GROUP_SIZE));
capture_info_buf_.irradiance_grid_size = grid_resolution;
capture_info_buf_.irradiance_grid_local_to_world = grid_local_to_world;
capture_info_buf_.irradiance_grid_world_to_local = float4x4(probe_object.world_to_object);
capture_info_buf_.irradiance_grid_world_to_local_rotation = float4x4(
invert(normalize(float3x3(grid_local_to_world))));
capture_info_buf_.min_distance_to_surface = min_distance_to_surface_;
capture_info_buf_.max_virtual_offset = max_virtual_offset_;
capture_info_buf_.surfel_radius = 0.5f / lightprobe->surfel_density;
/* Make virtual offset distances scale relative. */
float3 scale = math::to_scale(grid_local_to_world) / float3(grid_resolution);
float min_distance_between_grid_samples = min_fff(UNPACK3(scale));
capture_info_buf_.min_distance_to_surface *= min_distance_between_grid_samples;
capture_info_buf_.max_virtual_offset *= min_distance_between_grid_samples;
eGPUTextureUsage texture_usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
GPU_TEXTURE_USAGE_HOST_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
GPU_TEXTURE_USAGE_HOST_READ;
/* 32bit float is needed here otherwise we loose too much energy from rounding error during the
* accumulation when the sample count is above 500. */
@ -605,6 +682,9 @@ void IrradianceBake::surfels_create(const Object &probe_object)
irradiance_L1_c_tx_.clear(float4(0.0f));
validity_tx_.clear(float4(0.0f));
virtual_offset_tx_.ensure_3d(GPU_RGBA16F, grid_resolution, texture_usage);
virtual_offset_tx_.clear(float4(0.0f));
DRW_stats_group_start("IrradianceBake.SceneBounds");
{
@ -672,11 +752,11 @@ void IrradianceBake::surfels_create(const Object &probe_object)
capture_info_buf_.surfel_len = 0u;
capture_info_buf_.push_update();
empty_raster_fb_.ensure(transform_point(invert(basis_x_), grid_pixel_extent_).xy());
empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_x_), grid_pixel_extent_).xy()));
inst_.pipelines.capture.render(view_x_);
empty_raster_fb_.ensure(transform_point(invert(basis_y_), grid_pixel_extent_).xy());
empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_y_), grid_pixel_extent_).xy()));
inst_.pipelines.capture.render(view_y_);
empty_raster_fb_.ensure(transform_point(invert(basis_z_), grid_pixel_extent_).xy());
empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_z_), grid_pixel_extent_).xy()));
inst_.pipelines.capture.render(view_z_);
DRW_stats_group_end();
@ -703,11 +783,11 @@ void IrradianceBake::surfels_create(const Object &probe_object)
capture_info_buf_.surfel_len = 0u;
capture_info_buf_.push_update();
empty_raster_fb_.ensure(transform_point(invert(basis_x_), grid_pixel_extent_).xy());
empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_x_), grid_pixel_extent_).xy()));
inst_.pipelines.capture.render(view_x_);
empty_raster_fb_.ensure(transform_point(invert(basis_y_), grid_pixel_extent_).xy());
empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_y_), grid_pixel_extent_).xy()));
inst_.pipelines.capture.render(view_y_);
empty_raster_fb_.ensure(transform_point(invert(basis_z_), grid_pixel_extent_).xy());
empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_z_), grid_pixel_extent_).xy()));
inst_.pipelines.capture.render(view_z_);
/* Sync with any other following pass using the surfel buffer. */
@ -730,6 +810,32 @@ void IrradianceBake::surfels_lights_eval()
inst_.manager->submit(surfel_light_eval_ps_, view_z_);
}
void IrradianceBake::clusters_build()
{
if (max_virtual_offset_ == 0.0f) {
return;
}
eGPUTextureUsage texture_usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
cluster_list_tx_.ensure_3d(GPU_R32I, capture_info_buf_.irradiance_grid_size, texture_usage);
cluster_list_tx_.clear(int4(-1));
/* View is not important here. It is only for validation. */
inst_.manager->submit(surfel_cluster_build_ps_, view_z_);
}
void IrradianceBake::irradiance_offset()
{
if (max_virtual_offset_ == 0.0f) {
/* NOTE: Virtual offset texture should already have been cleared to 0. */
return;
}
inst_.manager->submit(irradiance_offset_ps_, view_z_);
/* Not needed after this point. */
cluster_list_tx_.free();
}
void IrradianceBake::raylists_build()
{
using namespace blender::math;
@ -815,6 +921,7 @@ void IrradianceBake::irradiance_capture()
void IrradianceBake::read_surfels(LightProbeGridCacheFrame *cache_frame)
{
if (!ELEM(inst_.debug_mode,
eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_CLUSTER,
eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL,
eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE))
{
@ -833,11 +940,24 @@ void IrradianceBake::read_surfels(LightProbeGridCacheFrame *cache_frame)
surfels_dst.copy_from(surfels_src);
}
void IrradianceBake::read_virtual_offset(LightProbeGridCacheFrame *cache_frame)
{
if (!ELEM(inst_.debug_mode, eDebugMode::DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET)) {
return;
}
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
cache_frame->baking.virtual_offset = (float(*)[4])virtual_offset_tx_.read<float4>(
GPU_DATA_FLOAT);
}
LightProbeGridCacheFrame *IrradianceBake::read_result_unpacked()
{
LightProbeGridCacheFrame *cache_frame = BKE_lightprobe_grid_cache_frame_create();
read_surfels(cache_frame);
read_virtual_offset(cache_frame);
cache_frame->size[0] = irradiance_L0_tx_.width();
cache_frame->size[1] = irradiance_L0_tx_.height();
@ -859,6 +979,7 @@ LightProbeGridCacheFrame *IrradianceBake::read_result_packed()
LightProbeGridCacheFrame *cache_frame = BKE_lightprobe_grid_cache_frame_create();
read_surfels(cache_frame);
read_virtual_offset(cache_frame);
cache_frame->size[0] = irradiance_L0_tx_.width();
cache_frame->size[1] = irradiance_L0_tx_.height();

View File

@ -49,10 +49,14 @@ class IrradianceBake {
PassSimple surfel_light_eval_ps_ = {"LightEval"};
/** Create linked list of surfel to emulated ray-cast. */
PassSimple surfel_ray_build_ps_ = {"RayBuild"};
/** Create linked list of surfel to cluster them in the 3D irradiance grid. */
PassSimple surfel_cluster_build_ps_ = {"RayBuild"};
/** Propagate light from surfel to surfel. */
PassSimple surfel_light_propagate_ps_ = {"LightPropagate"};
/** Capture surfel lighting to irradiance samples. */
PassSimple irradiance_capture_ps_ = {"IrradianceCapture"};
/** Compute virtual offset for each irradiance samples. */
PassSimple irradiance_offset_ps_ = {"IrradianceOffset"};
/** Compute scene bounding box. */
PassSimple irradiance_bounds_ps_ = {"IrradianceBounds"};
/** Index of source and destination radiance in radiance double-buffer. */
@ -91,6 +95,10 @@ class IrradianceBake {
Texture irradiance_L1_a_tx_ = {"irradiance_L1_a_tx_"};
Texture irradiance_L1_b_tx_ = {"irradiance_L1_b_tx_"};
Texture irradiance_L1_c_tx_ = {"irradiance_L1_c_tx_"};
/** Offset per irradiance point to apply to the baking location. */
Texture virtual_offset_tx_ = {"virtual_offset_tx_"};
/** List of closest surfels per irradiance sample. */
Texture cluster_list_tx_ = {"cluster_list_tx_"};
/** Contains ratio of back-face hits. Allows to get rid of invalid probes. */
Texture validity_tx_ = {"validity_tx_"};
@ -98,6 +106,18 @@ class IrradianceBake {
float4 scene_bound_sphere_;
/* Surfel per unit distance. */
float surfel_density_ = 1.0f;
/**
* Minimum distance a grid sample point should have with a surface.
* In minimum grid sample spacing.
* Avoids samples to be too close to surface even if they are valid.
*/
float min_distance_to_surface_ = 0.05f;
/**
* Maximum distance from the grid sample point to the baking location.
* In minimum grid sample spacing.
* Avoids samples to be too far from their actual origin.
*/
float max_virtual_offset_ = 0.1f;
public:
IrradianceBake(Instance &inst) : inst_(inst){};
@ -111,10 +131,22 @@ class IrradianceBake {
void surfels_create(const Object &probe_object);
/** Evaluate direct lighting (and also clear the surfels radiance). */
void surfels_lights_eval();
/** Create a surfel lists to emulate ray-casts for the current sample random direction. */
/**
* Create a surfel lists per irradiance probe in order to compute the virtual baking offset.
* NOTE: The resulting lists are only valid until `clusters_build()` or `raylists_build()` are
* called since they share the same links inside the Surfel struct.
*/
void clusters_build();
/**
* Create a surfel lists to emulate ray-casts for the current sample random direction.
* NOTE: The resulting lists are only valid until `clusters_build()` or `raylists_build()` are
* called since they share the same links inside the Surfel struct.
*/
void raylists_build();
/** Propagate light from surfel to surfel in a random direction over the sphere. */
void propagate_light();
/** Compute offset to bias irradiance capture location. */
void irradiance_offset();
/** Store surfel irradiance inside the irradiance grid samples. */
void irradiance_capture();
@ -126,6 +158,8 @@ class IrradianceBake {
private:
/** Read surfel data back to CPU into \a cache_frame . */
void read_surfels(LightProbeGridCacheFrame *cache_frame);
/** Read virtual offset back to CPU into \a cache_frame . */
void read_virtual_offset(LightProbeGridCacheFrame *cache_frame);
};
/**
@ -153,8 +187,8 @@ class IrradianceCache {
/** If true, will trigger the reupload of all grid data instead of just streaming new ones. */
bool do_full_update_ = true;
/** Display surfel debug data. */
PassSimple debug_surfels_ps_ = {"IrradianceCache.Debug"};
/** Display debug data. */
PassSimple debug_ps_ = {"IrradianceCache.Debug"};
/** Debug surfel elements copied from the light cache. */
draw::StorageArrayBuffer<Surfel> debug_surfels_buf_;

View File

@ -34,6 +34,7 @@ void LightProbeModule::sync_grid(const Object *ob, ObjectHandle &handle)
grid.initialized = true;
grid.updated = true;
grid.surfel_density = static_cast<const ::LightProbe *>(ob->data)->surfel_density;
grid.object_to_world = float4x4(ob->object_to_world);
grid.world_to_object = float4x4(
math::normalize(math::transpose(float3x3(grid.object_to_world))));

View File

@ -42,6 +42,8 @@ struct IrradianceGrid : public LightProbe, IrradianceGridData {
Vector<IrradianceBrickPacked> bricks;
/** Index of the grid inside the grid UBO. */
int grid_index;
/** Copy of surfel density for debugging purpose. */
float surfel_density;
/** Copy of DNA members. */
float dilation_threshold;
float dilation_radius;

View File

@ -125,7 +125,7 @@ void MotionBlurModule::sync()
{
/* Disable motion blur in viewport when changing camera projection type.
* Avoids really high velocities. */
if (inst_.velocity.camera_changed_projection()) {
if (inst_.velocity.camera_changed_projection() || inst_.camera.overscan_changed()) {
motion_blur_fx_enabled_ = false;
}

View File

@ -106,6 +106,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_motion_blur_tiles_flatten_rg";
case DEBUG_SURFELS:
return "eevee_debug_surfels";
case DEBUG_IRRADIANCE_GRID:
return "eevee_debug_irradiance_grid";
case DISPLAY_PROBE_GRID:
return "eevee_display_probe_grid";
case DOF_BOKEH_LUT:
@ -176,6 +178,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_ray_tile_compact";
case LIGHTPROBE_IRRADIANCE_BOUNDS:
return "eevee_lightprobe_irradiance_bounds";
case LIGHTPROBE_IRRADIANCE_OFFSET:
return "eevee_lightprobe_irradiance_offset";
case LIGHTPROBE_IRRADIANCE_RAY:
return "eevee_lightprobe_irradiance_ray";
case LIGHTPROBE_IRRADIANCE_LOAD:
@ -214,6 +218,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_shadow_tag_usage_transparent";
case SUBSURFACE_EVAL:
return "eevee_subsurface_eval";
case SURFEL_CLUSTER_BUILD:
return "eevee_surfel_cluster_build";
case SURFEL_LIGHT:
return "eevee_surfel_light";
case SURFEL_LIST_BUILD:

View File

@ -36,6 +36,7 @@ enum eShaderType {
DEFERRED_LIGHT_DIFFUSE_ONLY,
DEBUG_SURFELS,
DEBUG_IRRADIANCE_GRID,
DISPLAY_PROBE_GRID,
@ -67,6 +68,7 @@ enum eShaderType {
LIGHT_CULLING_ZBIN,
LIGHTPROBE_IRRADIANCE_BOUNDS,
LIGHTPROBE_IRRADIANCE_OFFSET,
LIGHTPROBE_IRRADIANCE_RAY,
LIGHTPROBE_IRRADIANCE_LOAD,
@ -107,6 +109,7 @@ enum eShaderType {
SUBSURFACE_EVAL,
SURFEL_CLUSTER_BUILD,
SURFEL_LIGHT,
SURFEL_LIST_BUILD,
SURFEL_LIST_SORT,

View File

@ -55,6 +55,11 @@ enum eDebugMode : uint32_t {
*/
DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL = 3u,
DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE = 4u,
DEBUG_IRRADIANCE_CACHE_SURFELS_CLUSTER = 5u,
/**
* Display IrradianceCache virtual offset.
*/
DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET = 6u,
/**
* Show tiles depending on their status.
*/
@ -866,7 +871,8 @@ struct Surfel {
float ray_distance;
/** Surface albedo to apply to incoming radiance. */
packed_float3 albedo_back;
int _pad3;
/** Cluster this surfel is assigned to. */
int cluster_id;
/** Surface radiance: Emission + Direct Lighting. */
SurfelRadiance radiance_direct;
/** Surface radiance: Indirect Lighting. Double buffered to avoid race conditions. */
@ -889,6 +895,8 @@ struct CaptureInfoData {
float sample_index;
/** Transform of the light-probe object. */
float4x4 irradiance_grid_local_to_world;
/** Transform of the light-probe object. */
float4x4 irradiance_grid_world_to_local;
/** Transform vectors from world space to local space. Does not have location component. */
/** TODO(fclem): This could be a float3x4 or a float3x3 if padded correctly. */
float4x4 irradiance_grid_world_to_local_rotation;
@ -899,9 +907,12 @@ struct CaptureInfoData {
int scene_bound_x_max;
int scene_bound_y_max;
int scene_bound_z_max;
int _pad0;
int _pad1;
int _pad2;
/** Minimum distance between a grid sample and a surface. Used to compute virtual offset. */
float min_distance_to_surface;
/** Maximum world scale offset an irradiance grid sample can be baked with. */
float max_virtual_offset;
/** Radius of surfels. */
float surfel_radius;
};
BLI_STATIC_ASSERT_ALIGN(CaptureInfoData, 16)

View File

@ -0,0 +1,5 @@
void main()
{
out_color = vec4(0.0, 1.0, 1.0, 0.0);
}

View File

@ -0,0 +1,33 @@
#pragma BLENDER_REQUIRE(eevee_lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
void main()
{
ivec3 grid_resolution = textureSize(debug_data_tx, 0);
ivec3 grid_sample;
int sample_id = gl_VertexID / 2;
grid_sample.x = (sample_id % grid_resolution.x);
grid_sample.y = (sample_id / grid_resolution.x) % grid_resolution.y;
grid_sample.z = (sample_id / (grid_resolution.x * grid_resolution.y));
vec3 P = lightprobe_irradiance_grid_sample_position(grid_mat, grid_resolution, grid_sample);
vec4 debug_data = texelFetch(debug_data_tx, grid_sample, 0);
if (debug_mode == DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET) {
if (is_zero(debug_data.xyz)) {
/* Only render points that have offset. */
gl_Position = vec4(0.0);
gl_PointSize = 0.0;
return;
}
if ((gl_VertexID & 1) == 1) {
P += debug_data.xyz;
}
}
gl_Position = point_world_to_ndc(P);
gl_Position.z -= 2.5e-5;
gl_PointSize = 3.0;
}

View File

@ -1,4 +1,13 @@
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
vec3 debug_random_color(int v)
{
float r = interlieved_gradient_noise(vec2(v, 0), 0.0, 0.0);
return hue_gradient(r);
}
void main()
{
Surfel surfel = surfels_buf[surfel_index];
@ -13,6 +22,9 @@ void main()
case DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL:
out_color = vec4(pow(surfel.normal * 0.5 + 0.5, vec3(2.2)), 0.0);
break;
case DEBUG_IRRADIANCE_CACHE_SURFELS_CLUSTER:
out_color = vec4(pow(debug_random_color(surfel.cluster_id), vec3(2.2)), 0.0);
break;
case DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE:
out_color = vec4(radiance, 0.0);
break;

View File

@ -4,7 +4,7 @@
void main()
{
ivec2 texel_film = ivec2(gl_FragCoord.xy) - film_buf.offset;
ivec2 texel_film = ivec2(gl_FragCoord.xy);
float out_depth;
if (film_buf.display_only) {

View File

@ -0,0 +1,192 @@
/**
* For every irradiance probe sample, check if close to a surounding surfel and try to offset the
* irradiance sample position. This is similar to the surfel ray but we do not actually transport
* the light.
*
* Dispatched as 1 thread per irradiance probe sample.
*/
#pragma BLENDER_REQUIRE(eevee_surfel_list_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_lightprobe_lib.glsl)
int find_closest_surfel(ivec3 grid_coord, vec3 P)
{
int surfel_first = imageLoad(cluster_list_img, grid_coord).r;
float search_radius_sqr = square_f(capture_info_buf.max_virtual_offset +
capture_info_buf.min_distance_to_surface);
int closest_surfel = -1;
float closest_distance_sqr = 1e10;
for (int surfel_id = surfel_first; surfel_id > -1; surfel_id = surfel_buf[surfel_id].next) {
Surfel surfel = surfel_buf[surfel_id];
vec3 probe_to_surfel = surfel.position - P;
float surfel_dist_sqr = length_squared(probe_to_surfel);
/* Do not consider surfels that are outside of search radius. */
if (surfel_dist_sqr > search_radius_sqr) {
continue;
}
if (closest_distance_sqr > surfel_dist_sqr) {
closest_distance_sqr = surfel_dist_sqr;
closest_surfel = surfel_id;
}
}
return closest_surfel;
}
float front_facing_offset(float surfel_distance)
{
if (abs(surfel_distance) > capture_info_buf.min_distance_to_surface) {
return 0.0;
}
/* NOTE: distance can be negative. */
return surfel_distance - ((surfel_distance > 0.0) ? capture_info_buf.min_distance_to_surface :
-capture_info_buf.min_distance_to_surface);
}
float back_facing_offset(float surfel_distance)
{
if (surfel_distance > capture_info_buf.max_virtual_offset) {
return 0.0;
}
/* NOTE: distance can be negative. */
return surfel_distance + ((surfel_distance > 0.0) ? capture_info_buf.min_distance_to_surface :
-capture_info_buf.min_distance_to_surface);
}
float compute_offset_length(ivec3 grid_coord, vec3 P, vec3 offset_direction)
{
int surfel_first = imageLoad(cluster_list_img, grid_coord).r;
float search_radius = max(capture_info_buf.max_virtual_offset,
capture_info_buf.min_distance_to_surface);
/* Scale it a bit to avoid missing surfaces. */
float ray_radius = capture_info_buf.surfel_radius * M_SQRT2;
/* Nearest and farthest surfels in offset direction on both sides. */
int surfel_pos = -1;
int surfel_neg = -1;
float surfel_distance_pos = +1e10;
float surfel_distance_neg = -1e10;
for (int surfel_id = surfel_first; surfel_id > -1; surfel_id = surfel_buf[surfel_id].next) {
Surfel surfel = surfel_buf[surfel_id];
vec3 probe_to_surfel = surfel.position - P;
float surf_dist_signed = dot(offset_direction, probe_to_surfel);
/* Do not consider surfels that are outside of search radius. */
if (abs(surf_dist_signed) > search_radius) {
continue;
}
/* Emulate ray cast with any hit shader by discarding surfels outside of the ray radius. */
float ray_dist = distance(surf_dist_signed * offset_direction, probe_to_surfel);
if (ray_dist > ray_radius) {
continue;
}
if (surf_dist_signed > 0.0) {
if (surfel_distance_pos > surf_dist_signed) {
surfel_distance_pos = surf_dist_signed;
surfel_pos = surfel_id;
}
}
else {
if (surfel_distance_neg < surf_dist_signed) {
surfel_distance_neg = surf_dist_signed;
surfel_neg = surfel_id;
}
}
}
bool has_neighbor_pos = surfel_pos != -1;
bool has_neighbor_neg = surfel_neg != -1;
if (has_neighbor_pos && has_neighbor_neg) {
/* If both sides have neighbors. */
bool is_front_facing_pos = dot(offset_direction, surfel_buf[surfel_pos].normal) < 0.0;
bool is_front_facing_neg = dot(-offset_direction, surfel_buf[surfel_neg].normal) < 0.0;
if (is_front_facing_pos && is_front_facing_neg) {
/* If both sides have same facing. */
if (is_front_facing_pos) {
/* If both sides are front facing. */
float distance_between_neighbors = surfel_distance_pos - surfel_distance_neg;
if (distance_between_neighbors < capture_info_buf.min_distance_to_surface * 2.0) {
/* Choose the middle point. */
return (surfel_distance_pos + surfel_distance_neg) / 2.0;
}
else {
/* Choose the maximum offset. */
/* NOTE: The maximum offset is always from positive side since it's the closest. */
return front_facing_offset(surfel_distance_pos);
}
}
else {
/* If both sides are back facing. */
/* Choose the minimum offset. */
/* NOTE: The minimum offset is always from positive side since it's the closest. */
return back_facing_offset(surfel_distance_pos);
}
}
else {
/* If both sides have different facing. */
float front_distance = is_front_facing_pos ? surfel_distance_pos : surfel_distance_neg;
float back_distance = !is_front_facing_pos ? surfel_distance_pos : surfel_distance_neg;
float front_offset = front_facing_offset(front_distance);
float back_offset = back_facing_offset(back_distance);
/* Choose the minimum offset. */
return (abs(front_offset) < abs(back_offset)) ? front_offset : back_offset;
}
}
if (has_neighbor_pos || has_neighbor_neg) {
/* Only one side have neighbor. */
int nearest_surfel_id = has_neighbor_pos ? surfel_pos : surfel_neg;
float surfel_distance = has_neighbor_pos ? surfel_distance_pos : surfel_distance_neg;
bool is_front_facing = dot(has_neighbor_pos ? offset_direction : -offset_direction,
surfel_buf[nearest_surfel_id].normal) < 0.0;
if (is_front_facing) {
return front_facing_offset(surfel_distance);
}
else {
return back_facing_offset(surfel_distance);
}
}
/* If no sides has neighbor (should never happen here since we already bailed out). */
return 0.0;
}
void main()
{
ivec3 grid_coord = ivec3(gl_GlobalInvocationID);
if (any(greaterThanEqual(grid_coord, capture_info_buf.irradiance_grid_size))) {
return;
}
vec3 P = lightprobe_irradiance_grid_sample_position(
capture_info_buf.irradiance_grid_local_to_world,
capture_info_buf.irradiance_grid_size,
grid_coord);
int closest_surfel_id = find_closest_surfel(grid_coord, P);
if (closest_surfel_id == -1) {
imageStore(virtual_offset_img, grid_coord, vec4(0.0));
return;
}
/* Offset direction towards the sampling point. */
// vec3 offset_direction = safe_normalize(surfel_buf[closest_surfel_id].position - P);
/* NOTE: Use normal direction of the surfel instead for stability reasons. */
vec3 offset_direction = surfel_buf[closest_surfel_id].normal;
bool is_front_facing = dot(surfel_buf[closest_surfel_id].position - P,
surfel_buf[closest_surfel_id].normal) < 0.0;
if (is_front_facing) {
offset_direction = -offset_direction;
}
float offset_length = compute_offset_length(grid_coord, P, offset_direction);
vec3 virtual_offset = offset_direction * offset_length;
imageStore(virtual_offset_img, grid_coord, vec4(virtual_offset, 0.0));
}

View File

@ -71,9 +71,13 @@ void main()
capture_info_buf.irradiance_grid_size,
grid_coord);
/* Add virtual offset to avoid baking inside of geometry as much as possible. */
P += imageLoad(virtual_offset_img, grid_coord).xyz;
/* Project to get ray linked list. */
float irradiance_sample_ray_distance;
int list_index = surfel_list_index_get(P, irradiance_sample_ray_distance);
int list_index = surfel_list_index_get(
list_info_buf.ray_grid_size, P, irradiance_sample_ray_distance);
/* Walk the ray to get which surfels the irradiance sample is between. */
int surfel_prev = -1;

View File

@ -0,0 +1,27 @@
/**
* Takes scene surfel representation and build list of surfels inside 3D cells.
*
* The lists head are allocated to fit the probe samples granularity.
*
* Dispatch 1 thread per surfel.
*/
#pragma BLENDER_REQUIRE(eevee_surfel_list_lib.glsl)
void main()
{
int surfel_index = int(gl_GlobalInvocationID.x);
if (surfel_index >= capture_info_buf.surfel_len) {
return;
}
ivec3 cluster = surfel_cluster_index_get(imageSize(cluster_list_img),
capture_info_buf.irradiance_grid_world_to_local,
surfel_buf[surfel_index].position);
/* For debugging. */
surfel_buf[surfel_index].cluster_id = cluster.x + cluster.y * 1000 + cluster.z * 1000000;
/* NOTE: We only need to init the `cluster_list_img` to -1 for the whole list to be valid since
* every surfel will load its `next` value from the list head. */
surfel_buf[surfel_index].next = imageAtomicExchange(cluster_list_img, cluster, surfel_index);
}

View File

@ -22,7 +22,8 @@ void main()
}
float ray_distance;
int list_index = surfel_list_index_get(surfel_buf[surfel_index].position, ray_distance);
int list_index = surfel_list_index_get(
list_info_buf.ray_grid_size, surfel_buf[surfel_index].position, ray_distance);
/* Do separate assignement to avoid reference to buffer in arguments which is tricky to cross
* compile. */
surfel_buf[surfel_index].ray_distance = ray_distance;

View File

@ -1,19 +1,34 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_math_matrix_lib.glsl)
/**
* Return the coresponding list index in the `list_start_buf` for a given world position.
* Return the corresponding list index in the `list_start_buf` for a given world position.
* It will clamp any coordinate outside valid bounds to nearest list.
* Also return the surfel sorting value as `r_ray_distance`.
*/
int surfel_list_index_get(vec3 P, out float r_ray_distance)
int surfel_list_index_get(ivec2 ray_grid_size, vec3 P, out float r_ray_distance)
{
vec4 hP = point_world_to_ndc(P);
r_ray_distance = -hP.z;
vec2 ssP = hP.xy * 0.5 + 0.5;
ivec2 ray_coord_on_grid = ivec2(ssP * vec2(list_info_buf.ray_grid_size));
ray_coord_on_grid = clamp(ray_coord_on_grid, ivec2(0), list_info_buf.ray_grid_size - 1);
ivec2 ray_coord_on_grid = ivec2(ssP * vec2(ray_grid_size));
ray_coord_on_grid = clamp(ray_coord_on_grid, ivec2(0), ray_grid_size - 1);
int list_index = ray_coord_on_grid.y * list_info_buf.ray_grid_size.x + ray_coord_on_grid.x;
int list_index = ray_coord_on_grid.y * ray_grid_size.x + ray_coord_on_grid.x;
return list_index;
}
/**
* Return the corresponding cluster index in the `cluster_list_tx` for a given world position.
* It will clamp any coordinate outside valid bounds to nearest cluster.
*/
ivec3 surfel_cluster_index_get(ivec3 cluster_grid_size,
float4x4 irradiance_grid_world_to_local,
vec3 P)
{
vec3 lP = transform_point(irradiance_grid_world_to_local, P) * 0.5 + 0.5;
ivec3 cluster_index = ivec3(lP * vec3(cluster_grid_size));
cluster_index = clamp(cluster_index, ivec3(0), cluster_grid_size - 1);
return cluster_index;
}

View File

@ -24,6 +24,16 @@ GPU_SHADER_CREATE_INFO(eevee_debug_surfels)
.push_constant(Type::INT, "debug_mode")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_debug_irradiance_grid)
.additional_info("eevee_shared", "draw_view")
.fragment_out(0, Type::VEC4, "out_color")
.sampler(0, ImageType::FLOAT_3D, "debug_data_tx")
.push_constant(Type::MAT4, "grid_mat")
.push_constant(Type::INT, "debug_mode")
.vertex_source("eevee_debug_irradiance_grid_vert.glsl")
.fragment_source("eevee_debug_irradiance_grid_frag.glsl")
.do_static_compilation(true);
GPU_SHADER_INTERFACE_INFO(eevee_display_probe_grid_iface, "")
.smooth(Type::VEC2, "lP")
.flat(Type::IVEC3, "cell");
@ -67,6 +77,14 @@ GPU_SHADER_CREATE_INFO(eevee_surfel_light)
.compute_source("eevee_surfel_light_comp.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_surfel_cluster_build)
.local_group_size(SURFEL_GROUP_SIZE)
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
.storage_buf(CAPTURE_BUF_SLOT, Qualifier::READ, "CaptureInfoData", "capture_info_buf")
.image(0, GPU_R32I, Qualifier::READ_WRITE, ImageType::INT_3D, "cluster_list_img")
.compute_source("eevee_surfel_cluster_build_comp.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_surfel_list_build)
.local_group_size(SURFEL_GROUP_SIZE)
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
@ -119,10 +137,23 @@ GPU_SHADER_CREATE_INFO(eevee_lightprobe_irradiance_ray)
.image(1, GPU_RGBA32F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "irradiance_L1_a_img")
.image(2, GPU_RGBA32F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "irradiance_L1_b_img")
.image(3, GPU_RGBA32F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "irradiance_L1_c_img")
.image(4, GPU_R32F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "validity_img")
.image(4, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_3D, "virtual_offset_img")
.image(5, GPU_R32F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "validity_img")
.compute_source("eevee_lightprobe_irradiance_ray_comp.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_lightprobe_irradiance_offset)
.local_group_size(IRRADIANCE_GRID_GROUP_SIZE,
IRRADIANCE_GRID_GROUP_SIZE,
IRRADIANCE_GRID_GROUP_SIZE)
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
.storage_buf(0, Qualifier::READ, "int", "list_start_buf[]")
.storage_buf(6, Qualifier::READ, "SurfelListInfoData", "list_info_buf")
.image(0, GPU_R32I, Qualifier::READ, ImageType::INT_3D, "cluster_list_img")
.image(1, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "virtual_offset_img")
.compute_source("eevee_lightprobe_irradiance_offset_comp.glsl")
.do_static_compilation(true);
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -58,8 +58,7 @@ static void populate_cache_for_instance(Object &object,
using namespace blender::bke;
const GeometrySet &base_geometry = *dupli_object.preview_base_geometry;
const InstancesComponent &instances =
*base_geometry.get_component_for_read<InstancesComponent>();
const InstancesComponent &instances = *base_geometry.get_component<InstancesComponent>();
const AttributeAccessor instance_attributes = *instances.attributes();
const VArray attribute = *instance_attributes.lookup<ColorGeometry4f>(".viewer");
if (!attribute) {
@ -168,8 +167,8 @@ void OVERLAY_viewer_attribute_cache_populate(OVERLAY_Data *vedata, Object *objec
DupliObject *dupli_object = DRW_object_get_dupli(object);
if (dupli_object->preview_instance_index >= 0) {
const auto &instances = *dupli_object->preview_base_geometry
->get_component_for_read<blender::bke::InstancesComponent>();
const auto &instances =
*dupli_object->preview_base_geometry->get_component<blender::bke::InstancesComponent>();
if (instances.attributes()->contains(".viewer")) {
populate_cache_for_instance(*object, *pd, *dupli_object, opacity);
return;

View File

@ -11,7 +11,6 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/clog
../../../../extern/curve_fit_nd
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
)
@ -38,6 +37,7 @@ set(LIB
bf_blenkernel
PRIVATE bf::blenlib
PRIVATE bf::dna
PRIVATE bf::extern::curve_fit_nd
PRIVATE bf::intern::guardedalloc
extern_curve_fit_nd
)

View File

@ -206,12 +206,12 @@ static bke::GeometrySet get_original_geometry_eval_copy(Object &object)
switch (object.type) {
case OB_CURVES: {
Curves *curves = BKE_curves_copy_for_eval(static_cast<const Curves *>(object.data));
return bke::GeometrySet::create_with_curves(curves);
return bke::GeometrySet::from_curves(curves);
}
case OB_POINTCLOUD: {
PointCloud *points = BKE_pointcloud_copy_for_eval(
static_cast<const PointCloud *>(object.data));
return bke::GeometrySet::create_with_pointcloud(points);
return bke::GeometrySet::from_pointcloud(points);
}
case OB_MESH: {
const Mesh *mesh = static_cast<const Mesh *>(object.data);
@ -220,9 +220,9 @@ static bke::GeometrySet get_original_geometry_eval_copy(Object &object)
BKE_mesh_wrapper_ensure_mdata(mesh_copy);
Mesh *final_copy = BKE_mesh_copy_for_eval(mesh_copy);
BKE_id_free(nullptr, mesh_copy);
return bke::GeometrySet::create_with_mesh(final_copy);
return bke::GeometrySet::from_mesh(final_copy);
}
return bke::GeometrySet::create_with_mesh(BKE_mesh_copy_for_eval(mesh));
return bke::GeometrySet::from_mesh(BKE_mesh_copy_for_eval(mesh));
}
default:
return {};

View File

@ -3268,7 +3268,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
newob = ob;
}
const Curves *curves_eval = geometry.get_curves_for_read();
const Curves *curves_eval = geometry.get_curves();
Curves *new_curves = static_cast<Curves *>(BKE_id_new(bmain, ID_CV, newob->id.name + 2));
newob->data = new_curves;
@ -3567,12 +3567,12 @@ static int object_convert_exec(bContext *C, wmOperator *op)
newob->data = new_mesh;
newob->type = OB_MESH;
if (const Mesh *mesh_eval = geometry.get_mesh_for_read()) {
if (const Mesh *mesh_eval = geometry.get_mesh()) {
BKE_mesh_nomain_to_mesh(BKE_mesh_copy_for_eval(mesh_eval), new_mesh, newob);
BKE_object_material_from_eval_data(bmain, newob, &mesh_eval->id);
new_mesh->attributes_for_write().remove_anonymous();
}
else if (const Curves *curves_eval = geometry.get_curves_for_read()) {
else if (const Curves *curves_eval = geometry.get_curves()) {
bke::AnonymousAttributePropagationInfo propagation_info;
propagation_info.propagate_all = false;
Mesh *mesh = bke::curve_to_wire_mesh(curves_eval->geometry.wrap(), propagation_info);

View File

@ -830,7 +830,7 @@ static Mesh *create_applied_mesh_for_modifier(Depsgraph *depsgraph,
}
if (mti->modify_geometry_set) {
bke::GeometrySet geometry_set = bke::GeometrySet::create_with_mesh(
bke::GeometrySet geometry_set = bke::GeometrySet::from_mesh(
mesh_temp, bke::GeometryOwnershipType::Owned);
mti->modify_geometry_set(md_eval, &mectx, &geometry_set);
if (!geometry_set.has_mesh()) {
@ -1068,7 +1068,7 @@ static bool modifier_apply_obdata(
return false;
}
bke::GeometrySet geometry_set = bke::GeometrySet::create_with_curves(
bke::GeometrySet geometry_set = bke::GeometrySet::from_curves(
&curves, bke::GeometryOwnershipType::ReadOnly);
ModifierEvalContext mectx = {depsgraph, ob, ModifierApplyFlag(0)};
@ -1093,7 +1093,7 @@ static bool modifier_apply_obdata(
return false;
}
bke::GeometrySet geometry_set = bke::GeometrySet::create_with_pointcloud(
bke::GeometrySet geometry_set = bke::GeometrySet::from_pointcloud(
&points, bke::GeometryOwnershipType::ReadOnly);
ModifierEvalContext mectx = {depsgraph, ob, ModifierApplyFlag(0)};

View File

@ -128,7 +128,7 @@ static void get_context_path_node_geometry(const bContext &C,
SpaceNode &snode,
Vector<ui::ContextPathItem> &path)
{
if (snode.flag & SNODE_PIN || snode.geometry_nodes_type == SNODE_GEOMETRY_OPERATOR) {
if (snode.flag & SNODE_PIN || snode.geometry_nodes_type == SNODE_GEOMETRY_TOOL) {
context_path_add_node_tree_and_node_groups(snode, path);
}
else {

View File

@ -212,7 +212,7 @@ void GeometryDataSource::foreach_default_column_ids(
}
else if (G.debug_value == 4001 && component_->type() == bke::GeometryComponent::Type::Mesh) {
const bke::MeshComponent &component = static_cast<const bke::MeshComponent &>(*component_);
if (const Mesh *mesh = component.get_for_read()) {
if (const Mesh *mesh = component.get()) {
add_mesh_debug_column_names(*mesh, domain_, fn);
}
}
@ -239,7 +239,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (component_->type() == bke::GeometryComponent::Type::Instance) {
if (const bke::Instances *instances =
static_cast<const bke::InstancesComponent &>(*component_).get_for_read())
static_cast<const bke::InstancesComponent &>(*component_).get())
{
if (STREQ(column_id.name, "Name")) {
Span<int> reference_handles = instances->reference_handles();
@ -268,7 +268,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
else if (G.debug_value == 4001 && component_->type() == bke::GeometryComponent::Type::Mesh) {
const bke::MeshComponent &component = static_cast<const bke::MeshComponent &>(*component_);
if (const Mesh *mesh = component.get_for_read()) {
if (const Mesh *mesh = component.get()) {
if (std::unique_ptr<ColumnValues> values = build_mesh_debug_columns(
*mesh, domain_, column_id.name))
{
@ -352,7 +352,7 @@ IndexMask GeometryDataSource::apply_selection_filter(IndexMaskMemory &memory) co
BLI_assert(object_eval_->type == OB_MESH);
BLI_assert(object_eval_->mode == OB_MODE_EDIT);
Object *object_orig = DEG_get_original_object(object_eval_);
const Mesh *mesh_eval = geometry_set_.get_mesh_for_read();
const Mesh *mesh_eval = geometry_set_.get_mesh();
const bke::AttributeAccessor attributes_eval = mesh_eval->attributes();
Mesh *mesh_orig = (Mesh *)object_orig->data;
BMesh *bm = mesh_orig->edit_mesh->bm;
@ -398,7 +398,7 @@ IndexMask GeometryDataSource::apply_selection_filter(IndexMaskMemory &memory) co
case bke::GeometryComponent::Type::Curve: {
BLI_assert(object_eval_->type == OB_CURVES);
const bke::CurveComponent &component = static_cast<const bke::CurveComponent &>(*component_);
const Curves &curves_id = *component.get_for_read();
const Curves &curves_id = *component.get();
switch (domain_) {
case ATTR_DOMAIN_POINT:
return curves::retrieve_selected_points(curves_id, memory);
@ -437,7 +437,7 @@ void VolumeDataSource::foreach_default_column_ids(
std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
const Volume *volume = component_->get_for_read();
const Volume *volume = component_->get();
if (volume == nullptr) {
return {};
}
@ -485,7 +485,7 @@ std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values(
int VolumeDataSource::tot_rows() const
{
const Volume *volume = component_->get_for_read();
const Volume *volume = component_->get();
if (volume == nullptr) {
return 0;
}

View File

@ -59,7 +59,7 @@ class GeometryDataSource : public DataSource {
ExtraColumns extra_columns = {})
: object_eval_(object_eval),
geometry_set_(std::move(geometry_set)),
component_(geometry_set_.get_component_for_read(component_type)),
component_(geometry_set_.get_component(component_type)),
domain_(domain),
extra_columns_(std::move(extra_columns))
{
@ -89,7 +89,7 @@ class VolumeDataSource : public DataSource {
public:
VolumeDataSource(bke::GeometrySet geometry_set)
: geometry_set_(std::move(geometry_set)),
component_(geometry_set_.get_component_for_read<bke::VolumeComponent>())
component_(geometry_set_.get_component<bke::VolumeComponent>())
{
}

View File

@ -188,7 +188,7 @@ std::optional<int> GeometryDataSetTreeViewItem::count() const
/* Special case for volumes since there is no grid domain. */
if (component_type_ == bke::GeometryComponent::Type::Volume) {
if (const Volume *volume = geometry.get_volume_for_read()) {
if (const Volume *volume = geometry.get_volume()) {
return BKE_volume_num_grids(volume);
}
return 0;
@ -198,7 +198,7 @@ std::optional<int> GeometryDataSetTreeViewItem::count() const
return std::nullopt;
}
if (const bke::GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
if (const bke::GeometryComponent *component = geometry.get_component(component_type_)) {
return component->attribute_domain_size(*domain_);
}

View File

@ -4,6 +4,7 @@
set(INC
../include
../asset
../../asset_system
../../blenfont
../../blenkernel

View File

@ -51,6 +51,7 @@
#include "BKE_viewer_path.h"
#include "BKE_workspace.h"
#include "ED_asset_shelf.h"
#include "ED_geometry.h"
#include "ED_object.h"
#include "ED_outliner.h"
@ -279,6 +280,19 @@ static SpaceLink *view3d_create(const ScrArea * /*area*/, const Scene *scene)
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
region->flag = RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER;
/* asset shelf */
region = MEM_cnew<ARegion>("asset shelf for view3d");
BLI_addtail(&v3d->regionbase, region);
region->regiontype = RGN_TYPE_ASSET_SHELF;
region->alignment = RGN_ALIGN_BOTTOM;
/* asset shelf header */
region = MEM_cnew<ARegion>("asset shelf header for view3d");
BLI_addtail(&v3d->regionbase, region);
region->regiontype = RGN_TYPE_ASSET_SHELF_HEADER;
region->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
/* tool shelf */
region = MEM_cnew<ARegion>("toolshelf for view3d");
@ -1904,6 +1918,15 @@ static void view3d_tools_region_draw(const bContext *C, ARegion *region)
ED_region_panels_ex(C, region, contexts);
}
/* add handlers, stuff you only do once or on area/region changes */
static void view3d_asset_shelf_region_init(wmWindowManager *wm, ARegion *region)
{
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "3D View Generic", SPACE_VIEW3D, 0);
WM_event_add_keymap_handler(&region->handlers, keymap);
ED_asset_shelf_region_init(wm, region);
}
/* area (not region) level listener */
static void space_view3d_listener(const wmSpaceTypeListenerParams *params)
{
@ -2213,6 +2236,33 @@ void ED_spacetype_view3d()
art->draw = view3d_header_region_draw;
BLI_addhead(&st->regiontypes, art);
/* regions: asset shelf */
art = MEM_cnew<ARegionType>("spacetype view3d asset shelf region");
art->regionid = RGN_TYPE_ASSET_SHELF;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_ASSET_SHELF | ED_KEYMAP_FRAMES;
art->duplicate = ED_asset_shelf_region_duplicate;
art->free = ED_asset_shelf_region_free;
art->listener = ED_asset_shelf_region_listen;
art->poll = ED_asset_shelf_regions_poll;
art->snap_size = ED_asset_shelf_region_snap;
art->context = ED_asset_shelf_context;
art->init = view3d_asset_shelf_region_init;
art->layout = ED_asset_shelf_region_layout;
art->draw = ED_asset_shelf_region_draw;
BLI_addhead(&st->regiontypes, art);
/* regions: asset shelf header */
art = MEM_cnew<ARegionType>("spacetype view3d asset shelf header region");
art->regionid = RGN_TYPE_ASSET_SHELF_HEADER;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_ASSET_SHELF | ED_KEYMAP_VIEW2D | ED_KEYMAP_FOOTER;
art->init = ED_asset_shelf_header_region_init;
art->poll = ED_asset_shelf_regions_poll;
art->draw = ED_asset_shelf_header_region;
art->listener = ED_asset_shelf_header_region_listen;
art->context = ED_asset_shelf_context;
BLI_addhead(&st->regiontypes, art);
ED_asset_shelf_header_regiontype_register(art, SPACE_VIEW3D);
/* regions: hud */
art = ED_area_type_hud(st->spaceid);
BLI_addhead(&st->regiontypes, art);

View File

@ -546,13 +546,13 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
const float4x4 &base_transform,
const InstanceContext &base_instance_context)
{
for (const bke::GeometryComponent *component : geometry_set.get_components_for_read()) {
for (const bke::GeometryComponent *component : geometry_set.get_components()) {
const bke::GeometryComponent::Type type = component->type();
switch (type) {
case bke::GeometryComponent::Type::Mesh: {
const bke::MeshComponent &mesh_component = *static_cast<const bke::MeshComponent *>(
component);
const Mesh *mesh = mesh_component.get_for_read();
const Mesh *mesh = mesh_component.get();
if (mesh != nullptr && mesh->totvert > 0) {
const int mesh_index = gather_info.meshes.order.index_of(mesh);
const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
@ -571,7 +571,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
case bke::GeometryComponent::Type::PointCloud: {
const auto &pointcloud_component = *static_cast<const bke::PointCloudComponent *>(
component);
const PointCloud *pointcloud = pointcloud_component.get_for_read();
const PointCloud *pointcloud = pointcloud_component.get();
if (pointcloud != nullptr && pointcloud->totpoint > 0) {
const int pointcloud_index = gather_info.pointclouds.order.index_of(pointcloud);
const PointCloudRealizeInfo &pointcloud_info =
@ -587,7 +587,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
}
case bke::GeometryComponent::Type::Curve: {
const auto &curve_component = *static_cast<const bke::CurveComponent *>(component);
const Curves *curves = curve_component.get_for_read();
const Curves *curves = curve_component.get();
if (curves != nullptr && curves->geometry.curve_num > 0) {
const int curve_index = gather_info.curves.order.index_of(curves);
const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
@ -603,7 +603,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
}
case bke::GeometryComponent::Type::Instance: {
const auto &instances_component = *static_cast<const bke::InstancesComponent *>(component);
const Instances *instances = instances_component.get_for_read();
const Instances *instances = instances_component.get();
if (instances != nullptr && instances->instances_num() > 0) {
gather_realize_tasks_for_instances(
gather_info, *instances, base_transform, base_instance_context);
@ -673,12 +673,12 @@ static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(
static void gather_pointclouds_to_realize(const bke::GeometrySet &geometry_set,
VectorSet<const PointCloud *> &r_pointclouds)
{
if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) {
if (const PointCloud *pointcloud = geometry_set.get_pointcloud()) {
if (pointcloud->totpoint > 0) {
r_pointclouds.add(pointcloud);
}
}
if (const Instances *instances = geometry_set.get_instances_for_read()) {
if (const Instances *instances = geometry_set.get_instances()) {
instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
});
@ -875,12 +875,12 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
static void gather_meshes_to_realize(const bke::GeometrySet &geometry_set,
VectorSet<const Mesh *> &r_meshes)
{
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
if (const Mesh *mesh = geometry_set.get_mesh()) {
if (mesh->totvert > 0) {
r_meshes.add(mesh);
}
}
if (const Instances *instances = geometry_set.get_instances_for_read()) {
if (const Instances *instances = geometry_set.get_instances()) {
instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
gather_meshes_to_realize(instance_geometry_set, r_meshes);
});
@ -1215,12 +1215,12 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate(
static void gather_curves_to_realize(const bke::GeometrySet &geometry_set,
VectorSet<const Curves *> &r_curves)
{
if (const Curves *curves = geometry_set.get_curves_for_read()) {
if (const Curves *curves = geometry_set.get_curves()) {
if (curves->geometry.curve_num != 0) {
r_curves.add(curves);
}
}
if (const Instances *instances = geometry_set.get_instances_for_read()) {
if (const Instances *instances = geometry_set.get_instances()) {
instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
gather_curves_to_realize(instance_geometry_set, r_curves);
});

View File

@ -174,12 +174,12 @@ void read_mverts(Mesh &mesh, const P3fArraySamplePtr positions, const N3fArraySa
BKE_mesh_tag_positions_changed(&mesh);
if (normals) {
float(*vert_normals)[3] = BKE_mesh_vert_normals_for_write(&mesh);
Vector<float3> vert_normals(mesh.totvert);
for (const int64_t i : IndexRange(normals->size())) {
Imath::V3f nor_in = (*normals)[i];
copy_zup_from_yup(vert_normals[i], nor_in.getValue());
}
BKE_mesh_vert_normals_clear_dirty(&mesh);
bke::mesh_vert_normals_assign(mesh, std::move(vert_normals));
}
}

View File

@ -656,10 +656,9 @@ void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
return;
}
MutableSpan vert_normals{(float3 *)BKE_mesh_vert_normals_for_write(mesh), mesh->totvert};
BLI_STATIC_ASSERT(sizeof(normals_[0]) == sizeof(float3), "Expected float3 normals size");
vert_normals.copy_from({(float3 *)normals_.data(), int64_t(normals_.size())});
BKE_mesh_vert_normals_clear_dirty(mesh);
bke::mesh_vert_normals_assign(
*mesh, Span(reinterpret_cast<const float3 *>(normals_.data()), int64_t(normals_.size())));
}
void USDMeshReader::process_normals_face_varying(Mesh *mesh)

View File

@ -21,6 +21,8 @@
.grid_resolution_y = 4, \
.grid_resolution_z = 4, \
.grid_bake_samples = 2048, \
.grid_surface_bias = 0.05, \
.grid_escape_bias = 0.1, \
.grid_normal_bias = 0.3f, \
.grid_view_bias = 0.0f, \
.grid_facing_bias = 0.5f, \

View File

@ -57,6 +57,9 @@ typedef struct LightProbe {
int grid_resolution_z;
/** Irradiance grid: number of directions to evaluate light transfer in. */
int grid_bake_samples;
/** Irradiance grid: Virtual offset parameters. */
float grid_surface_bias;
float grid_escape_bias;
/** Irradiance grid: Sampling biases. */
float grid_normal_bias;
float grid_view_bias;
@ -245,6 +248,8 @@ typedef struct LightProbeBakingData {
float (*L1_b)[4];
float (*L1_c)[4];
float *validity;
/* Capture offset. Only for debugging. */
float (*virtual_offset)[4];
} LightProbeBakingData;
/**

View File

@ -1670,7 +1670,7 @@ typedef enum eSpaceNode_ShaderFrom {
/** #SpaceNode.geometry_nodes_type */
typedef enum SpaceNodeGeometryNodesType {
SNODE_GEOMETRY_MODIFIER = 0,
SNODE_GEOMETRY_OPERATOR = 1,
SNODE_GEOMETRY_TOOL = 1,
} SpaceNodeGeometryNodesType;
/** #SpaceNode.insert_ofs_dir */

View File

@ -198,6 +198,18 @@ static void rna_def_lightprobe(BlenderRNA *brna)
RNA_def_property_range(prop, 1, INT_MAX);
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "grid_surface_bias", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop,
"Capture Surface Bias",
"Moves capture points position away from surfaces to avoid artifacts");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "grid_escape_bias", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop, "Capture Escape Bias", "Moves capture points outside objects");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "surfel_density", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop,

View File

@ -4955,7 +4955,8 @@ static void rna_def_space_view3d(BlenderRNA *brna)
rna_def_space_generic_show_region_toggles(srna,
((1 << RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_TOOLS) |
(1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD)));
(1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD) |
(1 << RGN_TYPE_ASSET_SHELF)));
prop = RNA_def_property(srna, "camera", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
@ -7478,10 +7479,10 @@ static void rna_def_space_node(BlenderRNA *brna)
0,
"Modifier",
"Edit node group from active object's active modifier"},
{SNODE_GEOMETRY_OPERATOR,
"OPERATOR",
{SNODE_GEOMETRY_TOOL,
"TOOL",
0,
"Operator",
"Tool",
"Edit any geometry node group for use as an operator"},
{0, nullptr, 0, nullptr, nullptr},
};

View File

@ -1968,7 +1968,7 @@ static void rna_def_userdef_theme_asset_shelf(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
static void UNUSED_FUNCTION(rna_def_userdef_theme_spaces_asset_shelf_main)(StructRNA *srna)
static void rna_def_userdef_theme_spaces_asset_shelf_main(StructRNA *srna)
{
PropertyRNA *prop = RNA_def_property(srna, "asset_shelf", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@ -2487,6 +2487,8 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Object Origin Size", "Diameter in pixels for object/light origin display");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
rna_def_userdef_theme_spaces_asset_shelf_main(srna);
}
static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)

View File

@ -282,7 +282,7 @@ static void mesh_merge_transform(Mesh *result,
int cap_nfaces,
int *remap,
int remap_len,
const bool recalc_normals_later)
MutableSpan<float3> dst_vert_normals)
{
using namespace blender;
int *index_orig;
@ -305,8 +305,7 @@ static void mesh_merge_transform(Mesh *result,
}
/* We have to correct normals too, if we do not tag them as dirty later! */
if (!recalc_normals_later) {
float(*dst_vert_normals)[3] = BKE_mesh_vert_normals_for_write(result);
if (!dst_vert_normals.is_empty()) {
for (i = 0; i < cap_nverts; i++) {
mul_mat3_m4_v3(cap_offset, dst_vert_normals[cap_verts_index + i]);
normalize_v3(dst_vert_normals[cap_verts_index + i]);
@ -583,11 +582,10 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
unit_m4(current_offset);
blender::Span<blender::float3> src_vert_normals;
float(*dst_vert_normals)[3] = nullptr;
Vector<float3> dst_vert_normals;
if (!use_recalc_normals) {
src_vert_normals = mesh->vert_normals();
dst_vert_normals = BKE_mesh_vert_normals_for_write(result);
BKE_mesh_vert_normals_clear_dirty(result);
dst_vert_normals.reinitialize(result->totvert);
}
for (c = 1; c < count; c++) {
@ -608,7 +606,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
mul_m4_v3(current_offset, result_positions[i_dst]);
/* We have to correct normals too, if we do not tag them as dirty! */
if (!use_recalc_normals) {
if (!dst_vert_normals.is_empty()) {
copy_v3_v3(dst_vert_normals[i_dst], src_vert_normals[i]);
mul_mat3_m4_v3(current_offset, dst_vert_normals[i_dst]);
normalize_v3(dst_vert_normals[i_dst]);
@ -758,7 +756,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
start_cap_nfaces,
vgroup_start_cap_remap,
vgroup_start_cap_remap_len,
use_recalc_normals);
dst_vert_normals);
/* Identify doubles with first chunk */
if (use_merge) {
dm_mvert_map_doubles(full_doubles_map,
@ -788,7 +786,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
end_cap_nfaces,
vgroup_end_cap_remap,
vgroup_end_cap_remap_len,
use_recalc_normals);
dst_vert_normals);
/* Identify doubles with last chunk */
if (use_merge) {
dm_mvert_map_doubles(full_doubles_map,
@ -802,6 +800,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
}
/* done capping */
blender::bke::mesh_vert_normals_assign(*result, std::move(dst_vert_normals));
/* Handle merging */
tot_doubles = 0;
if (use_merge) {

View File

@ -846,7 +846,7 @@ static void modifyGeometry(ModifierData *md,
bool use_orig_index_verts = false;
bool use_orig_index_edges = false;
bool use_orig_index_faces = false;
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
if (const Mesh *mesh = geometry_set.get_mesh()) {
use_orig_index_verts = CustomData_has_layer(&mesh->vert_data, CD_ORIGINDEX);
use_orig_index_edges = CustomData_has_layer(&mesh->edge_data, CD_ORIGINDEX);
use_orig_index_faces = CustomData_has_layer(&mesh->face_data, CD_ORIGINDEX);
@ -905,7 +905,7 @@ static void modifyGeometry(ModifierData *md,
static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
bke::GeometrySet geometry_set = bke::GeometrySet::create_with_mesh(
bke::GeometrySet geometry_set = bke::GeometrySet::from_mesh(
mesh, bke::GeometryOwnershipType::Editable);
modifyGeometry(md, ctx, geometry_set);

View File

@ -34,7 +34,7 @@ static void geometry_node_tree_get_from_context(
const bContext *C, bNodeTreeType * /*treetype*/, bNodeTree **r_ntree, ID **r_id, ID **r_from)
{
const SpaceNode *snode = CTX_wm_space_node(C);
if (snode->geometry_nodes_type == SNODE_GEOMETRY_OPERATOR) {
if (snode->geometry_nodes_type == SNODE_GEOMETRY_TOOL) {
*r_ntree = snode->nodetree;
return;
}

View File

@ -76,7 +76,7 @@ static void node_geo_exec(GeoNodeExecParams params)
switch (component) {
case GeometryComponent::Type::Mesh: {
if (const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>()) {
if (const MeshComponent *component = geometry_set.get_component<MeshComponent>()) {
const AttributeAccessor attributes = *component->attributes();
params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT));
params.set_output("Edge Count", attributes.domain_size(ATTR_DOMAIN_EDGE));
@ -89,8 +89,7 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
case GeometryComponent::Type::Curve: {
if (const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>())
{
if (const CurveComponent *component = geometry_set.get_component<CurveComponent>()) {
const AttributeAccessor attributes = *component->attributes();
params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT));
params.set_output("Spline Count", attributes.domain_size(ATTR_DOMAIN_CURVE));
@ -101,8 +100,7 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
case GeometryComponent::Type::PointCloud: {
if (const PointCloudComponent *component =
geometry_set.get_component_for_read<PointCloudComponent>())
if (const PointCloudComponent *component = geometry_set.get_component<PointCloudComponent>())
{
const AttributeAccessor attributes = *component->attributes();
params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT));
@ -113,9 +111,7 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
case GeometryComponent::Type::Instance: {
if (const InstancesComponent *component =
geometry_set.get_component_for_read<InstancesComponent>())
{
if (const InstancesComponent *component = geometry_set.get_component<InstancesComponent>()) {
const AttributeAccessor attributes = *component->attributes();
params.set_output("Instance Count", attributes.domain_size(ATTR_DOMAIN_INSTANCE));
}

View File

@ -190,7 +190,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const bNode &node = params.node();
const eCustomDataType data_type = eCustomDataType(node.custom1);
const eAttrDomain domain = eAttrDomain(node.custom2);
Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
Vector<const GeometryComponent *> components = geometry_set.get_components();
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");

View File

@ -78,7 +78,7 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Note that it technically wouldn't be necessary to realize the instances for the first
* geometry input, but the boolean code expects the first shape for the difference operation
* to be a single mesh. */
if (const Mesh *mesh_in_a = set_a.get_mesh_for_read()) {
if (const Mesh *mesh_in_a = set_a.get_mesh()) {
meshes.append(mesh_in_a);
if (mesh_in_a->totcol == 0) {
/* Necessary for faces using the default material when there are no material slots. */
@ -94,7 +94,7 @@ static void node_geo_exec(GeoNodeExecParams params)
Vector<GeometrySet> geometry_sets = params.extract_input<Vector<GeometrySet>>("Mesh 2");
for (const GeometrySet &geometry : geometry_sets) {
if (const Mesh *mesh = geometry.get_mesh_for_read()) {
if (const Mesh *mesh = geometry.get_mesh()) {
meshes.append(mesh);
Array<short> map(mesh->totcol);
for (const int i : IndexRange(mesh->totcol)) {
@ -143,7 +143,7 @@ static void node_geo_exec(GeoNodeExecParams params)
selection.finish();
}
params.set_output("Mesh", GeometrySet::create_with_mesh(result));
params.set_output("Mesh", GeometrySet::from_mesh(result));
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without GMP"));

View File

@ -139,7 +139,7 @@ static void node_geo_exec(GeoNodeExecParams params)
instances->add_instance(handle, transform);
}
params.set_output("Instances", GeometrySet::create_with_instances(instances.release()));
params.set_output("Instances", GeometrySet::from_instances(instances.release()));
}
} // namespace blender::nodes::node_geo_collection_info_cc

View File

@ -138,7 +138,7 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
Span<float3> positions_span;
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
if (const Mesh *mesh = geometry_set.get_mesh()) {
count++;
if (const VArray positions = *mesh->attributes().lookup<float3>("position")) {
if (positions.is_span()) {
@ -149,7 +149,7 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
}
}
if (const PointCloud *points = geometry_set.get_pointcloud_for_read()) {
if (const PointCloud *points = geometry_set.get_pointcloud()) {
count++;
if (const VArray positions = *points->attributes().lookup<float3>("position")) {
if (positions.is_span()) {
@ -160,7 +160,7 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
}
}
if (const Curves *curves_id = geometry_set.get_curves_for_read()) {
if (const Curves *curves_id = geometry_set.get_curves()) {
count++;
span_count++;
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
@ -175,34 +175,34 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
/* If there is only one positions virtual array and it is already contiguous, avoid copying
* all of the positions and instead pass the span directly to the convex hull function. */
if (span_count == 1 && count == 1) {
return hull_from_bullet(geometry_set.get_mesh_for_read(), positions_span);
return hull_from_bullet(geometry_set.get_mesh(), positions_span);
}
Array<float3> positions(total_num);
int offset = 0;
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
if (const Mesh *mesh = geometry_set.get_mesh()) {
if (const VArray varray = *mesh->attributes().lookup<float3>("position")) {
varray.materialize(positions.as_mutable_span().slice(offset, varray.size()));
offset += varray.size();
}
}
if (const PointCloud *points = geometry_set.get_pointcloud_for_read()) {
if (const PointCloud *points = geometry_set.get_pointcloud()) {
if (const VArray varray = *points->attributes().lookup<float3>("position")) {
varray.materialize(positions.as_mutable_span().slice(offset, varray.size()));
offset += varray.size();
}
}
if (const Curves *curves_id = geometry_set.get_curves_for_read()) {
if (const Curves *curves_id = geometry_set.get_curves()) {
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
Span<float3> array = curves.evaluated_positions();
positions.as_mutable_span().slice(offset, array.size()).copy_from(array);
offset += array.size();
}
return hull_from_bullet(geometry_set.get_mesh_for_read(), positions);
return hull_from_bullet(geometry_set.get_mesh(), positions);
}
#endif /* WITH_BULLET */

View File

@ -112,7 +112,7 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
return;
}
const Curves &curves_id = *geometry_set.get_curves_for_read();
const Curves &curves_id = *geometry_set.get_curves();
const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
if (curves.curves_num() == 0) {
geometry_set.replace_curves(nullptr);

View File

@ -72,7 +72,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
const Curves &curves_id = *geometry_set.get_curves_for_read();
const Curves &curves_id = *geometry_set.get_curves();
const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
const bke::CurvesFieldContext context{curves, ATTR_DOMAIN_POINT};
fn::FieldEvaluator evaluator{context, curves.points_num()};

View File

@ -22,7 +22,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
const Curves &curves_id = *curve_set.get_curves_for_read();
const Curves &curves_id = *curve_set.get_curves();
const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
const VArray<bool> cyclic = curves.cyclic();

View File

@ -333,7 +333,7 @@ static void node_geo_exec(GeoNodeExecParams params)
r_center,
r_normal,
r_radius);
params.set_output("Curve", GeometrySet::create_with_curves(curves));
params.set_output("Curve", GeometrySet::from_curves(curves));
params.set_output("Center", r_center);
params.set_output("Normal", r_normal);
params.set_output("Radius", r_radius);
@ -348,7 +348,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<bool>("Connect Center"),
params.extract_input<bool>("Invert Arc"));
params.set_output("Curve", GeometrySet::create_with_curves(curves));
params.set_output("Curve", GeometrySet::from_curves(curves));
break;
}
}

View File

@ -109,7 +109,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<float3>("End Handle"),
std::max(params.extract_input<int>("Resolution"), 1),
mode);
params.set_output("Curve", GeometrySet::create_with_curves(curves));
params.set_output("Curve", GeometrySet::from_curves(curves));
}
} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc

View File

@ -203,7 +203,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
if (curves) {
params.set_output("Curve", GeometrySet::create_with_curves(curves));
params.set_output("Curve", GeometrySet::from_curves(curves));
}
else {
params.set_default_remaining_outputs();

Some files were not shown because too many files have changed in this diff Show More