forked from blender/blender
davidhaver-WIP-realize-depth #3
@ -12,4 +12,7 @@ namespace blender::geometry {
|
|||||||
bke::GeometrySet join_geometries(Span<bke::GeometrySet> geometries,
|
bke::GeometrySet join_geometries(Span<bke::GeometrySet> geometries,
|
||||||
const bke::AnonymousAttributePropagationInfo &propagation_info);
|
const bke::AnonymousAttributePropagationInfo &propagation_info);
|
||||||
|
|
||||||
}
|
void join_attributes(Span<const bke::GeometryComponent *> src_components,
|
||||||
|
bke::GeometryComponent &r_result,
|
||||||
|
Span<StringRef> ignored_attributes = {});
|
||||||
|
} // namespace blender::geometry
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
namespace blender::geometry {
|
namespace blender::geometry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General options for realize_instances.
|
||||||
|
*/
|
||||||
struct RealizeInstancesOptions {
|
struct RealizeInstancesOptions {
|
||||||
/**
|
/**
|
||||||
* The default is to generate new ids for every element (when there was any id attribute in the
|
* The default is to generate new ids for every element (when there was any id attribute in the
|
||||||
@ -25,6 +28,26 @@ struct RealizeInstancesOptions {
|
|||||||
bke::AnonymousAttributePropagationInfo propagation_info;
|
bke::AnonymousAttributePropagationInfo propagation_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow the user to choice which instances to realize and to what depth.
|
||||||
|
*/
|
||||||
|
struct VariedDepthOption {
|
||||||
|
/**
|
||||||
|
* Selection of top-level instances to realize.
|
||||||
|
*/
|
||||||
|
IndexMask selection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Depth of realize instances for each selected top-level instance.
|
||||||
|
*/
|
||||||
|
VArray<int> depths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this value to realize the instance completely
|
||||||
|
*/
|
||||||
|
static const int MAX_DEPTH = -1;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join all instances into a single geometry component for each geometry type. For example, all
|
* Join all instances into a single geometry component for each geometry type. For example, all
|
||||||
* mesh instances (including the already realized mesh) are joined into a single mesh. The output
|
* mesh instances (including the already realized mesh) are joined into a single mesh. The output
|
||||||
@ -38,4 +61,20 @@ struct RealizeInstancesOptions {
|
|||||||
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set,
|
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set,
|
||||||
const RealizeInstancesOptions &options);
|
const RealizeInstancesOptions &options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join all instances into a single geometry component for each geometry type. For example, all
|
||||||
|
* mesh instances (including the already realized mesh) are joined into a single mesh. The output
|
||||||
|
* geometry set does not contain any instances. If the input did not contain any instances, it is
|
||||||
|
* returned directly.
|
||||||
|
*
|
||||||
|
* The `id` attribute has special handling. If there is an id attribute on any component, the
|
||||||
|
* output will contain an `id` attribute as well. The output id is generated by mixing/hashing ids
|
||||||
|
* of instances and of the instanced geometry data.
|
||||||
|
*
|
||||||
|
* Will realize only the instances chosen by varied_depth_option to there chosen depth.
|
||||||
|
*/
|
||||||
|
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set,
|
||||||
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option);
|
||||||
|
|
||||||
} // namespace blender::geometry
|
} // namespace blender::geometry
|
||||||
|
@ -73,9 +73,9 @@ static void fill_new_attribute(const Span<const GeometryComponent *> src_compone
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void join_attributes(const Span<const GeometryComponent *> src_components,
|
void join_attributes(const Span<const GeometryComponent *> src_components,
|
||||||
GeometryComponent &result,
|
GeometryComponent &r_result,
|
||||||
const Span<StringRef> ignored_attributes = {})
|
const Span<StringRef> ignored_attributes)
|
||||||
{
|
{
|
||||||
const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(src_components,
|
const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(src_components,
|
||||||
ignored_attributes);
|
ignored_attributes);
|
||||||
@ -85,7 +85,7 @@ static void join_attributes(const Span<const GeometryComponent *> src_components
|
|||||||
const AttributeMetaData &meta_data = item.value;
|
const AttributeMetaData &meta_data = item.value;
|
||||||
|
|
||||||
bke::GSpanAttributeWriter write_attribute =
|
bke::GSpanAttributeWriter write_attribute =
|
||||||
result.attributes_for_write()->lookup_or_add_for_write_only_span(
|
r_result.attributes_for_write()->lookup_or_add_for_write_only_span(
|
||||||
attribute_id, meta_data.domain, meta_data.data_type);
|
attribute_id, meta_data.domain, meta_data.data_type);
|
||||||
if (!write_attribute) {
|
if (!write_attribute) {
|
||||||
continue;
|
continue;
|
||||||
@ -97,7 +97,7 @@ static void join_attributes(const Span<const GeometryComponent *> src_components
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void join_instances(const Span<const GeometryComponent *> src_components,
|
static void join_instances(const Span<const GeometryComponent *> src_components,
|
||||||
GeometrySet &result)
|
GeometrySet &r_result)
|
||||||
{
|
{
|
||||||
Array<int> offsets_data(src_components.size() + 1);
|
Array<int> offsets_data(src_components.size() + 1);
|
||||||
for (const int i : src_components.index_range()) {
|
for (const int i : src_components.index_range()) {
|
||||||
@ -127,8 +127,8 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
|
|||||||
array_utils::gather(handle_map.as_span(), src_handles, all_handles.slice(dst_range));
|
array_utils::gather(handle_map.as_span(), src_handles, all_handles.slice(dst_range));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.replace_instances(dst_instances.release());
|
r_result.replace_instances(dst_instances.release());
|
||||||
auto &dst_component = result.get_component_for_write<bke::InstancesComponent>();
|
auto &dst_component = r_result.get_component_for_write<bke::InstancesComponent>();
|
||||||
join_attributes(src_components, dst_component, {".reference_index"});
|
join_attributes(src_components, dst_component, {".reference_index"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ static void join_volumes(const Span<const GeometryComponent *> /*src_components*
|
|||||||
static void join_component_type(const bke::GeometryComponent::Type component_type,
|
static void join_component_type(const bke::GeometryComponent::Type component_type,
|
||||||
const Span<GeometrySet> src_geometry_sets,
|
const Span<GeometrySet> src_geometry_sets,
|
||||||
const bke::AnonymousAttributePropagationInfo &propagation_info,
|
const bke::AnonymousAttributePropagationInfo &propagation_info,
|
||||||
GeometrySet &result)
|
GeometrySet &r_result)
|
||||||
{
|
{
|
||||||
Vector<const GeometryComponent *> components;
|
Vector<const GeometryComponent *> components;
|
||||||
for (const GeometrySet &geometry_set : src_geometry_sets) {
|
for (const GeometrySet &geometry_set : src_geometry_sets) {
|
||||||
@ -156,16 +156,16 @@ static void join_component_type(const bke::GeometryComponent::Type component_typ
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (components.size() == 1) {
|
if (components.size() == 1) {
|
||||||
result.add(*components.first());
|
r_result.add(*components.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (component_type) {
|
switch (component_type) {
|
||||||
case bke::GeometryComponent::Type::Instance:
|
case bke::GeometryComponent::Type::Instance:
|
||||||
join_instances(components, result);
|
join_instances(components, r_result);
|
||||||
return;
|
return;
|
||||||
case bke::GeometryComponent::Type::Volume:
|
case bke::GeometryComponent::Type::Volume:
|
||||||
join_volumes(components, result);
|
join_volumes(components, r_result);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -185,9 +185,10 @@ static void join_component_type(const bke::GeometryComponent::Type component_typ
|
|||||||
options.keep_original_ids = true;
|
options.keep_original_ids = true;
|
||||||
options.realize_instance_attributes = false;
|
options.realize_instance_attributes = false;
|
||||||
options.propagation_info = propagation_info;
|
options.propagation_info = propagation_info;
|
||||||
|
|
||||||
GeometrySet joined_components = realize_instances(
|
GeometrySet joined_components = realize_instances(
|
||||||
GeometrySet::from_instances(instances.release()), options);
|
GeometrySet::from_instances(instances.release()), options);
|
||||||
result.add(joined_components.get_component_for_write(component_type));
|
r_result.add(joined_components.get_component_for_write(component_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometrySet join_geometries(const Span<GeometrySet> geometries,
|
GeometrySet join_geometries(const Span<GeometrySet> geometries,
|
||||||
|
@ -2,20 +2,14 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include "GEO_join_geometries.hh"
|
||||||
#include "GEO_realize_instances.hh"
|
#include "GEO_realize_instances.hh"
|
||||||
|
|
||||||
#include "DNA_collection_types.h"
|
#include "DNA_collection_types.h"
|
||||||
#include "DNA_layer_types.h"
|
|
||||||
#include "DNA_object_types.h"
|
|
||||||
#include "DNA_pointcloud_types.h"
|
|
||||||
|
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_array_utils.hh"
|
||||||
#include "BLI_math_matrix.hh"
|
|
||||||
#include "BLI_math_rotation.hh"
|
|
||||||
#include "BLI_noise.hh"
|
#include "BLI_noise.hh"
|
||||||
#include "BLI_task.hh"
|
|
||||||
|
|
||||||
#include "BKE_collection.hh"
|
|
||||||
#include "BKE_curves.hh"
|
#include "BKE_curves.hh"
|
||||||
#include "BKE_customdata.hh"
|
#include "BKE_customdata.hh"
|
||||||
#include "BKE_geometry_set_instances.hh"
|
#include "BKE_geometry_set_instances.hh"
|
||||||
@ -225,6 +219,15 @@ struct AllCurvesInfo {
|
|||||||
bool create_custom_normal_attribute = false;
|
bool create_custom_normal_attribute = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AllInstancesInfo {
|
||||||
|
/** store an array of void pointer to attributes for each component. */
|
||||||
|
Vector<AttributeFallbacksArray> attribute_fallback;
|
||||||
|
/** Instance components to merge for output geometry. */
|
||||||
|
Vector<bke::GeometryComponentPtr> instances_components_to_merge;
|
||||||
|
/** Base transform for each instance component. */
|
||||||
|
Vector<float4x4> instances_components_transforms;
|
||||||
|
};
|
||||||
|
|
||||||
/** Collects all tasks that need to be executed to realize all instances. */
|
/** Collects all tasks that need to be executed to realize all instances. */
|
||||||
struct GatherTasks {
|
struct GatherTasks {
|
||||||
Vector<RealizePointCloudTask> pointcloud_tasks;
|
Vector<RealizePointCloudTask> pointcloud_tasks;
|
||||||
@ -249,8 +252,15 @@ struct GatherTasksInfo {
|
|||||||
const AllPointCloudsInfo &pointclouds;
|
const AllPointCloudsInfo &pointclouds;
|
||||||
const AllMeshesInfo &meshes;
|
const AllMeshesInfo &meshes;
|
||||||
const AllCurvesInfo &curves;
|
const AllCurvesInfo &curves;
|
||||||
|
const OrderedAttributes &instances_attriubutes;
|
||||||
bool create_id_attribute_on_any_component = false;
|
bool create_id_attribute_on_any_component = false;
|
||||||
|
|
||||||
|
/** Selection for top-level instances to realize. */
|
||||||
|
IndexMask selection;
|
||||||
|
|
||||||
|
/** Depth to realize instances for each selected top-level instance. */
|
||||||
|
const VArray<int> &depths;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Under some circumstances, temporary arrays need to be allocated during the gather operation.
|
* Under some circumstances, temporary arrays need to be allocated during the gather operation.
|
||||||
* For example, when an instance attribute has to be realized as a different data type. This
|
* For example, when an instance attribute has to be realized as a different data type. This
|
||||||
@ -259,6 +269,8 @@ struct GatherTasksInfo {
|
|||||||
*/
|
*/
|
||||||
Vector<std::unique_ptr<GArray<>>> &r_temporary_arrays;
|
Vector<std::unique_ptr<GArray<>>> &r_temporary_arrays;
|
||||||
|
|
||||||
|
AllInstancesInfo instances;
|
||||||
|
|
||||||
/** All gathered tasks. */
|
/** All gathered tasks. */
|
||||||
GatherTasks r_tasks;
|
GatherTasks r_tasks;
|
||||||
/** Current offsets while gathering tasks. */
|
/** Current offsets while gathering tasks. */
|
||||||
@ -275,17 +287,40 @@ struct InstanceContext {
|
|||||||
AttributeFallbacksArray meshes;
|
AttributeFallbacksArray meshes;
|
||||||
/** Ordered by #AllCurvesInfo.attributes. */
|
/** Ordered by #AllCurvesInfo.attributes. */
|
||||||
AttributeFallbacksArray curves;
|
AttributeFallbacksArray curves;
|
||||||
|
/** Ordered by #AllInstancesInfo.attributes. */
|
||||||
|
AttributeFallbacksArray instances;
|
||||||
/** Id mixed from all parent instances. */
|
/** Id mixed from all parent instances. */
|
||||||
uint32_t id = 0;
|
uint32_t id = 0;
|
||||||
|
|
||||||
InstanceContext(const GatherTasksInfo &gather_info)
|
InstanceContext(const GatherTasksInfo &gather_info)
|
||||||
: pointclouds(gather_info.pointclouds.attributes.size()),
|
: pointclouds(gather_info.pointclouds.attributes.size()),
|
||||||
meshes(gather_info.meshes.attributes.size()),
|
meshes(gather_info.meshes.attributes.size()),
|
||||||
curves(gather_info.curves.attributes.size())
|
curves(gather_info.curves.attributes.size()),
|
||||||
|
instances(gather_info.instances_attriubutes.size())
|
||||||
{
|
{
|
||||||
|
//empty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void realize_collections(Collection *collection, bke::Instances *instances)
|
||||||
|
{
|
||||||
|
LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
|
||||||
|
float4x4 transform = float4x4::identity();
|
||||||
|
transform.location() += float3((collection_child->collection)->instance_offset);
|
||||||
|
transform.location() -= float3(collection->instance_offset);
|
||||||
|
const int handle = instances->add_reference(*(collection_child->collection));
|
||||||
|
instances->add_instance(handle, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
|
||||||
|
float4x4 transform = float4x4::identity();
|
||||||
|
transform.location() -= float3(collection->instance_offset);
|
||||||
|
transform *= (collection_object->ob)->object_to_world();
|
||||||
|
const int handle = instances->add_reference(*(collection_object->ob));
|
||||||
|
instances->add_instance(handle, transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int64_t get_final_points_num(const GatherTasks &tasks)
|
static int64_t get_final_points_num(const GatherTasks &tasks)
|
||||||
{
|
{
|
||||||
int64_t points_num = 0;
|
int64_t points_num = 0;
|
||||||
@ -377,12 +412,12 @@ static void copy_generic_attributes_to_result(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_result_ids(const RealizeInstancesOptions &options,
|
static void create_result_ids(bool keep_original_ids,
|
||||||
Span<int> stored_ids,
|
Span<int> stored_ids,
|
||||||
const int task_id,
|
const int task_id,
|
||||||
MutableSpan<int> dst_ids)
|
MutableSpan<int> dst_ids)
|
||||||
{
|
{
|
||||||
if (options.keep_original_ids) {
|
if (keep_original_ids) {
|
||||||
if (stored_ids.is_empty()) {
|
if (stored_ids.is_empty()) {
|
||||||
dst_ids.fill(0);
|
dst_ids.fill(0);
|
||||||
}
|
}
|
||||||
@ -414,6 +449,8 @@ static void create_result_ids(const RealizeInstancesOptions &options,
|
|||||||
|
|
||||||
/* Forward declaration. */
|
/* Forward declaration. */
|
||||||
static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
||||||
|
const int current_depth,
|
||||||
|
const int target_depth,
|
||||||
const bke::GeometrySet &geometry_set,
|
const bke::GeometrySet &geometry_set,
|
||||||
const float4x4 &base_transform,
|
const float4x4 &base_transform,
|
||||||
const InstanceContext &base_instance_context);
|
const InstanceContext &base_instance_context);
|
||||||
@ -463,6 +500,38 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
|
|||||||
return attributes_to_override;
|
return attributes_to_override;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bke::GeometrySet &geometry_set_from_reference(const InstanceReference &reference,
|
||||||
|
bke::GeometrySet &r_geometry_set)
|
||||||
|
{
|
||||||
|
switch (reference.type()) {
|
||||||
|
case InstanceReference::Type::Object: {
|
||||||
|
const Object &object = reference.object();
|
||||||
|
r_geometry_set = bke::object_get_evaluated_geometry_set(object);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InstanceReference::Type::Collection: {
|
||||||
|
Collection *collection_ptr = &reference.collection();
|
||||||
|
std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
|
||||||
|
realize_collections(collection_ptr, instances.get());
|
||||||
|
r_geometry_set.replace_instances(instances.release());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InstanceReference::Type::GeometrySet: {
|
||||||
|
r_geometry_set = reference.geometry_set();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InstanceReference::Type::None: {
|
||||||
|
r_geometry_set = bke::GeometrySet(); // Return an empty GeometrySet for None type
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
r_geometry_set = bke::GeometrySet();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r_geometry_set;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls #fn for every geometry in the given #InstanceReference. Also passes on the transformation
|
* Calls #fn for every geometry in the given #InstanceReference. Also passes on the transformation
|
||||||
* that is applied to every instance.
|
* that is applied to every instance.
|
||||||
@ -474,40 +543,14 @@ static void foreach_geometry_in_reference(
|
|||||||
FunctionRef<void(const bke::GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)>
|
FunctionRef<void(const bke::GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)>
|
||||||
fn)
|
fn)
|
||||||
{
|
{
|
||||||
switch (reference.type()) {
|
bke::GeometrySet geometry_set;
|
||||||
case InstanceReference::Type::Object: {
|
geometry_set_from_reference(reference, geometry_set);
|
||||||
const Object &object = reference.object();
|
fn(geometry_set, base_transform, id);
|
||||||
const bke::GeometrySet object_geometry = bke::object_get_evaluated_geometry_set(object);
|
|
||||||
fn(object_geometry, base_transform, id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case InstanceReference::Type::Collection: {
|
|
||||||
Collection &collection = reference.collection();
|
|
||||||
float4x4 offset_matrix = float4x4::identity();
|
|
||||||
offset_matrix.location() -= collection.instance_offset;
|
|
||||||
int index = 0;
|
|
||||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
|
|
||||||
const bke::GeometrySet object_geometry = bke::object_get_evaluated_geometry_set(*object);
|
|
||||||
const float4x4 matrix = base_transform * offset_matrix * object->object_to_world();
|
|
||||||
const int sub_id = noise::hash(id, index);
|
|
||||||
fn(object_geometry, matrix, sub_id);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case InstanceReference::Type::GeometrySet: {
|
|
||||||
const bke::GeometrySet &instance_geometry_set = reference.geometry_set();
|
|
||||||
fn(instance_geometry_set, base_transform, id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case InstanceReference::Type::None: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
|
static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
|
||||||
|
const int current_depth,
|
||||||
|
const int target_depth,
|
||||||
const Instances &instances,
|
const Instances &instances,
|
||||||
const float4x4 &base_transform,
|
const float4x4 &base_transform,
|
||||||
const InstanceContext &base_instance_context)
|
const InstanceContext &base_instance_context)
|
||||||
@ -532,8 +575,17 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
|
|||||||
gather_info, instances, gather_info.meshes.attributes);
|
gather_info, instances, gather_info.meshes.attributes);
|
||||||
Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
|
Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
|
||||||
gather_info, instances, gather_info.curves.attributes);
|
gather_info, instances, gather_info.curves.attributes);
|
||||||
|
Vector<std::pair<int, GSpan>> instance_attributes_to_override = prepare_attribute_fallbacks(
|
||||||
|
gather_info, instances, gather_info.instances_attriubutes);
|
||||||
|
|
||||||
for (const int i : transforms.index_range()) {
|
/* If at top level, get instance indices from selection field, else use all instances. */
|
||||||
|
const IndexMask indices = current_depth == 0 ? gather_info.selection :
|
||||||
|
IndexMask(IndexRange(instances.instances_num()));
|
||||||
|
for (const int mask_index : indices.index_range()) {
|
||||||
|
const int i = indices[mask_index];
|
||||||
|
|
||||||
|
/* If at top level, retrieve depth from gather_info, else continue with target_depth. */
|
||||||
|
const int depth_target = current_depth == 0 ? gather_info.depths[mask_index] : target_depth;
|
||||||
const int handle = handles[i];
|
const int handle = handles[i];
|
||||||
const float4x4 &transform = transforms[i];
|
const float4x4 &transform = transforms[i];
|
||||||
const InstanceReference &reference = references[handle];
|
const InstanceReference &reference = references[handle];
|
||||||
@ -549,6 +601,9 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
|
|||||||
for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
|
for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
|
||||||
instance_context.curves.array[pair.first] = pair.second[i];
|
instance_context.curves.array[pair.first] = pair.second[i];
|
||||||
}
|
}
|
||||||
|
for (const std::pair<int, GSpan> &pair : instance_attributes_to_override) {
|
||||||
|
instance_context.instances.array[pair.first] = pair.second[i];
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t local_instance_id = 0;
|
uint32_t local_instance_id = 0;
|
||||||
if (gather_info.create_id_attribute_on_any_component) {
|
if (gather_info.create_id_attribute_on_any_component) {
|
||||||
@ -570,6 +625,8 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
|
|||||||
const uint32_t id) {
|
const uint32_t id) {
|
||||||
instance_context.id = id;
|
instance_context.id = id;
|
||||||
gather_realize_tasks_recursive(gather_info,
|
gather_realize_tasks_recursive(gather_info,
|
||||||
|
current_depth + 1,
|
||||||
|
depth_target,
|
||||||
instance_geometry_set,
|
instance_geometry_set,
|
||||||
transform,
|
transform,
|
||||||
instance_context);
|
instance_context);
|
||||||
@ -581,6 +638,8 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
|
|||||||
* Gather tasks for all geometries in the #geometry_set.
|
* Gather tasks for all geometries in the #geometry_set.
|
||||||
*/
|
*/
|
||||||
static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
||||||
|
const int current_depth,
|
||||||
|
const int target_depth,
|
||||||
const bke::GeometrySet &geometry_set,
|
const bke::GeometrySet &geometry_set,
|
||||||
const float4x4 &base_transform,
|
const float4x4 &base_transform,
|
||||||
const InstanceContext &base_instance_context)
|
const InstanceContext &base_instance_context)
|
||||||
@ -589,9 +648,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
|||||||
const bke::GeometryComponent::Type type = component->type();
|
const bke::GeometryComponent::Type type = component->type();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case bke::GeometryComponent::Type::Mesh: {
|
case bke::GeometryComponent::Type::Mesh: {
|
||||||
const bke::MeshComponent &mesh_component = *static_cast<const bke::MeshComponent *>(
|
const Mesh *mesh = (*static_cast<const bke::MeshComponent *>(component)).get();
|
||||||
component);
|
|
||||||
const Mesh *mesh = mesh_component.get();
|
|
||||||
if (mesh != nullptr && mesh->verts_num > 0) {
|
if (mesh != nullptr && mesh->verts_num > 0) {
|
||||||
const int mesh_index = gather_info.meshes.order.index_of(mesh);
|
const int mesh_index = gather_info.meshes.order.index_of(mesh);
|
||||||
const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
|
const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
|
||||||
@ -641,17 +698,29 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case bke::GeometryComponent::Type::Instance: {
|
case bke::GeometryComponent::Type::Instance: {
|
||||||
const auto &instances_component = *static_cast<const bke::InstancesComponent *>(component);
|
if (current_depth == target_depth) {
|
||||||
const Instances *instances = instances_component.get();
|
gather_info.instances.attribute_fallback.append(base_instance_context.instances);
|
||||||
if (instances != nullptr && instances->instances_num() > 0) {
|
gather_info.instances.instances_components_to_merge.append(component->copy());
|
||||||
gather_realize_tasks_for_instances(
|
gather_info.instances.instances_components_transforms.append(base_transform);
|
||||||
gather_info, *instances, base_transform, base_instance_context);
|
}
|
||||||
|
else {
|
||||||
|
const Instances *instances =
|
||||||
|
(*static_cast<const bke::InstancesComponent *>(component)).get();
|
||||||
|
if (instances != nullptr && instances->instances_num() > 0) {
|
||||||
|
gather_realize_tasks_for_instances(gather_info,
|
||||||
|
current_depth,
|
||||||
|
target_depth,
|
||||||
|
*instances,
|
||||||
|
base_transform,
|
||||||
|
base_instance_context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case bke::GeometryComponent::Type::Volume: {
|
case bke::GeometryComponent::Type::Volume: {
|
||||||
const auto *volume_component = static_cast<const bke::VolumeComponent *>(component);
|
|
||||||
if (!gather_info.r_tasks.first_volume) {
|
if (!gather_info.r_tasks.first_volume) {
|
||||||
|
const bke::VolumeComponent *volume_component = static_cast<const bke::VolumeComponent *>(
|
||||||
|
component);
|
||||||
volume_component->add_user();
|
volume_component->add_user();
|
||||||
gather_info.r_tasks.first_volume = ImplicitSharingPtr<const bke::VolumeComponent>(
|
gather_info.r_tasks.first_volume = ImplicitSharingPtr<const bke::VolumeComponent>(
|
||||||
volume_component);
|
volume_component);
|
||||||
@ -659,9 +728,9 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case bke::GeometryComponent::Type::Edit: {
|
case bke::GeometryComponent::Type::Edit: {
|
||||||
const auto *edit_component = static_cast<const bke::GeometryComponentEditData *>(
|
|
||||||
component);
|
|
||||||
if (!gather_info.r_tasks.first_edit_data) {
|
if (!gather_info.r_tasks.first_edit_data) {
|
||||||
|
const bke::GeometryComponentEditData *edit_component =
|
||||||
|
static_cast<const bke::GeometryComponentEditData *>(component);
|
||||||
edit_component->add_user();
|
edit_component->add_user();
|
||||||
gather_info.r_tasks.first_edit_data =
|
gather_info.r_tasks.first_edit_data =
|
||||||
ImplicitSharingPtr<const bke::GeometryComponentEditData>(edit_component);
|
ImplicitSharingPtr<const bke::GeometryComponentEditData>(edit_component);
|
||||||
@ -676,6 +745,278 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function iterates through a set of geometries, applying a callback to each attribute of
|
||||||
|
* eligible children based on specified conditions. Attributes should not be removed or added
|
||||||
|
* by the callback. Relevant children are determined by three criteria: the component type
|
||||||
|
* (e.g., mesh, curve), a depth value greater than 0 and a selection. If the primary component
|
||||||
|
* is an instance, the condition is true only when the depth is exactly 0. Additionally, the
|
||||||
|
* function extends its operation to instances if any of their nested children meet the first
|
||||||
|
* condition.
|
||||||
|
*
|
||||||
|
* Based on bke::GeometrySet::attribute_foreach
|
||||||
|
*/
|
||||||
|
static bool attribute_foreach(const bke::GeometrySet &geometry_set,
|
||||||
|
const Span<bke::GeometryComponent::Type> component_types,
|
||||||
|
const int current_depth,
|
||||||
|
const int depth_target,
|
||||||
|
const VArray<int> instance_depth,
|
||||||
|
const IndexMask selection,
|
||||||
|
const bke::GeometrySet::AttributeForeachCallback callback)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*Initialize flag to track if child instances have the specified components.*/
|
||||||
|
bool child_has_component = true;
|
||||||
|
|
||||||
|
if (geometry_set.has_instances()) {
|
||||||
|
child_has_component = false;
|
||||||
|
|
||||||
|
const Instances &instances = *geometry_set.get_instances();
|
||||||
|
const IndexMask indices = (0 == current_depth) ?
|
||||||
|
selection :
|
||||||
|
IndexMask(IndexRange(instances.instances_num()));
|
||||||
|
for (const int index : indices.index_range()) {
|
||||||
|
const int i = indices[index];
|
||||||
|
const int depth_target_tmp = (0 == current_depth) ? instance_depth[i] : depth_target;
|
||||||
|
bke::GeometrySet instance_geometry_set;
|
||||||
|
geometry_set_from_reference(instances.references()[instances.reference_handles()[i]],
|
||||||
|
instance_geometry_set);
|
||||||
|
/*Process child instances with a recursive call.*/
|
||||||
|
if (current_depth != depth_target_tmp) {
|
||||||
|
child_has_component = child_has_component | attribute_foreach(instance_geometry_set,
|
||||||
|
component_types,
|
||||||
|
current_depth + 1,
|
||||||
|
depth_target_tmp,
|
||||||
|
instance_depth,
|
||||||
|
selection,
|
||||||
|
callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Flag to track if any relevant attributes were found.*/
|
||||||
|
bool is_relevant = false;
|
||||||
|
|
||||||
|
for (const bke::GeometryComponent::Type component_type : component_types) {
|
||||||
|
if (geometry_set.has(component_type)) {
|
||||||
|
/*Check if the current instance components is the main one*/
|
||||||
|
const bool is_special_instance = (bke::GeometryComponent::Type::Instance ==
|
||||||
|
component_type) &&
|
||||||
|
(component_types.size() > 1);
|
||||||
|
if (!is_special_instance || child_has_component) {
|
||||||
|
/*Process attributes for the current component.*/
|
||||||
|
const bke::GeometryComponent &component = *geometry_set.get_component(component_type);
|
||||||
|
const std::optional<bke::AttributeAccessor> attributes = component.attributes();
|
||||||
|
if (attributes.has_value()) {
|
||||||
|
attributes->for_all(
|
||||||
|
[&](const AttributeIDRef &attributeId, const AttributeMetaData &metaData) {
|
||||||
|
callback(attributeId, metaData, component);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
is_relevant = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_relevant;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on bke::GeometrySet::gather_attributes_for_propagation.
|
||||||
|
* Specialized for Specialized attribute_foreach to get:
|
||||||
|
* current_depth, depth_target, instance_depth and selection.
|
||||||
|
*/
|
||||||
|
void static gather_attributes_for_propagation(
|
||||||
|
bke::GeometrySet re_geometry_set,
|
||||||
|
const Span<bke::GeometryComponent::Type> component_types,
|
||||||
|
const bke::GeometryComponent::Type dst_component_type,
|
||||||
|
const VArray<int> instance_depth,
|
||||||
|
const IndexMask selection,
|
||||||
|
const bke::AnonymousAttributePropagationInfo &propagation_info,
|
||||||
|
Map<AttributeIDRef, AttributeKind> &r_attributes)
|
||||||
|
{
|
||||||
|
/* Only needed right now to check if an attribute is built-in on this component type.
|
||||||
|
* TODO: Get rid of the dummy component. */
|
||||||
|
const bke::GeometryComponentPtr dummy_component = bke::GeometryComponent::create(
|
||||||
|
dst_component_type);
|
||||||
|
attribute_foreach(re_geometry_set,
|
||||||
|
component_types,
|
||||||
|
0,
|
||||||
|
VariedDepthOption::MAX_DEPTH,
|
||||||
|
instance_depth,
|
||||||
|
selection,
|
||||||
|
[&](const AttributeIDRef &attribute_id,
|
||||||
|
const AttributeMetaData &meta_data,
|
||||||
|
const bke::GeometryComponent &component) {
|
||||||
|
if (component.attributes()->is_builtin(attribute_id)) {
|
||||||
|
if (!dummy_component->attributes()->is_builtin(attribute_id)) {
|
||||||
|
/* Don't propagate built-in attributes that are not built-in on the
|
||||||
|
* destination component. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (meta_data.data_type == CD_PROP_STRING) {
|
||||||
|
/* Propagating string attributes is not supported yet. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (attribute_id.is_anonymous() &&
|
||||||
|
!propagation_info.propagate(attribute_id.anonymous_id())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttrDomain domain = meta_data.domain;
|
||||||
|
if (dst_component_type != bke::GeometryComponent::Type::Instance &&
|
||||||
|
domain == AttrDomain::Instance) {
|
||||||
|
domain = AttrDomain::Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto add_info = [&](AttributeKind *attribute_kind) {
|
||||||
|
attribute_kind->domain = domain;
|
||||||
|
attribute_kind->data_type = meta_data.data_type;
|
||||||
|
};
|
||||||
|
auto modify_info = [&](AttributeKind *attribute_kind) {
|
||||||
|
attribute_kind->domain = bke::attribute_domain_highest_priority(
|
||||||
|
{attribute_kind->domain, domain});
|
||||||
|
attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
|
||||||
|
{attribute_kind->data_type, meta_data.data_type});
|
||||||
|
};
|
||||||
|
r_attributes.add_or_modify(attribute_id, add_info, modify_info);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Instance
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
static OrderedAttributes gather_generic_instance_attributes_to_propagate(
|
||||||
|
const bke::GeometrySet &in_geometry_set,
|
||||||
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option)
|
||||||
|
{
|
||||||
|
Vector<bke::GeometryComponent::Type> src_component_types;
|
||||||
|
src_component_types.append(bke::GeometryComponent::Type::Instance);
|
||||||
|
|
||||||
|
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
|
||||||
|
gather_attributes_for_propagation(in_geometry_set,
|
||||||
|
src_component_types,
|
||||||
|
bke::GeometryComponent::Type::Instance,
|
||||||
|
varied_depth_option.depths,
|
||||||
|
varied_depth_option.selection,
|
||||||
|
options.propagation_info,
|
||||||
|
attributes_to_propagate);
|
||||||
|
attributes_to_propagate.remove("position");
|
||||||
|
attributes_to_propagate.remove("radius");
|
||||||
|
attributes_to_propagate.pop_try("id").has_value();
|
||||||
|
OrderedAttributes ordered_attributes;
|
||||||
|
for (const auto item : attributes_to_propagate.items()) {
|
||||||
|
ordered_attributes.ids.add_new(item.key);
|
||||||
|
ordered_attributes.kinds.append(item.value);
|
||||||
|
}
|
||||||
|
return ordered_attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void execute_instances_tasks(
|
||||||
|
const Span<bke::GeometryComponentPtr> src_components,
|
||||||
|
Span<blender::float4x4> src_base_transforms,
|
||||||
|
OrderedAttributes all_instances_attributes,
|
||||||
|
Span<blender::geometry::AttributeFallbacksArray> attribute_fallback,
|
||||||
|
bke::GeometrySet &r_realized_geometry)
|
||||||
|
{
|
||||||
|
BLI_assert(src_components.size() == src_base_transforms.size() &&
|
||||||
|
src_components.size() == attribute_fallback.size());
|
||||||
|
if (src_components.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VArray<blender::float4x4>::ForSpan(src_base_transforms);
|
||||||
|
Array<int> offsets_data(src_components.size() + 1);
|
||||||
|
for (const int component_index : src_components.index_range()) {
|
||||||
|
const bke::InstancesComponent &src_component = static_cast<const bke::InstancesComponent &>(
|
||||||
|
*src_components[component_index]);
|
||||||
|
offsets_data[component_index] = src_component.get()->instances_num();
|
||||||
|
}
|
||||||
|
const OffsetIndices offsets = offset_indices::accumulate_counts_to_offsets(offsets_data);
|
||||||
|
|
||||||
|
std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
|
||||||
|
dst_instances->resize(offsets.total_size());
|
||||||
|
|
||||||
|
/* Prepare generic output attributes. */
|
||||||
|
for (const int attribute_index : all_instances_attributes.index_range()) {
|
||||||
|
bke::AttrDomain domain = bke::AttrDomain::Instance;
|
||||||
|
bke::AttributeIDRef id = all_instances_attributes.ids[attribute_index];
|
||||||
|
eCustomDataType type = all_instances_attributes.kinds[attribute_index].data_type;
|
||||||
|
blender::bke::MutableAttributeAccessor attr = dst_instances->attributes_for_write();
|
||||||
|
attr.lookup_or_add_for_write_only_span(id, domain, type).finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableSpan<float4x4> all_transforms = dst_instances->transforms_for_write();
|
||||||
|
MutableSpan<int> all_handles = dst_instances->reference_handles_for_write();
|
||||||
|
|
||||||
|
for (const int component_index : src_components.index_range()) {
|
||||||
|
const bke::InstancesComponent &src_component = static_cast<const bke::InstancesComponent &>(
|
||||||
|
*src_components[component_index]);
|
||||||
|
const bke::Instances &src_instances = *src_component.get();
|
||||||
|
const blender::float4x4 src_base_transform = src_base_transforms[component_index];
|
||||||
|
const Array<const void *> attribute_fallback_array = attribute_fallback[component_index].array;
|
||||||
|
const Span<bke::InstanceReference> src_references = src_instances.references();
|
||||||
|
Array<int> handle_map(src_references.size());
|
||||||
|
|
||||||
|
for (const int src_handle : src_references.index_range()) {
|
||||||
|
handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]);
|
||||||
|
}
|
||||||
|
const IndexRange dst_range = offsets[component_index];
|
||||||
|
for (const int attribute_index : all_instances_attributes.index_range()) {
|
||||||
|
bke::AttributeIDRef id = all_instances_attributes.ids[attribute_index];
|
||||||
|
eCustomDataType type = all_instances_attributes.kinds[attribute_index].data_type;
|
||||||
|
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
|
||||||
|
BLI_assert(cpp_type != nullptr);
|
||||||
|
bke::GSpanAttributeWriter write_attribute =
|
||||||
|
dst_instances->attributes_for_write().lookup_for_write_span(id);
|
||||||
|
GMutableSpan dst_span = write_attribute.span;
|
||||||
|
|
||||||
|
if (!write_attribute) { // do not override existing attributes
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *attribute_ptr;
|
||||||
|
if (attribute_fallback_array[attribute_index] != nullptr) {
|
||||||
|
attribute_ptr = attribute_fallback_array[attribute_index];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
attribute_ptr = cpp_type->default_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
GVArray src_span = GVArray::ForSingle(*cpp_type, dst_range.size(), attribute_ptr);
|
||||||
|
array_utils::copy(src_span, dst_span.slice(dst_range));
|
||||||
|
write_attribute.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
for (blender::float4x4 &transfrom : all_transforms.slice(dst_range)) {
|
||||||
|
transfrom *= src_base_transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r_realized_geometry.replace_instances(dst_instances.release());
|
||||||
|
auto &dst_component = r_realized_geometry.get_component_for_write<bke::InstancesComponent>();
|
||||||
|
|
||||||
|
Vector<const bke::GeometryComponent *> for_join_attributes;
|
||||||
|
for (bke::GeometryComponentPtr compent : src_components) {
|
||||||
|
for_join_attributes.append(compent.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
join_attributes(
|
||||||
|
for_join_attributes, dst_component, {"position", ".reference_index", "instance_transform"});
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
@ -685,6 +1026,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
|||||||
static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(
|
static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(
|
||||||
const bke::GeometrySet &in_geometry_set,
|
const bke::GeometrySet &in_geometry_set,
|
||||||
const RealizeInstancesOptions &options,
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option,
|
||||||
bool &r_create_radii,
|
bool &r_create_radii,
|
||||||
bool &r_create_id)
|
bool &r_create_id)
|
||||||
{
|
{
|
||||||
@ -695,11 +1037,14 @@ static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
|
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
|
||||||
in_geometry_set.gather_attributes_for_propagation(src_component_types,
|
gather_attributes_for_propagation(in_geometry_set,
|
||||||
bke::GeometryComponent::Type::PointCloud,
|
src_component_types,
|
||||||
true,
|
bke::GeometryComponent::Type::PointCloud,
|
||||||
options.propagation_info,
|
varied_depth_option.depths,
|
||||||
attributes_to_propagate);
|
varied_depth_option.selection,
|
||||||
|
options.propagation_info,
|
||||||
|
attributes_to_propagate);
|
||||||
|
|
||||||
attributes_to_propagate.remove("position");
|
attributes_to_propagate.remove("position");
|
||||||
r_create_id = attributes_to_propagate.pop_try("id").has_value();
|
r_create_id = attributes_to_propagate.pop_try("id").has_value();
|
||||||
r_create_radii = attributes_to_propagate.pop_try("radius").has_value();
|
r_create_radii = attributes_to_propagate.pop_try("radius").has_value();
|
||||||
@ -727,11 +1072,15 @@ static void gather_pointclouds_to_realize(const bke::GeometrySet &geometry_set,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static AllPointCloudsInfo preprocess_pointclouds(const bke::GeometrySet &geometry_set,
|
static AllPointCloudsInfo preprocess_pointclouds(const bke::GeometrySet &geometry_set,
|
||||||
const RealizeInstancesOptions &options)
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option)
|
||||||
{
|
{
|
||||||
AllPointCloudsInfo info;
|
AllPointCloudsInfo info;
|
||||||
info.attributes = gather_generic_pointcloud_attributes_to_propagate(
|
info.attributes = gather_generic_pointcloud_attributes_to_propagate(geometry_set,
|
||||||
geometry_set, options, info.create_radius_attribute, info.create_id_attribute);
|
options,
|
||||||
|
varied_depth_option,
|
||||||
|
info.create_radius_attribute,
|
||||||
|
info.create_id_attribute);
|
||||||
|
|
||||||
gather_pointclouds_to_realize(geometry_set, info.order);
|
gather_pointclouds_to_realize(geometry_set, info.order);
|
||||||
info.realize_info.reinitialize(info.order.size());
|
info.realize_info.reinitialize(info.order.size());
|
||||||
@ -770,7 +1119,7 @@ static AllPointCloudsInfo preprocess_pointclouds(const bke::GeometrySet &geometr
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void execute_realize_pointcloud_task(
|
static void execute_realize_pointcloud_task(
|
||||||
const RealizeInstancesOptions &options,
|
bool keep_original_ids,
|
||||||
const RealizePointCloudTask &task,
|
const RealizePointCloudTask &task,
|
||||||
const OrderedAttributes &ordered_attributes,
|
const OrderedAttributes &ordered_attributes,
|
||||||
MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
|
MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
|
||||||
@ -788,7 +1137,7 @@ static void execute_realize_pointcloud_task(
|
|||||||
/* Create point ids. */
|
/* Create point ids. */
|
||||||
if (!all_dst_ids.is_empty()) {
|
if (!all_dst_ids.is_empty()) {
|
||||||
create_result_ids(
|
create_result_ids(
|
||||||
options, pointcloud_info.stored_ids, task.id, all_dst_ids.slice(point_slice));
|
keep_original_ids, pointcloud_info.stored_ids, task.id, all_dst_ids.slice(point_slice));
|
||||||
}
|
}
|
||||||
if (!all_dst_radii.is_empty()) {
|
if (!all_dst_radii.is_empty()) {
|
||||||
pointcloud_info.radii.materialize(all_dst_radii.slice(point_slice));
|
pointcloud_info.radii.materialize(all_dst_radii.slice(point_slice));
|
||||||
@ -806,7 +1155,7 @@ static void execute_realize_pointcloud_task(
|
|||||||
dst_attribute_writers);
|
dst_attribute_writers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options,
|
static void execute_realize_pointcloud_tasks(bool keep_original_ids,
|
||||||
const AllPointCloudsInfo &all_pointclouds_info,
|
const AllPointCloudsInfo &all_pointclouds_info,
|
||||||
const Span<RealizePointCloudTask> tasks,
|
const Span<RealizePointCloudTask> tasks,
|
||||||
const OrderedAttributes &ordered_attributes,
|
const OrderedAttributes &ordered_attributes,
|
||||||
@ -858,7 +1207,7 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
|
|||||||
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
|
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
|
||||||
for (const int task_index : task_range) {
|
for (const int task_index : task_range) {
|
||||||
const RealizePointCloudTask &task = tasks[task_index];
|
const RealizePointCloudTask &task = tasks[task_index];
|
||||||
execute_realize_pointcloud_task(options,
|
execute_realize_pointcloud_task(keep_original_ids,
|
||||||
task,
|
task,
|
||||||
ordered_attributes,
|
ordered_attributes,
|
||||||
dst_attribute_writers,
|
dst_attribute_writers,
|
||||||
@ -886,6 +1235,7 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
|
|||||||
static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
|
static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
|
||||||
const bke::GeometrySet &in_geometry_set,
|
const bke::GeometrySet &in_geometry_set,
|
||||||
const RealizeInstancesOptions &options,
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option,
|
||||||
bool &r_create_id,
|
bool &r_create_id,
|
||||||
bool &r_create_material_index)
|
bool &r_create_material_index)
|
||||||
{
|
{
|
||||||
@ -896,11 +1246,13 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
|
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
|
||||||
in_geometry_set.gather_attributes_for_propagation(src_component_types,
|
gather_attributes_for_propagation(in_geometry_set,
|
||||||
bke::GeometryComponent::Type::Mesh,
|
src_component_types,
|
||||||
true,
|
bke::GeometryComponent::Type::Mesh,
|
||||||
options.propagation_info,
|
varied_depth_option.depths,
|
||||||
attributes_to_propagate);
|
varied_depth_option.selection,
|
||||||
|
options.propagation_info,
|
||||||
|
attributes_to_propagate);
|
||||||
attributes_to_propagate.remove("position");
|
attributes_to_propagate.remove("position");
|
||||||
attributes_to_propagate.remove(".edge_verts");
|
attributes_to_propagate.remove(".edge_verts");
|
||||||
attributes_to_propagate.remove(".corner_vert");
|
attributes_to_propagate.remove(".corner_vert");
|
||||||
@ -931,11 +1283,16 @@ static void gather_meshes_to_realize(const bke::GeometrySet &geometry_set,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static AllMeshesInfo preprocess_meshes(const bke::GeometrySet &geometry_set,
|
static AllMeshesInfo preprocess_meshes(const bke::GeometrySet &geometry_set,
|
||||||
const RealizeInstancesOptions &options)
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option)
|
||||||
{
|
{
|
||||||
AllMeshesInfo info;
|
AllMeshesInfo info;
|
||||||
info.attributes = gather_generic_mesh_attributes_to_propagate(
|
info.attributes = gather_generic_mesh_attributes_to_propagate(
|
||||||
geometry_set, options, info.create_id_attribute, info.create_material_index_attribute);
|
geometry_set,
|
||||||
|
options,
|
||||||
|
varied_depth_option,
|
||||||
|
info.create_id_attribute,
|
||||||
|
info.create_material_index_attribute);
|
||||||
|
|
||||||
gather_meshes_to_realize(geometry_set, info.order);
|
gather_meshes_to_realize(geometry_set, info.order);
|
||||||
for (const Mesh *mesh : info.order) {
|
for (const Mesh *mesh : info.order) {
|
||||||
@ -1013,7 +1370,7 @@ static AllMeshesInfo preprocess_meshes(const bke::GeometrySet &geometry_set,
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
|
static void execute_realize_mesh_task(bool keep_original_ids,
|
||||||
const RealizeMeshTask &task,
|
const RealizeMeshTask &task,
|
||||||
const OrderedAttributes &ordered_attributes,
|
const OrderedAttributes &ordered_attributes,
|
||||||
MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
|
MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
|
||||||
@ -1097,7 +1454,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!all_dst_vertex_ids.is_empty()) {
|
if (!all_dst_vertex_ids.is_empty()) {
|
||||||
create_result_ids(options,
|
create_result_ids(keep_original_ids,
|
||||||
mesh_info.stored_vertex_ids,
|
mesh_info.stored_vertex_ids,
|
||||||
task.id,
|
task.id,
|
||||||
all_dst_vertex_ids.slice(task.start_indices.vertex, mesh.verts_num));
|
all_dst_vertex_ids.slice(task.start_indices.vertex, mesh.verts_num));
|
||||||
@ -1125,7 +1482,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
|
|||||||
dst_attribute_writers);
|
dst_attribute_writers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
|
static void execute_realize_mesh_tasks(bool keep_original_ids,
|
||||||
const AllMeshesInfo &all_meshes_info,
|
const AllMeshesInfo &all_meshes_info,
|
||||||
const Span<RealizeMeshTask> tasks,
|
const Span<RealizeMeshTask> tasks,
|
||||||
const OrderedAttributes &ordered_attributes,
|
const OrderedAttributes &ordered_attributes,
|
||||||
@ -1208,7 +1565,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
|
|||||||
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
|
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
|
||||||
for (const int task_index : task_range) {
|
for (const int task_index : task_range) {
|
||||||
const RealizeMeshTask &task = tasks[task_index];
|
const RealizeMeshTask &task = tasks[task_index];
|
||||||
execute_realize_mesh_task(options,
|
execute_realize_mesh_task(keep_original_ids,
|
||||||
task,
|
task,
|
||||||
ordered_attributes,
|
ordered_attributes,
|
||||||
dst_attribute_writers,
|
dst_attribute_writers,
|
||||||
@ -1249,6 +1606,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
|
|||||||
static OrderedAttributes gather_generic_curve_attributes_to_propagate(
|
static OrderedAttributes gather_generic_curve_attributes_to_propagate(
|
||||||
const bke::GeometrySet &in_geometry_set,
|
const bke::GeometrySet &in_geometry_set,
|
||||||
const RealizeInstancesOptions &options,
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option,
|
||||||
bool &r_create_id)
|
bool &r_create_id)
|
||||||
{
|
{
|
||||||
Vector<bke::GeometryComponent::Type> src_component_types;
|
Vector<bke::GeometryComponent::Type> src_component_types;
|
||||||
@ -1258,11 +1616,13 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
|
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
|
||||||
in_geometry_set.gather_attributes_for_propagation(src_component_types,
|
gather_attributes_for_propagation(in_geometry_set,
|
||||||
bke::GeometryComponent::Type::Curve,
|
src_component_types,
|
||||||
true,
|
bke::GeometryComponent::Type::Curve,
|
||||||
options.propagation_info,
|
varied_depth_option.depths,
|
||||||
attributes_to_propagate);
|
varied_depth_option.selection,
|
||||||
|
options.propagation_info,
|
||||||
|
attributes_to_propagate);
|
||||||
attributes_to_propagate.remove("position");
|
attributes_to_propagate.remove("position");
|
||||||
attributes_to_propagate.remove("radius");
|
attributes_to_propagate.remove("radius");
|
||||||
attributes_to_propagate.remove("nurbs_weight");
|
attributes_to_propagate.remove("nurbs_weight");
|
||||||
@ -1295,11 +1655,12 @@ static void gather_curves_to_realize(const bke::GeometrySet &geometry_set,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static AllCurvesInfo preprocess_curves(const bke::GeometrySet &geometry_set,
|
static AllCurvesInfo preprocess_curves(const bke::GeometrySet &geometry_set,
|
||||||
const RealizeInstancesOptions &options)
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option)
|
||||||
{
|
{
|
||||||
AllCurvesInfo info;
|
AllCurvesInfo info;
|
||||||
info.attributes = gather_generic_curve_attributes_to_propagate(
|
info.attributes = gather_generic_curve_attributes_to_propagate(
|
||||||
geometry_set, options, info.create_id_attribute);
|
geometry_set, options, varied_depth_option, info.create_id_attribute);
|
||||||
|
|
||||||
gather_curves_to_realize(geometry_set, info.order);
|
gather_curves_to_realize(geometry_set, info.order);
|
||||||
info.realize_info.reinitialize(info.order.size());
|
info.realize_info.reinitialize(info.order.size());
|
||||||
@ -1358,7 +1719,7 @@ static AllCurvesInfo preprocess_curves(const bke::GeometrySet &geometry_set,
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute_realize_curve_task(const RealizeInstancesOptions &options,
|
static void execute_realize_curve_task(bool keep_original_ids,
|
||||||
const AllCurvesInfo &all_curves_info,
|
const AllCurvesInfo &all_curves_info,
|
||||||
const RealizeCurveTask &task,
|
const RealizeCurveTask &task,
|
||||||
const OrderedAttributes &ordered_attributes,
|
const OrderedAttributes &ordered_attributes,
|
||||||
@ -1441,7 +1802,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
|
|||||||
|
|
||||||
if (!all_dst_ids.is_empty()) {
|
if (!all_dst_ids.is_empty()) {
|
||||||
create_result_ids(
|
create_result_ids(
|
||||||
options, curves_info.stored_ids, task.id, all_dst_ids.slice(dst_point_range));
|
keep_original_ids, curves_info.stored_ids, task.id, all_dst_ids.slice(dst_point_range));
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_generic_attributes_to_result(
|
copy_generic_attributes_to_result(
|
||||||
@ -1462,7 +1823,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
|
|||||||
dst_attribute_writers);
|
dst_attribute_writers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
static void execute_realize_curve_tasks(bool keep_original_ids,
|
||||||
const AllCurvesInfo &all_curves_info,
|
const AllCurvesInfo &all_curves_info,
|
||||||
const Span<RealizeCurveTask> tasks,
|
const Span<RealizeCurveTask> tasks,
|
||||||
const OrderedAttributes &ordered_attributes,
|
const OrderedAttributes &ordered_attributes,
|
||||||
@ -1541,7 +1902,7 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
|||||||
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
|
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
|
||||||
for (const int task_index : task_range) {
|
for (const int task_index : task_range) {
|
||||||
const RealizeCurveTask &task = tasks[task_index];
|
const RealizeCurveTask &task = tasks[task_index];
|
||||||
execute_realize_curve_task(options,
|
execute_realize_curve_task(keep_original_ids,
|
||||||
all_curves_info,
|
all_curves_info,
|
||||||
task,
|
task,
|
||||||
ordered_attributes,
|
ordered_attributes,
|
||||||
@ -1594,8 +1955,50 @@ static void remove_id_attribute_from_instances(bke::GeometrySet &geometry_set)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Propagate instances from the old geometry set to the new geometry set if they are not realized.
|
||||||
|
*/
|
||||||
|
static void propagate_instances_to_keep(
|
||||||
|
const bke::GeometrySet &geometry_set,
|
||||||
|
IndexMask selection,
|
||||||
|
bke::GeometrySet &new_geometry_set,
|
||||||
|
const bke::AnonymousAttributePropagationInfo &propagation_info)
|
||||||
|
{
|
||||||
|
const Instances &instances = *geometry_set.get_instances();
|
||||||
|
IndexMaskMemory inverse_selection_indices;
|
||||||
|
const IndexMask inverse_selection = selection.complement(IndexRange(instances.instances_num()),
|
||||||
|
inverse_selection_indices);
|
||||||
|
/* Check not all instances are being realized. */
|
||||||
|
if (inverse_selection.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Instances> new_instances = std::make_unique<Instances>(instances);
|
||||||
|
new_instances->remove(inverse_selection, propagation_info);
|
||||||
|
|
||||||
|
bke::InstancesComponent &new_instances_components =
|
||||||
|
new_geometry_set.get_component_for_write<bke::InstancesComponent>();
|
||||||
|
new_instances_components.replace(new_instances.release(), bke::GeometryOwnershipType::Owned);
|
||||||
|
}
|
||||||
|
|
||||||
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set,
|
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set,
|
||||||
const RealizeInstancesOptions &options)
|
const RealizeInstancesOptions &options)
|
||||||
|
{
|
||||||
|
if (!geometry_set.has_instances()) {
|
||||||
|
return geometry_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
VariedDepthOption all_instances;
|
||||||
|
all_instances.depths = VArray<int>::ForSingle(VariedDepthOption::MAX_DEPTH,
|
||||||
|
geometry_set.get_instances()->instances_num());
|
||||||
|
IndexMaskMemory memory;
|
||||||
|
all_instances.selection = IndexMask::from_bools(
|
||||||
|
VArray<bool>::ForSingle(true, geometry_set.get_instances()->instances_num()), memory);
|
||||||
|
return realize_instances(geometry_set, options, all_instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set,
|
||||||
|
const RealizeInstancesOptions &options,
|
||||||
|
const VariedDepthOption &varied_depth_option)
|
||||||
{
|
{
|
||||||
/* The algorithm works in three steps:
|
/* The algorithm works in three steps:
|
||||||
* 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
|
* 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
|
||||||
@ -1608,46 +2011,78 @@ bke::GeometrySet realize_instances(bke::GeometrySet geometry_set,
|
|||||||
return geometry_set;
|
return geometry_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bke::GeometrySet not_to_realize_set;
|
||||||
|
propagate_instances_to_keep(
|
||||||
|
geometry_set, varied_depth_option.selection, not_to_realize_set, options.propagation_info);
|
||||||
|
|
||||||
if (options.keep_original_ids) {
|
if (options.keep_original_ids) {
|
||||||
remove_id_attribute_from_instances(geometry_set);
|
remove_id_attribute_from_instances(geometry_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(geometry_set, options);
|
AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(
|
||||||
AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options);
|
geometry_set, options, varied_depth_option);
|
||||||
AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options);
|
AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options, varied_depth_option);
|
||||||
|
AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options, varied_depth_option);
|
||||||
|
OrderedAttributes all_instance_attributes = gather_generic_instance_attributes_to_propagate(
|
||||||
|
geometry_set, options, varied_depth_option);
|
||||||
|
|
||||||
Vector<std::unique_ptr<GArray<>>> temporary_arrays;
|
|
||||||
const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
|
const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
|
||||||
all_meshes_info.create_id_attribute ||
|
all_meshes_info.create_id_attribute ||
|
||||||
all_curves_info.create_id_attribute;
|
all_curves_info.create_id_attribute;
|
||||||
|
Vector<std::unique_ptr<GArray<>>> temporary_arrays;
|
||||||
GatherTasksInfo gather_info = {all_pointclouds_info,
|
GatherTasksInfo gather_info = {all_pointclouds_info,
|
||||||
all_meshes_info,
|
all_meshes_info,
|
||||||
all_curves_info,
|
all_curves_info,
|
||||||
|
all_instance_attributes,
|
||||||
create_id_attribute,
|
create_id_attribute,
|
||||||
|
varied_depth_option.selection,
|
||||||
|
varied_depth_option.depths,
|
||||||
temporary_arrays};
|
temporary_arrays};
|
||||||
|
|
||||||
|
if (not_to_realize_set.has_instances()) {
|
||||||
|
gather_info.instances.instances_components_to_merge.append(
|
||||||
|
(not_to_realize_set.get_component_for_write<bke::InstancesComponent>()).copy());
|
||||||
|
gather_info.instances.instances_components_transforms.append(float4x4::identity());
|
||||||
|
gather_info.instances.attribute_fallback.append((gather_info.instances_attriubutes.size()));
|
||||||
|
}
|
||||||
|
|
||||||
const float4x4 transform = float4x4::identity();
|
const float4x4 transform = float4x4::identity();
|
||||||
InstanceContext attribute_fallbacks(gather_info);
|
InstanceContext attribute_fallbacks(gather_info);
|
||||||
gather_realize_tasks_recursive(gather_info, geometry_set, transform, attribute_fallbacks);
|
|
||||||
|
gather_realize_tasks_recursive(gather_info,
|
||||||
|
0,
|
||||||
|
VariedDepthOption::MAX_DEPTH,
|
||||||
|
geometry_set,
|
||||||
|
transform,
|
||||||
|
attribute_fallbacks);
|
||||||
|
|
||||||
bke::GeometrySet new_geometry_set;
|
bke::GeometrySet new_geometry_set;
|
||||||
|
|
||||||
|
execute_instances_tasks(gather_info.instances.instances_components_to_merge,
|
||||||
|
gather_info.instances.instances_components_transforms,
|
||||||
|
all_instance_attributes,
|
||||||
|
gather_info.instances.attribute_fallback,
|
||||||
|
new_geometry_set);
|
||||||
|
|
||||||
const int64_t total_points_num = get_final_points_num(gather_info.r_tasks);
|
const int64_t total_points_num = get_final_points_num(gather_info.r_tasks);
|
||||||
/* This doesn't have to be exact at all, it's just a rough estimate ot make decisions about
|
/* This doesn't have to be exact at all, it's just a rough estimate ot make decisions about
|
||||||
* multi-threading (overhead). */
|
* multi-threading (overhead). */
|
||||||
const int64_t approximate_used_bytes_num = total_points_num * 32;
|
const int64_t approximate_used_bytes_num = total_points_num * 32;
|
||||||
threading::memory_bandwidth_bound_task(approximate_used_bytes_num, [&]() {
|
threading::memory_bandwidth_bound_task(approximate_used_bytes_num, [&]() {
|
||||||
execute_realize_pointcloud_tasks(options,
|
execute_realize_pointcloud_tasks(options.keep_original_ids,
|
||||||
all_pointclouds_info,
|
all_pointclouds_info,
|
||||||
gather_info.r_tasks.pointcloud_tasks,
|
gather_info.r_tasks.pointcloud_tasks,
|
||||||
all_pointclouds_info.attributes,
|
all_pointclouds_info.attributes,
|
||||||
new_geometry_set);
|
new_geometry_set);
|
||||||
execute_realize_mesh_tasks(options,
|
|
||||||
all_meshes_info,
|
execute_realize_mesh_tasks(options.keep_original_ids,
|
||||||
gather_info.r_tasks.mesh_tasks,
|
all_meshes_info,
|
||||||
all_meshes_info.attributes,
|
gather_info.r_tasks.mesh_tasks,
|
||||||
all_meshes_info.materials,
|
all_meshes_info.attributes,
|
||||||
new_geometry_set);
|
all_meshes_info.materials,
|
||||||
execute_realize_curve_tasks(options,
|
new_geometry_set);
|
||||||
|
|
||||||
|
execute_realize_curve_tasks(options.keep_original_ids,
|
||||||
all_curves_info,
|
all_curves_info,
|
||||||
gather_info.r_tasks.curve_tasks,
|
gather_info.r_tasks.curve_tasks,
|
||||||
all_curves_info.attributes,
|
all_curves_info.attributes,
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include "node_geometry_util.hh"
|
#include "node_geometry_util.hh"
|
||||||
|
|
||||||
|
#include "BKE_instances.hh"
|
||||||
|
|
||||||
#include "GEO_realize_instances.hh"
|
#include "GEO_realize_instances.hh"
|
||||||
|
|
||||||
#include "UI_resources.hh"
|
#include "UI_resources.hh"
|
||||||
@ -13,18 +15,65 @@ namespace blender::nodes::node_geo_realize_instances_cc {
|
|||||||
static void node_declare(NodeDeclarationBuilder &b)
|
static void node_declare(NodeDeclarationBuilder &b)
|
||||||
{
|
{
|
||||||
b.add_input<decl::Geometry>("Geometry");
|
b.add_input<decl::Geometry>("Geometry");
|
||||||
|
b.add_input<decl::Bool>("Selection")
|
||||||
|
.default_value(true)
|
||||||
|
.hide_value()
|
||||||
|
.supports_field()
|
||||||
|
.description("Which top-level instances to realize");
|
||||||
|
b.add_input<decl::Bool>("Realize All")
|
||||||
|
.default_value(true)
|
||||||
|
.supports_field()
|
||||||
|
.description("Determine wether to realize nested instances completly");
|
||||||
|
b.add_input<decl::Int>("Depth").default_value(0).min(0).supports_field().description(
|
||||||
|
"Number of levels of nested instances to realize for each top-level instance");
|
||||||
b.add_output<decl::Geometry>("Geometry").propagate_all();
|
b.add_output<decl::Geometry>("Geometry").propagate_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void node_geo_exec(GeoNodeExecParams params)
|
static void node_geo_exec(GeoNodeExecParams params)
|
||||||
{
|
{
|
||||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
||||||
|
if (!geometry_set.has_instances()) {
|
||||||
|
params.set_output("Geometry", std::move(geometry_set));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);
|
GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);
|
||||||
|
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||||
|
Field<bool> realize_all_filed = params.extract_input<Field<bool>>("Realize All");
|
||||||
|
Field<int> depth_field = params.extract_input<Field<int>>("Depth");
|
||||||
|
|
||||||
|
static auto depth_override = mf::build::SI2_SO<int, bool, int>(
|
||||||
|
"depth_override",
|
||||||
|
[](int value, bool realize) { return realize ? -1 : std::max(value, 0); },
|
||||||
|
mf::build::exec_presets::AllSpanOrSingle());
|
||||||
|
|
||||||
|
static auto selection_override = mf::build::SI2_SO<int, bool, bool>(
|
||||||
|
"selection_override",
|
||||||
|
[](int value, bool selection) { return value == 0 ? false : selection; },
|
||||||
|
mf::build::exec_presets::AllSpanOrSingle());
|
||||||
|
|
||||||
|
Field<int> depth_field_overrided(
|
||||||
|
FieldOperation::Create(depth_override, {depth_field, realize_all_filed}));
|
||||||
|
Field<bool> selection_field_overrided(
|
||||||
|
FieldOperation::Create(selection_override, {depth_field_overrided, selection_field}));
|
||||||
|
|
||||||
|
const bke::Instances &instances = *geometry_set.get_instances();
|
||||||
|
const bke::InstancesFieldContext field_context(instances);
|
||||||
|
fn::FieldEvaluator evaluator(field_context, instances.instances_num());
|
||||||
|
|
||||||
|
const int evaluated_depth_index = evaluator.add(depth_field_overrided);
|
||||||
|
evaluator.set_selection(selection_field_overrided);
|
||||||
|
evaluator.evaluate();
|
||||||
|
|
||||||
|
geometry::VariedDepthOption varied_depth_option;
|
||||||
|
varied_depth_option.depths = evaluator.get_evaluated<int>(evaluated_depth_index);
|
||||||
|
varied_depth_option.selection = evaluator.get_evaluated_selection_as_mask();
|
||||||
|
|
||||||
geometry::RealizeInstancesOptions options;
|
geometry::RealizeInstancesOptions options;
|
||||||
options.keep_original_ids = false;
|
options.keep_original_ids = false;
|
||||||
options.realize_instance_attributes = true;
|
options.realize_instance_attributes = true;
|
||||||
options.propagation_info = params.get_output_propagation_info("Geometry");
|
options.propagation_info = params.get_output_propagation_info("Geometry");
|
||||||
geometry_set = geometry::realize_instances(geometry_set, options);
|
geometry_set = geometry::realize_instances(geometry_set, options, varied_depth_option);
|
||||||
params.set_output("Geometry", std::move(geometry_set));
|
params.set_output("Geometry", std::move(geometry_set));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user