Instances: Move transforms to attribute #118531
|
@ -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
|
||||
* \{ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ static void rotate_instances(GeoNodeExecParams ¶ms, 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];
|
||||
|
|
|
@ -38,7 +38,7 @@ static void scale_instances(GeoNodeExecParams ¶ms, 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];
|
||||
|
|
|
@ -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)
|
||||
constexpr GrainSize grain_size{10000};
|
||||
|
||||
static bool check_positions_are_original(const AttributeAccessor &attributes,
|
||||
const VArray<float3> &in_positions)
|
||||
{
|
||||
/* 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() ==
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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,6 +120,17 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
if (geometry_set.has_instances()) {
|
||||
GeometryComponent &component = geometry_set.get_component_for_write(
|
||||
GeometryComponent::Type::Instance);
|
||||
|
||||
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);
|
||||
|
@ -126,6 +138,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -34,7 +34,7 @@ static void translate_instances(GeoNodeExecParams ¶ms, 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]) {
|
||||
|
|
Loading…
Reference in New Issue
We should show the
Position
, just like we showRotation
andScale
(see a few lines below).