Fix #141469: Geometry Nodes: use safer approach to modifying each instance geometry
Many nodes operate on all the instances that are passed into them. For example,
the Subdivision Surface node subdivides the mesh at the root but also instanced
meshes. This works well for most nodes, but there are a few nodes were the old
`modify_geometry_sets` function was not very well defined and it was tricky to
use correctly.
The fundamental problem was that the behavior is not obvious when a node creates
or modifies instances and how those are integrated with the already existing
instances.
This patch solves this with the following changes:
* Remove the old `GeometrySet::modify_geometry_sets` and related
`*_during_modify` methods.
* Add a new `blender::geometry::foreach_real_geometry` function that is similar
to the old `modify_geometry_sets` but has a more well-defined interface:
* It never passes instances into the callback. So existing instances can't be
modified with it.
* The callback is allowed to create new instances. This will automatically be
merged back with potentially already existing instances. The callback does
not have to worry about accidentally invalidating existing instances like
before.
* A few existing usages used `modify_geometry_sets` to actually modify existing
instances (usually just removing attributes). Those can't use the new
`foreach_real_geometry`, so they just get a custom simple recursive
implementation instead of using a generic function.
Pull Request: https://projects.blender.org/blender/blender/pulls/143898
This commit is contained in:
@@ -210,12 +210,6 @@ struct GeometrySet {
|
||||
* Remove all geometry components with types that are not in the provided list.
|
||||
*/
|
||||
void keep_only(Span<GeometryComponent::Type> component_types);
|
||||
/**
|
||||
* Keeps the provided geometry types, but also instances and edit data.
|
||||
* Instances must not be removed while using #modify_geometry_sets.
|
||||
*/
|
||||
void keep_only_during_modify(Span<GeometryComponent::Type> component_types);
|
||||
void remove_geometry_during_modify();
|
||||
|
||||
void add(const GeometryComponent &component);
|
||||
|
||||
@@ -272,14 +266,6 @@ struct GeometrySet {
|
||||
Vector<GeometryComponent::Type> gather_component_types(bool include_instances,
|
||||
bool ignore_empty) const;
|
||||
|
||||
using ForeachSubGeometryCallback = FunctionRef<void(GeometrySet &geometry_set)>;
|
||||
|
||||
/**
|
||||
* Modify every (recursive) instance separately. This is often more efficient than realizing all
|
||||
* instances just to change the same thing on all of them.
|
||||
*/
|
||||
void modify_geometry_sets(ForeachSubGeometryCallback callback);
|
||||
|
||||
/* Utility methods for creation. */
|
||||
/**
|
||||
* Create a new geometry set that only contains the given mesh.
|
||||
|
||||
@@ -168,6 +168,8 @@ class Instances {
|
||||
void add_instance(int instance_handle, const float4x4 &transform);
|
||||
|
||||
Span<InstanceReference> references() const;
|
||||
MutableSpan<InstanceReference> references_for_write();
|
||||
|
||||
void remove_unused_references();
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,52 +53,60 @@ static std::unique_ptr<BakeMaterialsList> materials_to_weak_references(
|
||||
return materials_list;
|
||||
}
|
||||
|
||||
static void prepare_geometry_for_bake_recursive(GeometrySet &geometry,
|
||||
BakeDataBlockMap *data_block_map)
|
||||
{
|
||||
if (Mesh *mesh = geometry.get_mesh_for_write()) {
|
||||
mesh->attributes_for_write().remove_anonymous();
|
||||
mesh->runtime->bake_materials = materials_to_weak_references(
|
||||
&mesh->mat, &mesh->totcol, data_block_map);
|
||||
}
|
||||
if (Curves *curves = geometry.get_curves_for_write()) {
|
||||
curves->geometry.wrap().attributes_for_write().remove_anonymous();
|
||||
curves->geometry.runtime->bake_materials = materials_to_weak_references(
|
||||
&curves->mat, &curves->totcol, data_block_map);
|
||||
}
|
||||
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
|
||||
for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
|
||||
if (base->type != GP_DRAWING) {
|
||||
continue;
|
||||
}
|
||||
greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
|
||||
drawing.strokes_for_write().attributes_for_write().remove_anonymous();
|
||||
}
|
||||
grease_pencil->attributes_for_write().remove_anonymous();
|
||||
grease_pencil->runtime->bake_materials = materials_to_weak_references(
|
||||
&grease_pencil->material_array, &grease_pencil->material_array_num, data_block_map);
|
||||
}
|
||||
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
|
||||
pointcloud->attributes_for_write().remove_anonymous();
|
||||
pointcloud->runtime->bake_materials = materials_to_weak_references(
|
||||
&pointcloud->mat, &pointcloud->totcol, data_block_map);
|
||||
}
|
||||
if (Volume *volume = geometry.get_volume_for_write()) {
|
||||
volume->runtime->bake_materials = materials_to_weak_references(
|
||||
&volume->mat, &volume->totcol, data_block_map);
|
||||
}
|
||||
if (bke::Instances *instances = geometry.get_instances_for_write()) {
|
||||
instances->attributes_for_write().remove_anonymous();
|
||||
instances->ensure_geometry_instances();
|
||||
for (bke::InstanceReference &reference : instances->references_for_write()) {
|
||||
if (reference.type() == bke::InstanceReference::Type::GeometrySet) {
|
||||
prepare_geometry_for_bake_recursive(reference.geometry_set(), data_block_map);
|
||||
}
|
||||
else {
|
||||
/* Can only bake geometry instances currently. */
|
||||
reference = bke::InstanceReference();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryBakeItem::prepare_geometry_for_bake(GeometrySet &main_geometry,
|
||||
BakeDataBlockMap *data_block_map)
|
||||
{
|
||||
main_geometry.ensure_owns_all_data();
|
||||
main_geometry.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
if (Mesh *mesh = geometry.get_mesh_for_write()) {
|
||||
mesh->attributes_for_write().remove_anonymous();
|
||||
mesh->runtime->bake_materials = materials_to_weak_references(
|
||||
&mesh->mat, &mesh->totcol, data_block_map);
|
||||
}
|
||||
if (Curves *curves = geometry.get_curves_for_write()) {
|
||||
curves->geometry.wrap().attributes_for_write().remove_anonymous();
|
||||
curves->geometry.runtime->bake_materials = materials_to_weak_references(
|
||||
&curves->mat, &curves->totcol, data_block_map);
|
||||
}
|
||||
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
|
||||
for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
|
||||
if (base->type != GP_DRAWING) {
|
||||
continue;
|
||||
}
|
||||
greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
|
||||
drawing.strokes_for_write().attributes_for_write().remove_anonymous();
|
||||
}
|
||||
grease_pencil->attributes_for_write().remove_anonymous();
|
||||
grease_pencil->runtime->bake_materials = materials_to_weak_references(
|
||||
&grease_pencil->material_array, &grease_pencil->material_array_num, data_block_map);
|
||||
}
|
||||
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
|
||||
pointcloud->attributes_for_write().remove_anonymous();
|
||||
pointcloud->runtime->bake_materials = materials_to_weak_references(
|
||||
&pointcloud->mat, &pointcloud->totcol, data_block_map);
|
||||
}
|
||||
if (Volume *volume = geometry.get_volume_for_write()) {
|
||||
volume->runtime->bake_materials = materials_to_weak_references(
|
||||
&volume->mat, &volume->totcol, data_block_map);
|
||||
}
|
||||
if (bke::Instances *instances = geometry.get_instances_for_write()) {
|
||||
instances->attributes_for_write().remove_anonymous();
|
||||
}
|
||||
geometry.keep_only_during_modify({GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::Curve,
|
||||
GeometryComponent::Type::GreasePencil,
|
||||
GeometryComponent::Type::PointCloud,
|
||||
GeometryComponent::Type::Volume,
|
||||
GeometryComponent::Type::Instance});
|
||||
});
|
||||
prepare_geometry_for_bake_recursive(main_geometry, data_block_map);
|
||||
}
|
||||
|
||||
static void restore_materials(Material ***materials,
|
||||
@@ -125,39 +133,47 @@ static void restore_materials(Material ***materials,
|
||||
}
|
||||
}
|
||||
|
||||
static void restore_data_blocks_recursive(GeometrySet &geometry, BakeDataBlockMap *data_block_map)
|
||||
{
|
||||
if (Mesh *mesh = geometry.get_mesh_for_write()) {
|
||||
restore_materials(
|
||||
&mesh->mat, &mesh->totcol, std::move(mesh->runtime->bake_materials), data_block_map);
|
||||
}
|
||||
if (Curves *curves = geometry.get_curves_for_write()) {
|
||||
restore_materials(&curves->mat,
|
||||
&curves->totcol,
|
||||
std::move(curves->geometry.runtime->bake_materials),
|
||||
data_block_map);
|
||||
}
|
||||
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
|
||||
restore_materials(&grease_pencil->material_array,
|
||||
&grease_pencil->material_array_num,
|
||||
std::move(grease_pencil->runtime->bake_materials),
|
||||
data_block_map);
|
||||
}
|
||||
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
|
||||
restore_materials(&pointcloud->mat,
|
||||
&pointcloud->totcol,
|
||||
std::move(pointcloud->runtime->bake_materials),
|
||||
data_block_map);
|
||||
}
|
||||
if (Volume *volume = geometry.get_volume_for_write()) {
|
||||
restore_materials(
|
||||
&volume->mat, &volume->totcol, std::move(volume->runtime->bake_materials), data_block_map);
|
||||
}
|
||||
if (bke::Instances *instances = geometry.get_instances_for_write()) {
|
||||
for (bke::InstanceReference &reference : instances->references_for_write()) {
|
||||
if (reference.type() == bke::InstanceReference::Type::GeometrySet) {
|
||||
restore_data_blocks_recursive(reference.geometry_set(), data_block_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryBakeItem::try_restore_data_blocks(GeometrySet &main_geometry,
|
||||
BakeDataBlockMap *data_block_map)
|
||||
{
|
||||
main_geometry.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
if (Mesh *mesh = geometry.get_mesh_for_write()) {
|
||||
restore_materials(
|
||||
&mesh->mat, &mesh->totcol, std::move(mesh->runtime->bake_materials), data_block_map);
|
||||
}
|
||||
if (Curves *curves = geometry.get_curves_for_write()) {
|
||||
restore_materials(&curves->mat,
|
||||
&curves->totcol,
|
||||
std::move(curves->geometry.runtime->bake_materials),
|
||||
data_block_map);
|
||||
}
|
||||
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
|
||||
restore_materials(&grease_pencil->material_array,
|
||||
&grease_pencil->material_array_num,
|
||||
std::move(grease_pencil->runtime->bake_materials),
|
||||
data_block_map);
|
||||
}
|
||||
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
|
||||
restore_materials(&pointcloud->mat,
|
||||
&pointcloud->totcol,
|
||||
std::move(pointcloud->runtime->bake_materials),
|
||||
data_block_map);
|
||||
}
|
||||
if (Volume *volume = geometry.get_volume_for_write()) {
|
||||
restore_materials(&volume->mat,
|
||||
&volume->totcol,
|
||||
std::move(volume->runtime->bake_materials),
|
||||
data_block_map);
|
||||
}
|
||||
});
|
||||
restore_data_blocks_recursive(main_geometry, data_block_map);
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
|
||||
@@ -164,19 +164,6 @@ void GeometrySet::keep_only(const Span<GeometryComponent::Type> component_types)
|
||||
}
|
||||
}
|
||||
|
||||
void GeometrySet::keep_only_during_modify(const Span<GeometryComponent::Type> component_types)
|
||||
{
|
||||
Vector<GeometryComponent::Type> extended_types = component_types;
|
||||
extended_types.append_non_duplicates(GeometryComponent::Type::Instance);
|
||||
extended_types.append_non_duplicates(GeometryComponent::Type::Edit);
|
||||
this->keep_only(extended_types);
|
||||
}
|
||||
|
||||
void GeometrySet::remove_geometry_during_modify()
|
||||
{
|
||||
this->keep_only_during_modify({});
|
||||
}
|
||||
|
||||
void GeometrySet::add(const GeometryComponent &component)
|
||||
{
|
||||
BLI_assert(!components_[size_t(component.type())]);
|
||||
@@ -796,39 +783,6 @@ Vector<GeometryComponent::Type> GeometrySet::gather_component_types(const bool i
|
||||
return types;
|
||||
}
|
||||
|
||||
static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
|
||||
Vector<GeometrySet *> &r_geometry_sets)
|
||||
{
|
||||
r_geometry_sets.append(&geometry_set);
|
||||
if (!geometry_set.has_instances()) {
|
||||
return;
|
||||
}
|
||||
/* In the future this can be improved by deduplicating instance references across different
|
||||
* instances. */
|
||||
Instances &instances = *geometry_set.get_instances_for_write();
|
||||
instances.ensure_geometry_instances();
|
||||
for (const int handle : instances.references().index_range()) {
|
||||
if (instances.references()[handle].type() == InstanceReference::Type::GeometrySet) {
|
||||
GeometrySet &instance_geometry = instances.geometry_set_from_reference(handle);
|
||||
gather_mutable_geometry_sets(instance_geometry, r_geometry_sets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
|
||||
{
|
||||
Vector<GeometrySet *> geometry_sets;
|
||||
gather_mutable_geometry_sets(*this, geometry_sets);
|
||||
if (geometry_sets.size() == 1) {
|
||||
/* Avoid possible overhead and a large call stack when multithreading is pointless. */
|
||||
callback(*geometry_sets.first());
|
||||
}
|
||||
else {
|
||||
threading::parallel_for_each(geometry_sets,
|
||||
[&](GeometrySet *geometry_set) { callback(*geometry_set); });
|
||||
}
|
||||
}
|
||||
|
||||
bool object_has_geometry_set_instances(const Object &object)
|
||||
{
|
||||
const GeometrySet *geometry_set = object.runtime->geometry_set_eval;
|
||||
|
||||
@@ -275,6 +275,11 @@ Span<InstanceReference> Instances::references() const
|
||||
return references_;
|
||||
}
|
||||
|
||||
MutableSpan<InstanceReference> Instances::references_for_write()
|
||||
{
|
||||
return references_;
|
||||
}
|
||||
|
||||
void Instances::remove(const IndexMask &mask, const AttributeFilter &attribute_filter)
|
||||
{
|
||||
const std::optional<IndexRange> masked_range = mask.to_range();
|
||||
|
||||
@@ -20,6 +20,7 @@ set(SRC
|
||||
intern/fillet_curves.cc
|
||||
intern/fit_curves.cc
|
||||
intern/interpolate_curves.cc
|
||||
intern/foreach_geometry.cc
|
||||
intern/join_geometries.cc
|
||||
intern/merge_curves.cc
|
||||
intern/merge_layers.cc
|
||||
@@ -63,6 +64,7 @@ set(SRC
|
||||
GEO_extract_elements.hh
|
||||
GEO_fillet_curves.hh
|
||||
GEO_fit_curves.hh
|
||||
GEO_foreach_geometry.hh
|
||||
GEO_interpolate_curves.hh
|
||||
GEO_join_geometries.hh
|
||||
GEO_merge_curves.hh
|
||||
|
||||
19
source/blender/geometry/GEO_foreach_geometry.hh
Normal file
19
source/blender/geometry/GEO_foreach_geometry.hh
Normal file
@@ -0,0 +1,19 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
/**
|
||||
* Modify every real geometry separately, including those from instances. The input to the
|
||||
* callback never contains instances. Newly generated instances will be merged with the
|
||||
* previously existing ones.
|
||||
*/
|
||||
void foreach_real_geometry(bke::GeometrySet &geometry,
|
||||
FunctionRef<void(bke::GeometrySet &geometry_set)> fn);
|
||||
|
||||
} // namespace blender::geometry
|
||||
@@ -8,10 +8,18 @@
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
/**
|
||||
* \param allow_merging_instance_references: If true, instance references from multiple instances
|
||||
* components may be merged when they are the same. This is typically good because it reduces the
|
||||
* amount of processing for later nodes. However, this may be undesirable in some cases if the
|
||||
* instance references are modified afterwards and the calling code assumes that the instances
|
||||
* references are just concatenated.
|
||||
*/
|
||||
bke::GeometrySet join_geometries(Span<bke::GeometrySet> geometries,
|
||||
const bke::AttributeFilter &attribute_filter,
|
||||
const std::optional<Span<bke::GeometryComponent::Type>>
|
||||
&component_types_to_join = std::nullopt);
|
||||
&component_types_to_join = std::nullopt,
|
||||
bool allow_merging_instance_references = true);
|
||||
|
||||
void join_attributes(const Span<const bke::GeometryComponent *> src_components,
|
||||
bke::GeometryComponent &r_result,
|
||||
|
||||
105
source/blender/geometry/intern/foreach_geometry.cc
Normal file
105
source/blender/geometry/intern/foreach_geometry.cc
Normal file
@@ -0,0 +1,105 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_instances.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_join_geometries.hh"
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
static void extract_real_geometries_recursive(
|
||||
bke::GeometrySet &geometry,
|
||||
Vector<int> &path,
|
||||
Map<bke::GeometrySet, Vector<Vector<int>>> &r_real_geometries)
|
||||
{
|
||||
bke::GeometrySet real_geometry = geometry;
|
||||
real_geometry.remove(bke::GeometryComponent::Type::Instance);
|
||||
geometry.keep_only({bke::GeometryComponent::Type::Instance});
|
||||
|
||||
r_real_geometries.lookup_or_add_default(std::move(real_geometry)).append(path);
|
||||
|
||||
bke::Instances *instances = geometry.get_instances_for_write();
|
||||
if (!instances) {
|
||||
return;
|
||||
}
|
||||
instances->ensure_geometry_instances();
|
||||
MutableSpan<bke::InstanceReference> references = instances->references_for_write();
|
||||
for (const int i : references.index_range()) {
|
||||
bke::InstanceReference &reference = references[i];
|
||||
if (reference.type() == bke::InstanceReference::Type::GeometrySet) {
|
||||
bke::GeometrySet &sub_geometry = reference.geometry_set();
|
||||
path.append(i);
|
||||
extract_real_geometries_recursive(sub_geometry, path, r_real_geometries);
|
||||
path.pop_last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reinsert_modified_geometry_recursive(bke::GeometrySet &geometry,
|
||||
const bke::GeometrySet &geometry_to_insert,
|
||||
const Span<int> path)
|
||||
{
|
||||
if (path.is_empty()) {
|
||||
/* Instance references must not be merged here as that could invalidate the paths. */
|
||||
const bool allow_merging_instance_references = false;
|
||||
/* Important to pass the old geometry first, so that the instance reference paths stay
|
||||
* valid. */
|
||||
geometry = join_geometries(
|
||||
{geometry, geometry_to_insert}, {}, {}, allow_merging_instance_references);
|
||||
return;
|
||||
}
|
||||
bke::Instances *instances = geometry.get_instances_for_write();
|
||||
BLI_assert(instances);
|
||||
const int reference_i = path.first();
|
||||
const MutableSpan<bke::InstanceReference> references = instances->references_for_write();
|
||||
BLI_assert(reference_i < references.size());
|
||||
bke::InstanceReference &reference = references[reference_i];
|
||||
BLI_assert(reference.type() == bke::InstanceReference::Type::GeometrySet);
|
||||
bke::GeometrySet &sub_geometry = reference.geometry_set();
|
||||
reinsert_modified_geometry_recursive(sub_geometry, geometry_to_insert, path.drop_front(1));
|
||||
}
|
||||
|
||||
struct GeometryWithPaths {
|
||||
bke::GeometrySet geometry;
|
||||
Vector<Vector<int>> paths;
|
||||
};
|
||||
|
||||
void foreach_real_geometry(bke::GeometrySet &geometry,
|
||||
FunctionRef<void(bke::GeometrySet &geometry_set)> fn)
|
||||
{
|
||||
/* Afterwards the geometry does not have realized geometry anymore. It has been extracted and
|
||||
* will be reinserted afterwards. */
|
||||
Map<bke::GeometrySet, Vector<Vector<int>>> real_geometries;
|
||||
{
|
||||
Vector<int> path;
|
||||
extract_real_geometries_recursive(geometry, path, real_geometries);
|
||||
}
|
||||
/* Take the geometries out of the map so that they can be edited in-place. As keys in the #Map
|
||||
* the geometries are const and thus can't be modified. */
|
||||
Vector<GeometryWithPaths> geometries_with_paths;
|
||||
for (auto &&item : real_geometries.items()) {
|
||||
geometries_with_paths.append({item.key, std::move(item.value)});
|
||||
}
|
||||
/* Clear to avoid extra references to the geometries which prohibit editing them in-place. */
|
||||
real_geometries.clear();
|
||||
|
||||
/* Actually modify the geometries in parallel. */
|
||||
threading::parallel_for(geometries_with_paths.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
bke::GeometrySet &geometry_to_modify = geometries_with_paths[i].geometry;
|
||||
fn(geometry_to_modify);
|
||||
}
|
||||
});
|
||||
|
||||
/* Reinsert modified geometries. */
|
||||
for (GeometryWithPaths &geometry_with_paths : geometries_with_paths) {
|
||||
for (const Span<int> path : geometry_with_paths.paths) {
|
||||
reinsert_modified_geometry_recursive(geometry, geometry_with_paths.geometry, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::geometry
|
||||
@@ -95,6 +95,7 @@ void join_attributes(const Span<const GeometryComponent *> src_components,
|
||||
}
|
||||
|
||||
static void join_instances(const Span<const GeometryComponent *> src_components,
|
||||
const bool allow_merging_instance_references,
|
||||
GeometrySet &result)
|
||||
{
|
||||
Array<int> offsets_data(src_components.size() + 1);
|
||||
@@ -109,7 +110,7 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
|
||||
|
||||
MutableSpan<int> all_handles = dst_instances->reference_handles_for_write();
|
||||
|
||||
Map<std::reference_wrapper<const bke::InstanceReference>, int> new_handle_by_src_reference;
|
||||
Map<std::reference_wrapper<const bke::InstanceReference>, int> new_handle_by_src_reference_cache;
|
||||
|
||||
for (const int i : src_components.index_range()) {
|
||||
const auto &src_component = static_cast<const bke::InstancesComponent &>(*src_components[i]);
|
||||
@@ -119,8 +120,13 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
|
||||
Array<int> handle_map(src_references.size());
|
||||
for (const int src_handle : src_references.index_range()) {
|
||||
const bke::InstanceReference &src_reference = src_references[src_handle];
|
||||
handle_map[src_handle] = new_handle_by_src_reference.lookup_or_add_cb(
|
||||
src_reference, [&]() { return dst_instances->add_new_reference(src_reference); });
|
||||
if (allow_merging_instance_references) {
|
||||
handle_map[src_handle] = new_handle_by_src_reference_cache.lookup_or_add_cb(
|
||||
src_reference, [&]() { return dst_instances->add_new_reference(src_reference); });
|
||||
}
|
||||
else {
|
||||
handle_map[src_handle] = dst_instances->add_new_reference(src_reference);
|
||||
}
|
||||
}
|
||||
|
||||
const IndexRange dst_range = offsets[i];
|
||||
@@ -144,6 +150,7 @@ static void join_volumes(const Span<const GeometryComponent *> /*src_components*
|
||||
static void join_component_type(const bke::GeometryComponent::Type component_type,
|
||||
const Span<GeometrySet> src_geometry_sets,
|
||||
const bke::AttributeFilter &attribute_filter,
|
||||
const bool allow_merging_instance_references,
|
||||
GeometrySet &result)
|
||||
{
|
||||
Vector<const GeometryComponent *> components;
|
||||
@@ -164,7 +171,7 @@ static void join_component_type(const bke::GeometryComponent::Type component_typ
|
||||
|
||||
switch (component_type) {
|
||||
case bke::GeometryComponent::Type::Instance:
|
||||
join_instances(components, result);
|
||||
join_instances(components, allow_merging_instance_references, result);
|
||||
return;
|
||||
case bke::GeometryComponent::Type::Volume:
|
||||
join_volumes(components, result);
|
||||
@@ -199,7 +206,8 @@ static void join_component_type(const bke::GeometryComponent::Type component_typ
|
||||
GeometrySet join_geometries(
|
||||
const Span<GeometrySet> geometries,
|
||||
const bke::AttributeFilter &attribute_filter,
|
||||
const std::optional<Span<GeometryComponent::Type>> &component_types_to_join)
|
||||
const std::optional<Span<GeometryComponent::Type>> &component_types_to_join,
|
||||
const bool allow_merging_instance_references)
|
||||
{
|
||||
GeometrySet result;
|
||||
result.name = geometries.is_empty() ? "" : geometries[0].name;
|
||||
@@ -218,7 +226,8 @@ GeometrySet join_geometries(
|
||||
supported_types);
|
||||
|
||||
for (const GeometryComponent::Type type : types_to_join) {
|
||||
join_component_type(type, geometries, attribute_filter, result);
|
||||
join_component_type(
|
||||
type, geometries, attribute_filter, allow_merging_instance_references, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -2426,11 +2426,17 @@ static void execute_realize_edit_data_tasks(const Span<RealizeEditDataTask> task
|
||||
|
||||
static void remove_id_attribute_from_instances(bke::GeometrySet &geometry_set)
|
||||
{
|
||||
geometry_set.modify_geometry_sets([&](bke::GeometrySet &sub_geometry) {
|
||||
if (Instances *instances = sub_geometry.get_instances_for_write()) {
|
||||
instances->attributes_for_write().remove("id");
|
||||
Instances *instances = geometry_set.get_instances_for_write();
|
||||
if (!instances) {
|
||||
return;
|
||||
}
|
||||
instances->attributes_for_write().remove("id");
|
||||
instances->ensure_geometry_instances();
|
||||
for (bke::InstanceReference &reference : instances->references_for_write()) {
|
||||
if (reference.type() == bke::InstanceReference::Type::GeometrySet) {
|
||||
remove_id_attribute_from_instances(reference.geometry_set());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Propagate instances from the old geometry set to the new geometry set if they are not
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "BKE_library.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_attribute_capture_cc {
|
||||
@@ -196,7 +198,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
GeometryComponent::Type::Curve,
|
||||
GeometryComponent::Type::GreasePencil};
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
for (const GeometryComponent::Type type : types) {
|
||||
if (geometry_set.has(type)) {
|
||||
capture_on(geometry_set.get_component_for_write(type));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_primitive_cuboid.hh"
|
||||
#include "GEO_transform.hh"
|
||||
|
||||
@@ -49,7 +50,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
* every instance). Because geometry components are reference counted anyway, we can just
|
||||
* repurpose the original geometry sets for the output. */
|
||||
if (params.output_is_required("Bounding Box")) {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &sub_geometry) {
|
||||
std::optional<Bounds<float3>> sub_bounds;
|
||||
|
||||
/* Reuse the min and max calculation if this is the main "real" geometry set. */
|
||||
@@ -61,7 +62,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
|
||||
if (!sub_bounds) {
|
||||
sub_geometry.remove_geometry_during_modify();
|
||||
sub_geometry.clear();
|
||||
}
|
||||
else {
|
||||
const float3 scale = sub_bounds->max - sub_bounds->min;
|
||||
@@ -69,7 +70,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
Mesh *mesh = geometry::create_cuboid_mesh(scale, 2, 2, 2, "uv_map");
|
||||
geometry::transform_mesh(*mesh, center, math::Quaternion::identity(), float3(1));
|
||||
sub_geometry.replace_mesh(mesh);
|
||||
sub_geometry.keep_only_during_modify({GeometryComponent::Type::Mesh});
|
||||
sub_geometry.keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "BKE_material.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -257,7 +258,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
#ifdef WITH_BULLET
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
Mesh *mesh = compute_hull(geometry_set);
|
||||
if (mesh) {
|
||||
geometry::debug_randomize_mesh_order(mesh);
|
||||
@@ -266,7 +267,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (geometry_set.has_grease_pencil()) {
|
||||
convex_hull_grease_pencil(geometry_set);
|
||||
}
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::Instance,
|
||||
GeometryComponent::Type::Edit});
|
||||
});
|
||||
|
||||
params.set_output("Convex Hull", std::move(geometry_set));
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_curve_fill_cc {
|
||||
@@ -310,8 +312,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
Field<int> group_index = params.extract_input<Field<int>>("Group ID");
|
||||
const GeometryNodeCurveFillMode mode = params.extract_input<GeometryNodeCurveFillMode>("Mode");
|
||||
|
||||
geometry_set.modify_geometry_sets(
|
||||
[&](GeometrySet &geometry_set) { curve_fill_calculate(geometry_set, mode, group_index); });
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
curve_fill_calculate(geometry, mode, group_index);
|
||||
});
|
||||
|
||||
params.set_output("Mesh", std::move(geometry_set));
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_fillet_curves.hh"
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
@@ -142,7 +143,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Curve");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_curves()) {
|
||||
const Curves &curves_id = *geometry_set.get_curves();
|
||||
const bke::CurvesGeometry &src_curves = curves_id.geometry.wrap();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_resample_curves.hh"
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
@@ -91,7 +92,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
switch (mode) {
|
||||
case GEO_NODE_CURVE_RESAMPLE_COUNT: {
|
||||
Field<int> count = params.extract_input<Field<int>>("Count");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (const Curves *src_curves_id = geometry.get_curves()) {
|
||||
const bke::CurvesGeometry &src_curves = src_curves_id->geometry.wrap();
|
||||
const bke::CurvesFieldContext field_context{*src_curves_id, AttrDomain::Curve};
|
||||
@@ -123,7 +124,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
|
||||
Field<float> length = params.extract_input<Field<float>>("Length");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (const Curves *src_curves_id = geometry.get_curves()) {
|
||||
const bke::CurvesGeometry &src_curves = src_curves_id->geometry.wrap();
|
||||
const bke::CurvesFieldContext field_context{*src_curves_id, AttrDomain::Curve};
|
||||
@@ -153,7 +154,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (const Curves *src_curves_id = geometry.get_curves()) {
|
||||
const bke::CurvesGeometry &src_curves = src_curves_id->geometry.wrap();
|
||||
const bke::CurvesFieldContext field_context{*src_curves_id, AttrDomain::Curve};
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_curve_reverse_cc {
|
||||
@@ -57,7 +59,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
const bke::CurvesFieldContext field_context{*curves_id, AttrDomain::Curve};
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "UI_interface_layout.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_curve_set_handle_type_cc {
|
||||
@@ -101,7 +103,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
std::atomic<bool> has_curves = false;
|
||||
std::atomic<bool> has_bezier = false;
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
has_curves = true;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "UI_interface_layout.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_set_curve_type.hh"
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
@@ -52,7 +53,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
|
||||
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_curves()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_subdivide_curves.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -88,7 +89,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);
|
||||
const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Curve");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_curves()) {
|
||||
const Curves &src_curves_id = *geometry_set.get_curves();
|
||||
Curves *dst_curves_id = subdivide_curves(src_curves_id, cuts_field, attribute_filter);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_instances.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_join_geometries.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
@@ -126,7 +127,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
bke::GeometryComponentEditData::remember_deformed_positions_if_necessary(curve_set);
|
||||
const AttributeFilter &attribute_filter = params.get_attribute_filter("Mesh");
|
||||
|
||||
curve_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(curve_set, [&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_curves()) {
|
||||
const Curves &curves = *geometry_set.get_curves();
|
||||
|
||||
@@ -142,7 +143,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (geometry_set.has_grease_pencil()) {
|
||||
grease_pencil_to_mesh(geometry_set, profile_set, scale_field, fill_caps, attribute_filter);
|
||||
}
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::Instance,
|
||||
GeometryComponent::Type::Edit});
|
||||
});
|
||||
|
||||
params.set_output("Mesh", std::move(curve_set));
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "BKE_instances.hh"
|
||||
#include "BKE_pointcloud.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_join_geometries.hh"
|
||||
#include "GEO_resample_curves.hh"
|
||||
|
||||
@@ -215,7 +216,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
switch (mode) {
|
||||
case GEO_NODE_CURVE_RESAMPLE_COUNT: {
|
||||
const Field<int> count = params.extract_input<Field<int>>("Count");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (const Curves *src_curves_id = geometry.get_curves()) {
|
||||
bke::CurvesGeometry dst_curves = geometry::resample_to_count(
|
||||
src_curves_id->geometry.wrap(),
|
||||
@@ -246,13 +247,15 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
layer_pointclouds_to_instances(pointcloud_by_layer, attribute_filter, geometry);
|
||||
}
|
||||
geometry.keep_only_during_modify({bke::GeometryComponent::Type::PointCloud});
|
||||
geometry.keep_only({bke::GeometryComponent::Type::PointCloud,
|
||||
bke::GeometryComponent::Type::Instance,
|
||||
bke::GeometryComponent::Type::Edit});
|
||||
});
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
|
||||
const Field<float> length = params.extract_input<Field<float>>("Length");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (const Curves *src_curves_id = geometry.get_curves()) {
|
||||
bke::CurvesGeometry dst_curves = geometry::resample_to_length(
|
||||
src_curves_id->geometry.wrap(),
|
||||
@@ -283,12 +286,14 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
layer_pointclouds_to_instances(pointcloud_by_layer, attribute_filter, geometry);
|
||||
}
|
||||
geometry.keep_only_during_modify({bke::GeometryComponent::Type::PointCloud});
|
||||
geometry.keep_only({bke::GeometryComponent::Type::PointCloud,
|
||||
bke::GeometryComponent::Type::Instance,
|
||||
bke::GeometryComponent::Type::Edit});
|
||||
});
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_CURVE_RESAMPLE_EVALUATED: {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (const Curves *src_curves_id = geometry.get_curves()) {
|
||||
bke::CurvesGeometry dst_curves = geometry::resample_to_evaluated(
|
||||
src_curves_id->geometry.wrap(),
|
||||
@@ -318,7 +323,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
layer_pointclouds_to_instances(pointcloud_by_layer, attribute_filter, geometry);
|
||||
}
|
||||
geometry.keep_only_during_modify({bke::GeometryComponent::Type::PointCloud});
|
||||
geometry.keep_only({bke::GeometryComponent::Type::PointCloud,
|
||||
bke::GeometryComponent::Type::Instance,
|
||||
bke::GeometryComponent::Type::Edit});
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_trim_curves.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
@@ -219,7 +220,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) {
|
||||
Field<float> start_field = params.extract_input<Field<float>>("Start");
|
||||
Field<float> end_field = params.extract_input<Field<float>>("End");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
geometry_set_curve_trim(
|
||||
geometry_set, mode, selection_field, start_field, end_field, attribute_filter);
|
||||
});
|
||||
@@ -227,7 +228,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
|
||||
Field<float> start_field = params.extract_input<Field<float>>("Start_001");
|
||||
Field<float> end_field = params.extract_input<Field<float>>("End_001");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
geometry_set_curve_trim(
|
||||
geometry_set, mode, selection_field, start_field, end_field, attribute_filter);
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "UI_interface_layout.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_separate_geometry.hh"
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
@@ -74,7 +75,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
geometry::separate_geometry(geometry_set, domain, mode, selection, attribute_filter, is_error);
|
||||
}
|
||||
else {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
bool is_error;
|
||||
/* Invert here because we want to keep the things not in the selection. */
|
||||
geometry::separate_geometry(
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "BKE_volume.hh"
|
||||
#include "BKE_volume_grid.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -195,9 +196,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
threshold = params.extract_input<float>("Threshold");
|
||||
}
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_volume()) {
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
const VolumeComponent *component = geometry_set.get_component<VolumeComponent>();
|
||||
@@ -241,7 +242,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
geometry::debug_randomize_point_order(pointcloud);
|
||||
|
||||
geometry_set.replace_pointcloud(pointcloud);
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud});
|
||||
geometry_set.keep_only({GeometryComponent::Type::PointCloud, GeometryComponent::Type::Edit});
|
||||
});
|
||||
|
||||
params.set_output("Points", std::move(geometry_set));
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "UI_interface_layout.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -594,12 +595,12 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
lazy_threading::send_hint();
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
point_distribution_calculate(
|
||||
geometry_set, selection_field, method, seed, attribute_outputs, params);
|
||||
/* Keep instances because the original geometry set may contain instances that are processed as
|
||||
* well. */
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud});
|
||||
geometry_set.keep_only({GeometryComponent::Type::PointCloud, GeometryComponent::Type::Edit});
|
||||
});
|
||||
|
||||
params.set_output("Points", std::move(geometry_set));
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -920,7 +921,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
|
||||
const bool keep_boundaries = params.extract_input<bool>("Keep Boundaries");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (const Mesh *mesh = geometry_set.get_mesh()) {
|
||||
Mesh *new_mesh = calc_dual_mesh(
|
||||
*mesh, keep_boundaries, params.get_attribute_filter("Dual Mesh"));
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "FN_multi_function_builder.hh"
|
||||
|
||||
#include "UI_interface_layout.hh"
|
||||
@@ -317,8 +319,9 @@ static void duplicate_curves(GeometrySet &geometry_set,
|
||||
const IndexAttributes &attribute_outputs,
|
||||
const AttributeFilter &attribute_filter)
|
||||
{
|
||||
geometry_set.keep_only_during_modify(
|
||||
{GeometryComponent::Type::Curve, GeometryComponent::Type::GreasePencil});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Curve,
|
||||
GeometryComponent::Type::GreasePencil,
|
||||
GeometryComponent::Type::Edit});
|
||||
GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);
|
||||
if (const Curves *curves_id = geometry_set.get_curves()) {
|
||||
const bke::CurvesFieldContext field_context{*curves_id, AttrDomain::Curve};
|
||||
@@ -463,10 +466,10 @@ static void duplicate_faces(GeometrySet &geometry_set,
|
||||
const AttributeFilter &attribute_filter)
|
||||
{
|
||||
if (!geometry_set.has_mesh()) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.clear();
|
||||
return;
|
||||
}
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit});
|
||||
|
||||
const Mesh &mesh = *geometry_set.get_mesh();
|
||||
const OffsetIndices faces = mesh.faces();
|
||||
@@ -649,7 +652,7 @@ static void duplicate_edges(GeometrySet &geometry_set,
|
||||
const AttributeFilter &attribute_filter)
|
||||
{
|
||||
if (!geometry_set.has_mesh()) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.clear();
|
||||
return;
|
||||
};
|
||||
const Mesh &mesh = *geometry_set.get_mesh();
|
||||
@@ -994,8 +997,8 @@ static void duplicate_points(GeometrySet &geometry_set,
|
||||
break;
|
||||
}
|
||||
}
|
||||
component_types.append(GeometryComponent::Type::Instance);
|
||||
geometry_set.keep_only_during_modify(component_types);
|
||||
component_types.append(GeometryComponent::Type::Edit);
|
||||
geometry_set.keep_only(component_types);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1015,7 +1018,7 @@ static void duplicate_layers(GeometrySet &geometry_set,
|
||||
geometry_set.clear();
|
||||
return;
|
||||
}
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::GreasePencil});
|
||||
geometry_set.keep_only({GeometryComponent::Type::GreasePencil, GeometryComponent::Type::Edit});
|
||||
GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);
|
||||
const GreasePencil &src_grease_pencil = *geometry_set.get_grease_pencil();
|
||||
|
||||
@@ -1179,7 +1182,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
|
||||
}
|
||||
else {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
switch (duplicate_domain) {
|
||||
case AttrDomain::Curve:
|
||||
duplicate_curves(
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_to_curve.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -72,10 +73,10 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
const Mesh *mesh = geometry_set.get_mesh();
|
||||
if (mesh == nullptr) {
|
||||
geometry_set.keep_only({GeometryComponent::Type::Instance});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,13 +89,13 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
IndexMask start_verts = evaluator.get_evaluated_as_mask(1);
|
||||
|
||||
if (start_verts.is_empty()) {
|
||||
geometry_set.keep_only({GeometryComponent::Type::Instance});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
|
||||
geometry_set.replace_curves(edge_paths_to_curves_convert(
|
||||
*mesh, start_verts, next_vert, params.get_attribute_filter("Curves")));
|
||||
geometry_set.keep_only({GeometryComponent::Type::Curve, GeometryComponent::Type::Instance});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Curve, GeometryComponent::Type::Edit});
|
||||
});
|
||||
|
||||
params.set_output("Curves", std::move(geometry_set));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_split_edges.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -27,7 +28,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (const Mesh *mesh = geometry_set.get_mesh()) {
|
||||
const bke::MeshFieldContext field_context{*mesh, AttrDomain::Edge};
|
||||
fn::FieldEvaluator selection_evaluator{field_context, mesh->edges_num};
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "BKE_mesh_mapping.hh"
|
||||
#include "BKE_mesh_runtime.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_selection.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
@@ -1476,7 +1477,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Mesh");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
|
||||
switch (mode) {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "BKE_mesh.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_flip_faces_cc {
|
||||
@@ -25,7 +27,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
const bke::MeshFieldContext field_context(*mesh, AttrDomain::Face);
|
||||
fn::FieldEvaluator evaluator(field_context, mesh->faces_num);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_instances.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_join_geometries.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -187,16 +188,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
instance.ensure_owns_direct_data();
|
||||
const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Instances");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
/* It's important not to invalidate the existing #InstancesComponent because it owns references
|
||||
* to other geometry sets that are processed by this node. */
|
||||
InstancesComponent &instances_component =
|
||||
geometry_set.get_component_for_write<InstancesComponent>();
|
||||
bke::Instances *dst_instances = instances_component.get_for_write();
|
||||
if (dst_instances == nullptr) {
|
||||
dst_instances = new bke::Instances();
|
||||
instances_component.replace(dst_instances);
|
||||
}
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
bke::Instances *dst_instances = new bke::Instances();
|
||||
|
||||
const Array<GeometryComponent::Type> types{GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::PointCloud,
|
||||
@@ -226,7 +219,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (geometry_set.has_grease_pencil()) {
|
||||
using namespace bke::greasepencil;
|
||||
const GreasePencil &grease_pencil = *geometry_set.get_grease_pencil();
|
||||
bke::Instances *instances = new bke::Instances();
|
||||
bke::Instances *instances_per_layer = new bke::Instances();
|
||||
for (const int layer_index : grease_pencil.layers().index_range()) {
|
||||
const Layer &layer = grease_pencil.layer(layer_index);
|
||||
const Drawing *drawing = grease_pencil.get_eval_drawing(layer);
|
||||
@@ -239,8 +232,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
/* Add an empty reference so the number of layers and instances match.
|
||||
* This makes it easy to reconstruct the layers afterwards and keep their attributes.
|
||||
* Although in this particular case we don't propagate the attributes. */
|
||||
const int handle = instances->add_reference(bke::InstanceReference());
|
||||
instances->add_instance(handle, layer_transform);
|
||||
const int handle = instances_per_layer->add_reference(bke::InstanceReference());
|
||||
instances_per_layer->add_instance(handle, layer_transform);
|
||||
continue;
|
||||
}
|
||||
/* TODO: Attributes are not propagating from the curves or the points. */
|
||||
@@ -254,25 +247,23 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
params,
|
||||
attributes_to_propagate);
|
||||
GeometrySet temp_set = GeometrySet::from_instances(layer_instances);
|
||||
const int handle = instances->add_reference(bke::InstanceReference{temp_set});
|
||||
instances->add_instance(handle, layer_transform);
|
||||
const int handle = instances_per_layer->add_reference(bke::InstanceReference{temp_set});
|
||||
instances_per_layer->add_instance(handle, layer_transform);
|
||||
}
|
||||
|
||||
bke::copy_attributes(geometry_set.get_grease_pencil()->attributes(),
|
||||
bke::AttrDomain::Layer,
|
||||
bke::AttrDomain::Instance,
|
||||
attribute_filter,
|
||||
instances->attributes_for_write());
|
||||
instances_per_layer->attributes_for_write());
|
||||
GeometrySet new_instances = geometry::join_geometries(
|
||||
{GeometrySet::from_instances(dst_instances, bke::GeometryOwnershipType::Editable),
|
||||
GeometrySet::from_instances(instances)},
|
||||
{GeometrySet::from_instances(dst_instances),
|
||||
GeometrySet::from_instances(instances_per_layer)},
|
||||
attribute_filter);
|
||||
instances_component.replace(
|
||||
new_instances.get_component_for_write<InstancesComponent>().release());
|
||||
|
||||
geometry_set.replace_grease_pencil(nullptr);
|
||||
dst_instances = new_instances.get_component_for_write<InstancesComponent>().release();
|
||||
}
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
geometry_set.replace_instances(dst_instances);
|
||||
});
|
||||
|
||||
/* Unused references may have been added above. Remove those now so that other nodes don't
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_material_replace_cc {
|
||||
@@ -40,7 +42,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
replace_materials({mesh->mat, mesh->totcol}, old_material, new_material);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_merge_by_distance.hh"
|
||||
#include "GEO_point_merge_by_distance.hh"
|
||||
|
||||
@@ -103,7 +104,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const float merge_distance = params.extract_input<float>("Distance");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (const PointCloud *pointcloud = geometry_set.get_pointcloud()) {
|
||||
PointCloud *result = pointcloud_merge_by_distance(
|
||||
*pointcloud, merge_distance, selection, params.get_attribute_filter("Geometry"));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_merge_layers.hh"
|
||||
|
||||
#include "BKE_grease_pencil.hh"
|
||||
@@ -170,8 +171,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
const NodeAttributeFilter attribute_filter = params.get_attribute_filter("Grease Pencil");
|
||||
|
||||
main_geometry.modify_geometry_sets(
|
||||
[&](GeometrySet &geometry) { merge_layers(geometry, storage, params, attribute_filter); });
|
||||
geometry::foreach_real_geometry(main_geometry, [&](GeometrySet &geometry) {
|
||||
merge_layers(geometry, storage, params, attribute_filter);
|
||||
});
|
||||
|
||||
params.set_output("Grease Pencil", std::move(main_geometry));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "BKE_subdiv.hh"
|
||||
#include "BKE_subdiv_mesh.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -72,7 +73,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
return;
|
||||
}
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (const Mesh *mesh = geometry_set.get_mesh()) {
|
||||
geometry_set.replace_mesh(simple_subdivide_mesh(*mesh, level));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_to_curve.hh"
|
||||
|
||||
#include "UI_interface_c.hh"
|
||||
@@ -39,10 +40,10 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Mode mode = Mode(params.node().custom1);
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
const Mesh *mesh = geometry_set.get_mesh();
|
||||
if (mesh == nullptr) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,7 +55,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
|
||||
if (selection.is_empty()) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -70,7 +71,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
|
||||
if (selection.is_empty()) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -80,7 +81,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
break;
|
||||
}
|
||||
}
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Curve});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Curve, GeometryComponent::Type::Edit});
|
||||
});
|
||||
|
||||
params.set_output("Curve", std::move(geometry_set));
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "UI_interface_layout.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "FN_multi_function_builder.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -60,12 +62,12 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
|
||||
{
|
||||
const Mesh *mesh = geometry_set.get_mesh();
|
||||
if (mesh == nullptr) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
const int domain_size = mesh->attributes().domain_size(domain);
|
||||
if (domain_size == 0) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
const AttributeAccessor src_attributes = mesh->attributes();
|
||||
@@ -138,7 +140,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
|
||||
}
|
||||
|
||||
geometry_set.replace_pointcloud(pointcloud);
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud});
|
||||
geometry_set.keep_only({GeometryComponent::Type::PointCloud, GeometryComponent::Type::Edit});
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
@@ -161,7 +163,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Points");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
switch (mode) {
|
||||
case GEO_NODE_MESH_TO_POINTS_VERTICES:
|
||||
geometry_set_mesh_to_points(geometry_set,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "BKE_lib_id.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_to_volume.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
@@ -127,11 +128,11 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set(params.extract_input<GeometrySet>("Mesh"));
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_mesh()) {
|
||||
Volume *volume = create_volume_from_mesh(*geometry_set.get_mesh(), params);
|
||||
geometry_set.replace_volume(volume);
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Volume});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Volume, GeometryComponent::Type::Edit});
|
||||
}
|
||||
});
|
||||
params.set_output("Volume", std::move(geometry_set));
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "BLI_sort.hh"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
@@ -174,14 +175,14 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<float> weight_field = params.extract_input<Field<float>>("Weight");
|
||||
|
||||
const NodeAttributeFilter attribute_filter = params.get_attribute_filter("Curves");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
geometry_set.replace_curves(nullptr);
|
||||
if (const PointCloud *points = geometry_set.get_pointcloud()) {
|
||||
Curves *curves_id = curves_from_points(
|
||||
*points, group_id_field, weight_field, attribute_filter);
|
||||
geometry_set.replace_curves(curves_id);
|
||||
}
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Curve});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Curve, GeometryComponent::Type::Edit});
|
||||
});
|
||||
|
||||
params.set_output("Curves", std::move(geometry_set));
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_points_to_vertices_cc {
|
||||
@@ -29,11 +31,11 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
|
||||
{
|
||||
const PointCloud *points = geometry_set.get_pointcloud();
|
||||
if (points == nullptr) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
if (points->totpoint == 0) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
geometry_set.keep_only({GeometryComponent::Type::Edit});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +87,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
|
||||
mesh->tag_overlapping_none();
|
||||
|
||||
geometry_set.replace_mesh(mesh);
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit});
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
@@ -93,7 +95,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
|
||||
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
geometry_set_points_to_vertices(
|
||||
geometry_set, selection_field, params.get_attribute_filter("Mesh"));
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_points_to_volume.hh"
|
||||
|
||||
#include "BKE_lib_id.hh"
|
||||
@@ -115,7 +116,7 @@ static void initialize_volume_component_from_points(GeoNodeExecParams ¶ms,
|
||||
blender::geometry::fog_volume_grid_add_from_points(
|
||||
volume, "density", positions, radii, voxel_size, density);
|
||||
|
||||
r_geometry_set.keep_only_during_modify({GeometryComponent::Type::Volume});
|
||||
r_geometry_set.keep_only({GeometryComponent::Type::Volume, GeometryComponent::Type::Edit});
|
||||
r_geometry_set.replace_volume(volume);
|
||||
}
|
||||
|
||||
@@ -172,7 +173,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
initialize_volume_component_from_points(params, geometry_set);
|
||||
});
|
||||
params.set_output("Volume", std::move(geometry_set));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_instances.hh"
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include <fmt/format.h>
|
||||
@@ -36,6 +37,82 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_input<decl::String>("Name").is_attribute_name().hide_label();
|
||||
}
|
||||
|
||||
struct RemoveAttributeParams {
|
||||
PatternMode pattern_mode;
|
||||
std::string pattern;
|
||||
std::string wildcard_prefix;
|
||||
std::string wildcard_suffix;
|
||||
|
||||
Set<std::string> removed_attributes;
|
||||
Set<std::string> failed_attributes;
|
||||
};
|
||||
|
||||
static void remove_attributes_recursive(GeometrySet &geometry_set, RemoveAttributeParams ¶ms)
|
||||
{
|
||||
for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::PointCloud,
|
||||
GeometryComponent::Type::Curve,
|
||||
GeometryComponent::Type::Instance,
|
||||
GeometryComponent::Type::GreasePencil})
|
||||
{
|
||||
if (!geometry_set.has(type)) {
|
||||
continue;
|
||||
}
|
||||
/* First check if the attribute exists before getting write access,
|
||||
* to avoid potentially expensive unnecessary copies. */
|
||||
const GeometryComponent &read_only_component = *geometry_set.get_component(type);
|
||||
Vector<std::string> attributes_to_remove;
|
||||
switch (params.pattern_mode) {
|
||||
case PatternMode::Exact: {
|
||||
if (read_only_component.attributes()->contains(params.pattern)) {
|
||||
attributes_to_remove.append(params.pattern);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PatternMode::Wildcard: {
|
||||
read_only_component.attributes()->foreach_attribute([&](const bke::AttributeIter &iter) {
|
||||
const StringRef attribute_name = iter.name;
|
||||
if (bke::attribute_name_is_anonymous(attribute_name)) {
|
||||
return;
|
||||
}
|
||||
if (attribute_name.startswith(params.wildcard_prefix) &&
|
||||
attribute_name.endswith(params.wildcard_suffix))
|
||||
{
|
||||
attributes_to_remove.append(attribute_name);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (attributes_to_remove.is_empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
GeometryComponent &component = geometry_set.get_component_for_write(type);
|
||||
for (const StringRef attribute_name : attributes_to_remove) {
|
||||
if (!bke::allow_procedural_attribute_access(attribute_name)) {
|
||||
continue;
|
||||
}
|
||||
if (component.attributes_for_write()->remove(attribute_name)) {
|
||||
params.removed_attributes.add(attribute_name);
|
||||
}
|
||||
else {
|
||||
params.failed_attributes.add(attribute_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
|
||||
instances->ensure_geometry_instances();
|
||||
for (bke::InstanceReference &reference : instances->references_for_write()) {
|
||||
if (reference.type() == bke::InstanceReference::Type::GeometrySet) {
|
||||
remove_attributes_recursive(reference.geometry_set(), params);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
||||
@@ -44,6 +121,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
params.set_output("Geometry", std::move(geometry_set));
|
||||
return;
|
||||
}
|
||||
|
||||
PatternMode pattern_mode = params.get_input<PatternMode>("Pattern Mode");
|
||||
if (pattern_mode == PatternMode::Wildcard) {
|
||||
const int wildcard_count = Span(pattern.c_str(), pattern.size()).count('*');
|
||||
@@ -58,83 +136,24 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
}
|
||||
|
||||
StringRef wildcard_prefix;
|
||||
StringRef wildcard_suffix;
|
||||
RemoveAttributeParams removal_params;
|
||||
removal_params.pattern_mode = pattern_mode;
|
||||
removal_params.pattern = pattern;
|
||||
if (pattern_mode == PatternMode::Wildcard) {
|
||||
const int wildcard_index = pattern.find('*');
|
||||
wildcard_prefix = StringRef(pattern).substr(0, wildcard_index);
|
||||
wildcard_suffix = StringRef(pattern).substr(wildcard_index + 1);
|
||||
removal_params.wildcard_prefix = StringRef(pattern).substr(0, wildcard_index);
|
||||
removal_params.wildcard_suffix = StringRef(pattern).substr(wildcard_index + 1);
|
||||
}
|
||||
|
||||
Mutex attribute_log_mutex;
|
||||
Set<std::string> removed_attributes;
|
||||
Set<std::string> failed_attributes;
|
||||
remove_attributes_recursive(geometry_set, removal_params);
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::PointCloud,
|
||||
GeometryComponent::Type::Curve,
|
||||
GeometryComponent::Type::Instance,
|
||||
GeometryComponent::Type::GreasePencil})
|
||||
{
|
||||
if (!geometry_set.has(type)) {
|
||||
continue;
|
||||
}
|
||||
/* First check if the attribute exists before getting write access,
|
||||
* to avoid potentially expensive unnecessary copies. */
|
||||
const GeometryComponent &read_only_component = *geometry_set.get_component(type);
|
||||
Vector<std::string> attributes_to_remove;
|
||||
switch (pattern_mode) {
|
||||
case PatternMode::Exact: {
|
||||
if (read_only_component.attributes()->contains(pattern)) {
|
||||
attributes_to_remove.append(pattern);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PatternMode::Wildcard: {
|
||||
read_only_component.attributes()->foreach_attribute([&](const bke::AttributeIter &iter) {
|
||||
const StringRef attribute_name = iter.name;
|
||||
if (bke::attribute_name_is_anonymous(attribute_name)) {
|
||||
return;
|
||||
}
|
||||
if (attribute_name.startswith(wildcard_prefix) &&
|
||||
attribute_name.endswith(wildcard_suffix))
|
||||
{
|
||||
attributes_to_remove.append(attribute_name);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (attributes_to_remove.is_empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
GeometryComponent &component = geometry_set.get_component_for_write(type);
|
||||
for (const StringRef attribute_name : attributes_to_remove) {
|
||||
if (!bke::allow_procedural_attribute_access(attribute_name)) {
|
||||
continue;
|
||||
}
|
||||
if (component.attributes_for_write()->remove(attribute_name)) {
|
||||
std::lock_guard lock{attribute_log_mutex};
|
||||
removed_attributes.add(attribute_name);
|
||||
}
|
||||
else {
|
||||
std::lock_guard lock{attribute_log_mutex};
|
||||
failed_attributes.add(attribute_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const StringRef attribute_name : removed_attributes) {
|
||||
for (const StringRef attribute_name : removal_params.removed_attributes) {
|
||||
params.used_named_attribute(attribute_name, NamedAttributeUsage::Remove);
|
||||
}
|
||||
|
||||
if (!failed_attributes.is_empty()) {
|
||||
if (!removal_params.failed_attributes.is_empty()) {
|
||||
Vector<std::string> quoted_attribute_names;
|
||||
for (const StringRef attribute_name : failed_attributes) {
|
||||
for (const StringRef attribute_name : removal_params.failed_attributes) {
|
||||
quoted_attribute_names.append(fmt::format("\"{}\"", attribute_name));
|
||||
}
|
||||
const std::string message = fmt::format(
|
||||
@@ -142,7 +161,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
fmt::join(quoted_attribute_names, ", "));
|
||||
params.error_message_add(NodeWarningType::Warning, message);
|
||||
}
|
||||
else if (removed_attributes.is_empty() && pattern_mode == PatternMode::Exact) {
|
||||
else if (removal_params.removed_attributes.is_empty() && pattern_mode == PatternMode::Exact) {
|
||||
const std::string message = fmt::format(fmt::runtime(TIP_("Attribute does not exist: \"{}\"")),
|
||||
pattern);
|
||||
params.error_message_add(NodeWarningType::Warning, message);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "UI_interface_layout.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_selection.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
@@ -474,7 +475,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<float> scale_field = params.extract_input<Field<float>>("Scale");
|
||||
const Field<float3> center_field = params.extract_input<Field<float3>>("Center");
|
||||
|
||||
geometry.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry, [&](GeometrySet &geometry) {
|
||||
if (Mesh *mesh = geometry.get_mesh_for_write()) {
|
||||
const bke::MeshFieldContext context{*mesh, domain};
|
||||
FieldEvaluator evaluator{context, mesh->attributes().domain_size(domain)};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_separate_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -68,7 +69,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
is_error);
|
||||
}
|
||||
else {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
geometry::separate_geometry(geometry_set,
|
||||
domain,
|
||||
GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_curve_handles_cc {
|
||||
@@ -176,7 +178,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
std::atomic<bool> has_curves = false;
|
||||
std::atomic<bool> has_bezier = false;
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
has_curves = true;
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_curve_normal_cc {
|
||||
@@ -90,7 +92,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
custom_normal = params.extract_input<Field<float3>>("Normal");
|
||||
}
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
set_curve_normal(curves,
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_curve_radius_cc {
|
||||
@@ -44,7 +46,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<float> radius = params.extract_input<Field<float>>("Radius");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
const bke::CurvesFieldContext field_context(*curves_id, AttrDomain::Point);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_curve_tilt_cc {
|
||||
@@ -58,7 +60,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<float> tilt = params.extract_input<Field<float>>("Tilt");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
const bke::CurvesFieldContext field_context(*curves_id, AttrDomain::Point);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -62,7 +64,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const StringRef color_attr_name = domain == AttrDomain::Point ? "vertex_color" : "fill_color";
|
||||
const StringRef opacity_attr_name = domain == AttrDomain::Point ? "opacity" : "fill_opacity";
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
|
||||
using namespace bke::greasepencil;
|
||||
for (const int layer_index : grease_pencil->layers().index_range()) {
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_grease_pencil_set_depth_mode {
|
||||
@@ -40,7 +42,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Grease Pencil");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
|
||||
SET_FLAG_FROM_TEST(grease_pencil->flag,
|
||||
params.node().custom1 == GREASE_PENCIL_STROKE_ORDER_3D,
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_grease_pencil_softness_cc {
|
||||
@@ -28,7 +30,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<float> softness = params.extract_input<Field<float>>("Softness");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) {
|
||||
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
|
||||
using namespace bke::greasepencil;
|
||||
for (const int layer_index : grease_pencil->layers().index_range()) {
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_material.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_material_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
@@ -83,7 +85,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
bool volume_selection_warning = false;
|
||||
bool curves_selection_warning = false;
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
if (mesh->faces_num == 0) {
|
||||
if (mesh->verts_num > 0) {
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_material_index_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
@@ -50,7 +52,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<int> material_index = params.extract_input<Field<int>>("Material Index");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
bke::try_capture_field_on_geometry(mesh->attributes_for_write(),
|
||||
bke::MeshFieldContext(*mesh, AttrDomain::Face),
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -76,7 +78,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const bool remove_custom = params.extract_input<bool>("Remove Custom");
|
||||
const fn::Field sharp_edge = params.extract_input<fn::Field<bool>>("Edge Sharpness");
|
||||
const fn::Field sharp_face = params.extract_input<fn::Field<bool>>("Face Sharpness");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
/* Evaluate both fields before storing the result to avoid one attribute change
|
||||
* potentially affecting the other field evaluation. */
|
||||
@@ -129,7 +131,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
case Mode::Free: {
|
||||
const fn::Field custom_normal = params.extract_input<fn::Field<float3>>("Custom Normal");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
const bke::AttrDomain domain = bke::AttrDomain(node.custom2);
|
||||
bke::try_capture_field_on_geometry(mesh->attributes_for_write(),
|
||||
@@ -144,7 +146,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
case Mode::CornerFanSpace: {
|
||||
const fn::Field custom_normal = params.extract_input<fn::Field<float3>>("Custom Normal");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
const bke::MeshFieldContext context(*mesh, bke::AttrDomain::Corner);
|
||||
fn::FieldEvaluator evaluator(context, mesh->corners_num);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_point_radius_cc {
|
||||
@@ -30,7 +32,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<float> radius = params.extract_input<Field<float>>("Radius");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (PointCloud *pointcloud = geometry_set.get_pointcloud_for_write()) {
|
||||
bke::try_capture_field_on_geometry(pointcloud->attributes_for_write(),
|
||||
bke::PointCloudFieldContext(*pointcloud),
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_shade_smooth_cc {
|
||||
@@ -89,7 +91,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<bool> smooth_field = params.extract_input<Field<bool>>("Shade Smooth");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
set_sharp(*mesh,
|
||||
domain,
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_spline_cyclic_cc {
|
||||
@@ -58,7 +60,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<bool> cyclic = params.extract_input<Field<bool>>("Cyclic");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
const bke::CurvesFieldContext field_context{*curves_id, AttrDomain::Curve};
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_spline_resolution_cc {
|
||||
@@ -59,7 +61,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<int> resolution = params.extract_input<Field<int>>("Resolution");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
const bke::CurvesFieldContext field_context(*curves_id, AttrDomain::Curve);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "BLI_sort.hh"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_reorder.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
@@ -224,7 +225,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
}
|
||||
else {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
for (const auto [type, domains] : geometry::components_supported_reordering().items()) {
|
||||
const bke::GeometryComponent *src_component = geometry_set.get_component(type);
|
||||
if (src_component == nullptr || src_component->is_empty()) {
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "NOD_rna_define.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include <fmt/format.h>
|
||||
@@ -145,7 +147,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
}
|
||||
else {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::PointCloud,
|
||||
GeometryComponent::Type::Curve,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
#include "FN_multi_function_builder.hh"
|
||||
@@ -194,7 +195,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
return;
|
||||
}
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
if (const Mesh *mesh = geometry_set.get_mesh()) {
|
||||
geometry_set.replace_mesh(mesh_subsurf_calc(
|
||||
mesh, level, vert_crease, edge_crease, boundary_smooth, uv_smooth, use_limit_surface));
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_tool_set_face_set_cc {
|
||||
@@ -37,7 +39,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const bool is_zero = is_constant_zero(face_set);
|
||||
|
||||
GeometrySet geometry = params.extract_input<GeometrySet>("Mesh");
|
||||
geometry.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry, [&](GeometrySet &geometry) {
|
||||
if (Mesh *mesh = geometry.get_mesh_for_write()) {
|
||||
if (is_zero) {
|
||||
mesh->attributes_for_write().remove(".sculpt_face_set");
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "FN_multi_function_builder.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -95,7 +97,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const GField selection = params.extract_input<GField>("Selection");
|
||||
const AttrDomain domain = AttrDomain(params.node().custom1);
|
||||
const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
|
||||
geometry.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry, [&](GeometrySet &geometry) {
|
||||
if (Mesh *mesh = geometry.get_mesh_for_write()) {
|
||||
switch (mode) {
|
||||
case OB_MODE_EDIT: {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_mesh_triangulate.hh"
|
||||
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -85,7 +85,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const auto ngon_method = params.extract_input<geometry::TriangulateNGonMode>("N-gon Method");
|
||||
const auto quad_method = params.extract_input<geometry::TriangulateQuadMode>("Quad Method");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
const Mesh *src_mesh = geometry_set.get_mesh();
|
||||
if (!src_mesh) {
|
||||
return;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "BKE_volume_grid.hh"
|
||||
#include "BKE_volume_to_mesh.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_randomize.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_volume_to_mesh_cc {
|
||||
@@ -191,10 +192,10 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
|
||||
Mesh *mesh = create_mesh_from_volume(geometry_set, params);
|
||||
geometry_set.replace_mesh(mesh);
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh});
|
||||
geometry_set.keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit});
|
||||
});
|
||||
params.set_output("Mesh", std::move(geometry_set));
|
||||
#else
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "NOD_node_declaration.hh"
|
||||
#include "NOD_socket.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "BKE_geometry_fields.hh"
|
||||
#include "BKE_geometry_nodes_reference_set.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
@@ -738,20 +740,13 @@ static MultiValueMap<bke::AttrDomain, OutputAttributeInfo> find_output_attribute
|
||||
static Vector<OutputAttributeToStore> compute_attributes_to_store(
|
||||
const bke::GeometrySet &geometry,
|
||||
const MultiValueMap<bke::AttrDomain, OutputAttributeInfo> &outputs_by_domain,
|
||||
const bool do_instances)
|
||||
const Span<const bke::GeometryComponent::Type> component_types)
|
||||
{
|
||||
Vector<OutputAttributeToStore> attributes_to_store;
|
||||
for (const auto component_type : {bke::GeometryComponent::Type::Mesh,
|
||||
bke::GeometryComponent::Type::PointCloud,
|
||||
bke::GeometryComponent::Type::Curve,
|
||||
bke::GeometryComponent::Type::Instance})
|
||||
{
|
||||
for (const auto component_type : component_types) {
|
||||
if (!geometry.has(component_type)) {
|
||||
continue;
|
||||
}
|
||||
if (!do_instances && component_type == bke::GeometryComponent::Type::Instance) {
|
||||
continue;
|
||||
}
|
||||
const bke::GeometryComponent &component = *geometry.get_component(component_type);
|
||||
const bke::AttributeAccessor attributes = *component.attributes();
|
||||
for (const auto item : outputs_by_domain.items()) {
|
||||
@@ -838,24 +833,32 @@ static void store_output_attributes(bke::GeometrySet &geometry,
|
||||
if (outputs_by_domain.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
/* Handle top level instances separately first. */
|
||||
Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store(
|
||||
geometry, outputs_by_domain, {bke::GeometryComponent::Type::Instance});
|
||||
store_computed_output_attributes(geometry, attributes_to_store);
|
||||
}
|
||||
|
||||
const bool only_instance_attributes = outputs_by_domain.size() == 1 &&
|
||||
*outputs_by_domain.keys().begin() ==
|
||||
bke::AttrDomain::Instance;
|
||||
if (only_instance_attributes) {
|
||||
/* No need to call #modify_geometry_sets when only adding attributes to top-level instances.
|
||||
/* No need to call #foreach_real_geometry when only adding attributes to top-level instances.
|
||||
* This avoids some unnecessary data copies currently if some sub-geometries are not yet owned
|
||||
* by the geometry set, i.e. they use #GeometryOwnershipType::Editable/ReadOnly. */
|
||||
Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store(
|
||||
geometry, outputs_by_domain, true);
|
||||
store_computed_output_attributes(geometry, attributes_to_store);
|
||||
return;
|
||||
}
|
||||
|
||||
geometry.modify_geometry_sets([&](bke::GeometrySet &instance_geometry) {
|
||||
geometry::foreach_real_geometry(geometry, [&](bke::GeometrySet &instance_geometry) {
|
||||
/* Instance attributes should only be created for the top-level geometry. */
|
||||
const bool do_instances = &geometry == &instance_geometry;
|
||||
Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store(
|
||||
instance_geometry, outputs_by_domain, do_instances);
|
||||
instance_geometry,
|
||||
outputs_by_domain,
|
||||
{bke::GeometryComponent::Type::Mesh,
|
||||
bke::GeometryComponent::Type::PointCloud,
|
||||
bke::GeometryComponent::Type::Curve});
|
||||
store_computed_output_attributes(instance_geometry, attributes_to_store);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "BKE_node_socket_value.hh"
|
||||
|
||||
#include "GEO_extract_elements.hh"
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
#include "GEO_join_geometries.hh"
|
||||
|
||||
#include "FN_lazy_function_graph_executor.hh"
|
||||
@@ -1137,7 +1138,7 @@ void LazyFunctionForReduceForeachGeometryElement::handle_generation_items_group(
|
||||
}
|
||||
}
|
||||
else {
|
||||
geometry.modify_geometry_sets([&](GeometrySet &sub_geometry) {
|
||||
geometry::foreach_real_geometry(geometry, [&](GeometrySet &sub_geometry) {
|
||||
for (const GeometryComponent::Type component_type :
|
||||
{GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::PointCloud,
|
||||
|
||||
@@ -54,6 +54,8 @@
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "GEO_foreach_geometry.hh"
|
||||
|
||||
#include "list_function_eval.hh"
|
||||
#include "volume_grid_function_eval.hh"
|
||||
|
||||
@@ -909,7 +911,7 @@ class LazyFunctionForViewerNode : public LazyFunction {
|
||||
}
|
||||
}
|
||||
else {
|
||||
geometry.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
geometry::foreach_real_geometry(geometry, [&](GeometrySet &geometry) {
|
||||
for (const bke::GeometryComponent::Type type :
|
||||
{bke::GeometryComponent::Type::Mesh,
|
||||
bke::GeometryComponent::Type::PointCloud,
|
||||
|
||||
BIN
tests/files/modeling/geometry_nodes/instance/instance_on_points_in_instances.blend
(Stored with Git LFS)
Normal file
BIN
tests/files/modeling/geometry_nodes/instance/instance_on_points_in_instances.blend
(Stored with Git LFS)
Normal file
Binary file not shown.
Reference in New Issue
Block a user