Instances: Move transforms to attribute #118531

Merged
Hans Goudey merged 7 commits from HooglyBoogly/blender:instances-tranform-attribute into main 2024-02-22 17:57:21 +01:00
21 changed files with 214 additions and 210 deletions

View File

@ -27,6 +27,7 @@
#include "BLI_math_matrix_types.hh"
#include "BLI_shared_cache.hh"
#include "BLI_vector.hh"
#include "BLI_virtual_array_fwd.hh"
#include "DNA_customdata_types.h"
@ -99,8 +100,7 @@ class Instances {
*/
Vector<InstanceReference> references_;
/** Transformation of the instances. */
Vector<float4x4> transforms_;
int instances_num_ = 0;
CustomData attributes_;
@ -159,8 +159,8 @@ class Instances {
Span<int> reference_handles() const;
MutableSpan<int> reference_handles_for_write();
MutableSpan<float4x4> transforms();
Span<float4x4> transforms() const;
MutableSpan<float4x4> transforms_for_write();
int instances_num() const;
int references_num() const;
@ -193,6 +193,9 @@ class Instances {
}
};
VArray<float3> instance_position_varray(const Instances &instances);
VMutableArray<float3> instance_position_varray_for_write(Instances &instances);
/* -------------------------------------------------------------------- */
/** \name #InstanceReference Inline Methods
* \{ */

View File

@ -716,14 +716,6 @@ static std::unique_ptr<Instances> try_load_instances(const DictionaryValue &io_g
instances->add_reference(std::move(reference_geometry));
}
const auto *io_transforms = io_instances->lookup_dict("transforms");
if (!io_transforms) {
return {};
}
if (!read_blob_simple_gspan(blob_reader, *io_transforms, instances->transforms())) {
return {};
}
MutableAttributeAccessor attributes = instances->attributes_for_write();
if (!load_attributes(*io_attributes, attributes, blob_reader, blob_sharing)) {
return {};
@ -743,6 +735,18 @@ static std::unique_ptr<Instances> try_load_instances(const DictionaryValue &io_g
}
}
if (!attributes.contains("instance_transform")) {
/* Try reading the transform attribute from the old bake format from before it was an
* attribute. */
const auto *io_handles = io_instances->lookup_dict("transforms");
if (!io_handles) {
return {};
}
if (!read_blob_simple_gspan(blob_reader, *io_handles, instances->transforms_for_write())) {
return {};
}
}
return instances;
}
@ -973,11 +977,8 @@ static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet
serialize_geometry_set(reference.geometry_set(), blob_writer, blob_sharing));
}
io_instances->append(
"transforms", write_blob_simple_gspan(blob_writer, blob_sharing, instances.transforms()));
auto io_attributes = serialize_attributes(
instances.attributes(), blob_writer, blob_sharing, {"position"});
instances.attributes(), blob_writer, blob_sharing, {});
io_instances->append("attributes", io_attributes);
}
return io_geometry;

View File

@ -102,65 +102,6 @@ void InstancesComponent::replace(Instances *instances, GeometryOwnershipType own
ownership_ = ownership;
}
static float3 get_transform_position(const float4x4 &transform)
{
return transform.location();
}
static void set_transform_position(float4x4 &transform, const float3 position)
{
transform.location() = position;
}
class InstancePositionAttributeProvider final : public BuiltinAttributeProvider {
public:
InstancePositionAttributeProvider()
: BuiltinAttributeProvider(
"position", AttrDomain::Instance, CD_PROP_FLOAT3, NonCreatable, NonDeletable)
{
}
GAttributeReader try_get_for_read(const void *owner) const final
{
const Instances *instances = static_cast<const Instances *>(owner);
if (instances == nullptr) {
return {};
}
Span<float4x4> transforms = instances->transforms();
return {VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms),
domain_,
nullptr};
}
GAttributeWriter try_get_for_write(void *owner) const final
{
Instances *instances = static_cast<Instances *>(owner);
if (instances == nullptr) {
return {};
}
MutableSpan<float4x4> transforms = instances->transforms();
return {VMutableArray<float3>::ForDerivedSpan<float4x4,
get_transform_position,
set_transform_position>(transforms),
domain_};
}
bool try_delete(void * /*owner*/) const final
{
return false;
}
bool try_create(void * /*owner*/, const AttributeInit & /*initializer*/) const final
{
return false;
}
bool exists(const void * /*owner*/) const final
{
return true;
}
};
static void tag_component_reference_index_changed(void *owner)
{
Instances &instances = *static_cast<Instances *>(owner);
@ -169,7 +110,6 @@ static void tag_component_reference_index_changed(void *owner)
static ComponentAttributeProviders create_attribute_providers_for_instances()
{
static InstancePositionAttributeProvider position;
static CustomDataAccessInfo instance_custom_data_access = {
[](void *owner) -> CustomData * {
Instances *instances = static_cast<Instances *>(owner);
@ -199,6 +139,15 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
instance_custom_data_access,
nullptr);
static BuiltinCustomDataLayerProvider instance_transform("instance_transform",
AttrDomain::Instance,
CD_PROP_FLOAT4X4,
CD_PROP_FLOAT4X4,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::NonDeletable,
instance_custom_data_access,
nullptr);
/** Indices into `Instances::references_`. Determines what data is instanced. */
static BuiltinCustomDataLayerProvider reference_index(".reference_index",
AttrDomain::Instance,
@ -212,7 +161,8 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
static CustomDataAttributeProvider instance_custom_data(AttrDomain::Instance,
instance_custom_data_access);
return ComponentAttributeProviders({&position, &id, &reference_index}, {&instance_custom_data});
return ComponentAttributeProviders({&instance_transform, &id, &reference_index},
{&instance_custom_data});
}
static AttributeAccessorFunctions get_instances_accessor_functions()

View File

@ -396,9 +396,14 @@ GVArray AttributeFieldInput::get_varray_for_context(const GeometryFieldContext &
}
}
}
else if (context.domain() == bke::AttrDomain::Instance && name_ == "position") {
/* Special case for "position" which is no longer an attribute on instances. */
return bke::instance_position_varray(*context.instances());
}
else if (auto attributes = context.attributes()) {
return *attributes->lookup(name_, domain, data_type);
}
return {};
}

View File

@ -127,13 +127,21 @@ void Instances::ensure_geometry_instances()
* collection as instances. */
std::unique_ptr<Instances> instances = std::make_unique<Instances>();
Collection &collection = reference.collection();
Vector<Object *, 8> objects;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
const int handle = instances->add_reference(*object);
instances->add_instance(handle, object->object_to_world());
float4x4 &transform = instances->transforms().last();
transform.location() -= collection.instance_offset;
objects.append(object);
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
instances->resize(objects.size());
MutableSpan<int> handles = instances->reference_handles_for_write();
MutableSpan<float4x4> transforms = instances->transforms_for_write();
for (const int i : objects.index_range()) {
handles[i] = instances->add_reference(*objects[i]);
transforms[i] = objects[i]->object_to_world();
transforms[i].location() -= collection.instance_offset;
}
instances->ensure_geometry_instances();
new_references.append(GeometrySet::from_instances(instances.release()));
break;

View File

@ -50,7 +50,7 @@ Instances::Instances()
Instances::Instances(Instances &&other)
: references_(std::move(other.references_)),
transforms_(std::move(other.transforms_)),
instances_num_(other.instances_num_),
attributes_(other.attributes_),
almost_unique_ids_cache_(std::move(other.almost_unique_ids_cache_))
{
@ -59,15 +59,15 @@ Instances::Instances(Instances &&other)
Instances::Instances(const Instances &other)
: references_(other.references_),
transforms_(other.transforms_),
instances_num_(other.instances_num_),
almost_unique_ids_cache_(other.almost_unique_ids_cache_)
{
CustomData_copy(&other.attributes_, &attributes_, CD_MASK_ALL, other.instances_num());
CustomData_copy(&other.attributes_, &attributes_, CD_MASK_ALL, other.instances_num_);
}
Instances::~Instances()
{
CustomData_free(&attributes_, this->instances_num());
CustomData_free(&attributes_, instances_num_);
}
Instances &Instances::operator=(const Instances &other)
@ -92,46 +92,55 @@ Instances &Instances::operator=(Instances &&other)
void Instances::resize(int capacity)
{
const int old_size = this->instances_num();
transforms_.resize(capacity);
CustomData_realloc(&attributes_, old_size, capacity, CD_SET_DEFAULT);
CustomData_realloc(&attributes_, instances_num_, capacity, CD_SET_DEFAULT);
instances_num_ = capacity;
}
void Instances::add_instance(const int instance_handle, const float4x4 &transform)
{
BLI_assert(instance_handle >= 0);
BLI_assert(instance_handle < references_.size());
const int old_size = this->instances_num();
transforms_.append(transform);
CustomData_realloc(&attributes_, old_size, transforms_.size());
const int old_size = instances_num_;
instances_num_++;
CustomData_realloc(&attributes_, old_size, instances_num_);
this->reference_handles_for_write().last() = instance_handle;
this->transforms_for_write().last() = transform;
}
Span<int> Instances::reference_handles() const
{
return {static_cast<const int *>(
CustomData_get_layer_named(&attributes_, CD_PROP_INT32, ".reference_index")),
this->instances_num()};
instances_num_};
}
MutableSpan<int> Instances::reference_handles_for_write()
{
int *data = static_cast<int *>(CustomData_get_layer_named_for_write(
&attributes_, CD_PROP_INT32, ".reference_index", this->instances_num()));
&attributes_, CD_PROP_INT32, ".reference_index", instances_num_));
if (!data) {
data = static_cast<int *>(CustomData_add_layer_named(
&attributes_, CD_PROP_INT32, CD_SET_DEFAULT, this->instances_num(), ".reference_index"));
&attributes_, CD_PROP_INT32, CD_SET_DEFAULT, instances_num_, ".reference_index"));
}
return {data, this->instances_num()};
return {data, instances_num_};
}
MutableSpan<float4x4> Instances::transforms()
{
return transforms_;
}
Span<float4x4> Instances::transforms() const
{
return transforms_;
return {static_cast<const float4x4 *>(
CustomData_get_layer_named(&attributes_, CD_PROP_FLOAT4X4, "instance_transform")),
instances_num_};
}
MutableSpan<float4x4> Instances::transforms_for_write()
{
float4x4 *data = static_cast<float4x4 *>(CustomData_get_layer_named_for_write(
&attributes_, CD_PROP_FLOAT4X4, "instance_transform", instances_num_));
if (!data) {
data = static_cast<float4x4 *>(CustomData_add_layer_named(
&attributes_, CD_PROP_FLOAT4X4, CD_SET_DEFAULT, instances_num_, "instance_transform"));
}
return {data, instances_num_};
}
GeometrySet &Instances::geometry_set_from_reference(const int reference_index)
@ -178,17 +187,14 @@ void Instances::remove(const IndexMask &mask,
return;
}
const int new_size = mask.size();
Instances new_instances;
new_instances.references_ = std::move(references_);
new_instances.transforms_.resize(new_size);
array_utils::gather(transforms_.as_span(), mask, new_instances.transforms_.as_mutable_span());
new_instances.instances_num_ = mask.size();
gather_attributes(this->attributes(),
AttrDomain::Instance,
propagation_info,
{"position"},
{},
mask,
new_instances.attributes_for_write());
@ -199,7 +205,7 @@ void Instances::remove(const IndexMask &mask,
void Instances::remove_unused_references()
{
const int tot_instances = this->instances_num();
const int tot_instances = instances_num_;
const int tot_references_before = references_.size();
if (tot_instances == 0) {
@ -281,7 +287,7 @@ void Instances::remove_unused_references()
int Instances::instances_num() const
{
return transforms_.size();
return this->instances_num_;
}
int Instances::references_num() const
@ -372,11 +378,33 @@ Span<int> Instances::almost_unique_ids() const
}
}
else {
r_data.reinitialize(this->instances_num());
r_data.reinitialize(instances_num_);
array_utils::fill_index_range(r_data.as_mutable_span());
}
});
return almost_unique_ids_cache_.data();
}
static float3 get_transform_position(const float4x4 &transform)
{
return transform.location();
}
static void set_transform_position(float4x4 &transform, const float3 position)
{
transform.location() = position;
}
VArray<float3> instance_position_varray(const Instances &instances)
{
return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(instances.transforms());
}
VMutableArray<float3> instance_position_varray_for_write(Instances &instances)
{
MutableSpan<float4x4> transforms = instances.transforms_for_write();
return VMutableArray<float3>::
ForDerivedSpan<float4x4, get_transform_position, set_transform_position>(transforms);
}
} // namespace blender::bke

View File

@ -204,6 +204,13 @@ void GeometryDataSource::foreach_default_column_ids(
if (!bke::allow_procedural_attribute_access(attribute_id.name())) {
return true;
}
if (meta_data.domain == bke::AttrDomain::Instance &&
HooglyBoogly marked this conversation as resolved
Review

We should show the Position, just like we show Rotation and Scale (see a few lines below).

We should show the `Position`, just like we show `Rotation` and `Scale` (see a few lines below).
attribute_id.name() == "instance_transform")
{
/* Don't display the instance transform attribute, since matrix visualization in the
* spreadsheet isn't helpful. */
return true;
}
SpreadsheetColumnID column_id;
column_id.name = (char *)attribute_id.name().data();
const bool is_front = attribute_id.name() == ".viewer";
@ -212,6 +219,7 @@ void GeometryDataSource::foreach_default_column_ids(
});
if (component_->type() == bke::GeometryComponent::Type::Instance) {
fn({(char *)"Position"}, false);
fn({(char *)"Rotation"}, false);
fn({(char *)"Scale"}, false);
}
@ -257,6 +265,12 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}));
}
Span<float4x4> transforms = instances->transforms();
if (STREQ(column_id.name, "Position")) {
return std::make_unique<ColumnValues>(
column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
return transforms[index].location();
}));
}
if (STREQ(column_id.name, "Rotation")) {
return std::make_unique<ColumnValues>(
column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {

View File

@ -109,7 +109,6 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
dst_instances->resize(offsets.total_size());
MutableSpan<float4x4> all_transforms = dst_instances->transforms();
MutableSpan<int> all_handles = dst_instances->reference_handles_for_write();
for (const int i : src_components.index_range()) {
@ -126,12 +125,11 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
const Span<int> src_handles = src_instances.reference_handles();
array_utils::gather(handle_map.as_span(), src_handles, all_handles.slice(dst_range));
array_utils::copy(src_instances.transforms(), all_transforms.slice(dst_range));
}
result.replace_instances(dst_instances.release());
auto &dst_component = result.get_component_for_write<bke::InstancesComponent>();
join_attributes(src_components, dst_component, {"position", ".reference_index"});
join_attributes(src_components, dst_component, {".reference_index"});
}
static void join_volumes(const Span<const GeometryComponent *> /*src_components*/,
@ -174,11 +172,13 @@ static void join_component_type(const bke::GeometryComponent::Type component_typ
}
std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
for (const GeometryComponent *component : components) {
instances->resize(components.size());
instances->transforms_for_write().fill(float4x4::identity());
MutableSpan<int> handles = instances->reference_handles_for_write();
for (const int i : components.index_range()) {
GeometrySet tmp_geo;
tmp_geo.add(*component);
const int handle = instances->add_reference(bke::InstanceReference{tmp_geo});
instances->add_instance(handle, float4x4::identity());
tmp_geo.add(*components[i]);
handles[i] = instances->add_reference(bke::InstanceReference{tmp_geo});
}
RealizeInstancesOptions options;

View File

@ -69,29 +69,6 @@ static void mix(GMutableSpan a, const GVArray &b, const float factor)
});
}
static void mix(MutableSpan<float4x4> a, const Span<float4x4> b, const float factor)
{
threading::parallel_for(a.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
a[i] = math::interpolate(a[i], b[i], factor);
}
});
}
static void mix_with_indices(MutableSpan<float4x4> a,
const Span<float4x4> b,
const Span<int> index_map,
const float factor)
{
threading::parallel_for(a.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
if (index_map[i] != -1) {
a[i] = math::interpolate(a[i], b[index_map[i]], factor);
}
}
});
}
static void mix_attributes(bke::MutableAttributeAccessor attributes_a,
const bke::AttributeAccessor b_attributes,
const Span<int> index_map,
@ -216,13 +193,7 @@ bke::GeometrySet mix_geometries(bke::GeometrySet a, const bke::GeometrySet &b, c
index_map,
bke::AttrDomain::Instance,
factor,
{"position"});
if (index_map.is_empty()) {
mix(instances_a->transforms(), instances_b->transforms(), factor);
}
else {
mix_with_indices(instances_a->transforms(), instances_b->transforms(), index_map, factor);
}
{});
}
}
return a;

View File

@ -233,27 +233,10 @@ void debug_randomize_instance_order(bke::Instances *instances)
if (instances == nullptr || !use_debug_randomization()) {
return;
}
const int instances_num = instances->instances_num();
const int seed = seed_from_instances(*instances);
const Array<int> new_by_old_map = get_permutation(instances_num, seed);
reorder_customdata(instances->custom_data_attributes(), new_by_old_map);
const Span<int> old_reference_handles = instances->reference_handles();
const Span<float4x4> old_transforms = instances->transforms();
Vector<int> new_reference_handles(instances_num);
Vector<float4x4> new_transforms(instances_num);
for (const int old_i : new_by_old_map.index_range()) {
const int new_i = new_by_old_map[old_i];
new_reference_handles[new_i] = old_reference_handles[old_i];
new_transforms[new_i] = old_transforms[old_i];
}
instances->reference_handles_for_write().copy_from(new_reference_handles);
instances->transforms().copy_from(new_transforms);
}
bool use_debug_randomization()

View File

@ -209,10 +209,6 @@ static void reorder_instaces_exec(const bke::Instances &src_instances,
{},
old_by_new_map,
dst_instances.attributes_for_write());
const Span<float4x4> old_transforms = src_instances.transforms();
MutableSpan<float4x4> new_transforms = dst_instances.transforms();
array_utils::gather(old_transforms, old_by_new_map, new_transforms);
}
static void clean_unused_attributes(const bke::AnonymousAttributePropagationInfo &propagation_info,

View File

@ -111,7 +111,7 @@ static void transform_greasepencil(GreasePencil &grease_pencil, const float4x4 &
static void translate_instances(bke::Instances &instances, const float3 translation)
{
MutableSpan<float4x4> transforms = instances.transforms();
MutableSpan<float4x4> transforms = instances.transforms_for_write();
threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
for (float4x4 &instance_transform : transforms.slice(range)) {
add_v3_v3(instance_transform.ptr()[3], translation);
@ -121,7 +121,7 @@ static void translate_instances(bke::Instances &instances, const float3 translat
static void transform_instances(bke::Instances &instances, const float4x4 &transform)
{
MutableSpan<float4x4> transforms = instances.transforms();
MutableSpan<float4x4> transforms = instances.transforms_for_write();
threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
for (float4x4 &instance_transform : transforms.slice(range)) {
instance_transform = transform * instance_transform;

View File

@ -954,8 +954,6 @@ static void duplicate_instances(GeometrySet &geometry_set,
const int old_handle = src_instances.reference_handles()[i_selection];
const bke::InstanceReference reference = src_instances.references()[old_handle];
const int new_handle = dst_instances->add_reference(reference);
const float4x4 transform = src_instances.transforms()[i_selection];
dst_instances->transforms().slice(range).fill(transform);
dst_instances->reference_handles_for_write().slice(range).fill(new_handle);
}

View File

@ -81,7 +81,8 @@ static void add_instances_from_component(
MutableSpan<int> dst_handles = dst_component.reference_handles_for_write().slice(start_len,
select_len);
MutableSpan<float4x4> dst_transforms = dst_component.transforms().slice(start_len, select_len);
MutableSpan<float4x4> dst_transforms = dst_component.transforms_for_write().slice(start_len,
select_len);
const VArraySpan positions = *src_attributes.lookup<float3>("position");

View File

@ -39,7 +39,7 @@ static void rotate_instances(GeoNodeExecParams &params, bke::Instances &instance
const VArray<float3> pivots = evaluator.get_evaluated<float3>(1);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2);
MutableSpan<float4x4> transforms = instances.transforms();
MutableSpan<float4x4> transforms = instances.transforms_for_write();
selection.foreach_index(GrainSize(512), [&](const int64_t i) {
const float3 pivot = pivots[i];

View File

@ -38,7 +38,7 @@ static void scale_instances(GeoNodeExecParams &params, bke::Instances &instances
const VArray<float3> pivots = evaluator.get_evaluated<float3>(1);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2);
MutableSpan<float4x4> transforms = instances.transforms();
MutableSpan<float4x4> transforms = instances.transforms_for_write();
selection.foreach_index(GrainSize(512), [&](const int64_t i) {
const float3 pivot = pivots[i];

View File

@ -6,6 +6,7 @@
#include "BKE_curves.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_instances.hh"
#include "node_geometry_util.hh"
@ -20,20 +21,25 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Geometry").propagate_all();
}
static void set_computed_position_and_offset(GeometryComponent &component,
const VArray<float3> &in_positions,
const VArray<float3> &in_offsets,
const IndexMask &selection,
MutableAttributeAccessor attributes)
{
/* Optimize the case when `in_positions` references the original positions array. */
const bke::AttributeReader positions_read_only = attributes.lookup<float3>("position");
bool positions_are_original = false;
if (positions_read_only.varray.is_span() && in_positions.is_span()) {
positions_are_original = positions_read_only.varray.get_internal_span().data() ==
in_positions.get_internal_span().data();
}
constexpr GrainSize grain_size{10000};
static bool check_positions_are_original(const AttributeAccessor &attributes,
const VArray<float3> &in_positions)
{
const bke::AttributeReader positions_read_only = attributes.lookup<float3>("position");
if (positions_read_only.varray.is_span() && in_positions.is_span()) {
return positions_read_only.varray.get_internal_span().data() ==
in_positions.get_internal_span().data();
}
return false;
}
static void write_offset_positions(const bool positions_are_original,
const IndexMask &selection,
const VArray<float3> &in_positions,
const VArray<float3> &in_offsets,
VMutableArray<float3> &out_positions)
{
if (positions_are_original) {
if (const std::optional<float3> offset = in_offsets.get_if_single()) {
if (math::is_zero(*offset)) {
@ -41,8 +47,32 @@ static void set_computed_position_and_offset(GeometryComponent &component,
}
}
}
const GrainSize grain_size{10000};
MutableVArraySpan<float3> out_positions_span = out_positions;
if (positions_are_original) {
devirtualize_varray(in_offsets, [&](const auto in_offsets) {
selection.foreach_index_optimized<int>(
grain_size, [&](const int i) { out_positions_span[i] += in_offsets[i]; });
});
}
else {
devirtualize_varray2(
in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
selection.foreach_index_optimized<int>(grain_size, [&](const int i) {
out_positions_span[i] = in_positions[i] + in_offsets[i];
});
});
}
out_positions_span.save();
}
static void set_computed_position_and_offset(GeometryComponent &component,
const VArray<float3> &in_positions,
const VArray<float3> &in_offsets,
const IndexMask &selection,
MutableAttributeAccessor attributes)
{
/* Optimize the case when `in_positions` references the original positions array. */
switch (component.type()) {
case GeometryComponent::Type::Curve: {
if (attributes.contains("handle_right") && attributes.contains("handle_left")) {
@ -76,26 +106,30 @@ static void set_computed_position_and_offset(GeometryComponent &component,
curves.calculate_bezier_auto_handles();
break;
}
ATTR_FALLTHROUGH;
AttributeWriter<float3> positions = attributes.lookup_for_write<float3>("position");
write_offset_positions(check_positions_are_original(attributes, in_positions),
selection,
in_positions,
in_offsets,
positions.varray);
positions.finish();
break;
}
case GeometryComponent::Type::Instance: {
/* Special case for "position" which is no longer an attribute on instances. */
auto &instances_component = reinterpret_cast<bke::InstancesComponent &>(component);
bke::Instances &instances = *instances_component.get_for_write();
VMutableArray<float3> positions = bke::instance_position_varray_for_write(instances);
write_offset_positions(false, selection, in_positions, in_offsets, positions);
break;
}
default: {
AttributeWriter<float3> positions = attributes.lookup_for_write<float3>("position");
MutableVArraySpan<float3> out_positions_span = positions.varray;
if (positions_are_original) {
devirtualize_varray(in_offsets, [&](const auto in_offsets) {
selection.foreach_index_optimized<int>(
grain_size, [&](const int i) { out_positions_span[i] += in_offsets[i]; });
});
}
else {
devirtualize_varray2(
in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
selection.foreach_index_optimized<int>(grain_size, [&](const int i) {
out_positions_span[i] = in_positions[i] + in_offsets[i];
});
});
}
out_positions_span.save();
write_offset_positions(check_positions_are_original(attributes, in_positions),
selection,
in_positions,
in_offsets,
positions.varray);
positions.finish();
break;
}

View File

@ -246,7 +246,6 @@ static void split_instance_groups(const InstancesComponent &component,
group_instances->add_reference(reference);
}
array_utils::gather(src_instances.transforms(), mask, group_instances->transforms());
bke::gather_attributes(src_instances.attributes(),
AttrDomain::Instance,
propagation_info,
@ -323,7 +322,7 @@ static void node_geo_exec(GeoNodeExecParams params)
dst_group_id.finish();
}
dst_instances->transforms().fill(float4x4::identity());
dst_instances->transforms_for_write().fill(float4x4::identity());
array_utils::fill_index_range(dst_instances->reference_handles_for_write());
for (auto item : geometry_by_group_id.items()) {

View File

@ -10,6 +10,7 @@
#include "RNA_access.hh"
#include "RNA_enum_types.hh"
#include "BKE_instances.hh"
#include "BKE_mesh.hh"
#include "BKE_type_conversions.hh"
@ -119,9 +120,21 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_instances()) {
GeometryComponent &component = geometry_set.get_component_for_write(
GeometryComponent::Type::Instance);
if (!bke::try_capture_field_on_geometry(component, name, domain, selection, field)) {
if (component.attribute_domain_size(domain) != 0) {
failure.store(true);
if (name == "position" && data_type == CD_PROP_FLOAT3) {
/* Special case for "position" which is no longer an attribute on instances. */
bke::Instances &instances = *geometry_set.get_instances_for_write();
bke::InstancesFieldContext context(instances);
fn::FieldEvaluator evaluator{context, instances.instances_num()};
evaluator.set_selection(selection);
evaluator.add_with_destination(field, bke::instance_position_varray_for_write(instances));
evaluator.evaluate();
}
else {
if (!bke::try_capture_field_on_geometry(component, name, domain, selection, field)) {
if (component.attribute_domain_size(domain) != 0) {
failure.store(true);
}
}
}
}

View File

@ -318,7 +318,7 @@ static void add_instances_from_handles(bke::Instances &instances,
{
instances.resize(layout.positions.size());
MutableSpan<int> handles = instances.reference_handles_for_write();
MutableSpan<float4x4> transforms = instances.transforms();
MutableSpan<float4x4> transforms = instances.transforms_for_write();
threading::parallel_for(IndexRange(layout.positions.size()), 256, [&](IndexRange range) {
for (const int i : range) {

View File

@ -34,7 +34,7 @@ static void translate_instances(GeoNodeExecParams &params, bke::Instances &insta
const VArray<float3> translations = evaluator.get_evaluated<float3>(0);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(1);
MutableSpan<float4x4> transforms = instances.transforms();
MutableSpan<float4x4> transforms = instances.transforms_for_write();
selection.foreach_index(GrainSize(1024), [&](const int64_t i) {
if (local_spaces[i]) {