Curves: Port realize instances node to the new data-block
This commit replaces the temporary conversion to `CurveEval` with use of the new curves data-block. The end result is that the process looks more like the other components-- somewhere in between meshes and point clouds in terms of complexity. The final result is that the logic between meshes and curves is very similar. There are a few different strategies to reduce duplication here, so I'll investigate that separately. There is some special behavior for the radius and handle position attributes. I used the attribute API to store spans of these attributes temporarily. Using access methods on `CurvesGeometry` would be reasonable to, storing spans separately feels a bit more predictable for now though. There should be significant performance improvements in some cases, I haven't tested that specifically though. Differential Revision: https://developer.blender.org/D14247
This commit is contained in:
parent
39c50d8f31
commit
6c6f591f90
Notes:
blender-bot
2023-02-14 03:21:27 +01:00
Referenced by issue #95443, Refactor curve nodes to use new data structure
|
@ -121,15 +121,37 @@ struct RealizeMeshTask {
|
|||
struct RealizeCurveInfo {
|
||||
const Curves *curves;
|
||||
/**
|
||||
* Matches the order in #AllCurvesInfo.attributes. For point attributes, the `std::optional`
|
||||
* will be empty.
|
||||
* Matches the order in #AllCurvesInfo.attributes.
|
||||
*/
|
||||
Array<std::optional<GVArray_GSpan>> spline_attributes;
|
||||
Array<std::optional<GVArray_GSpan>> attributes;
|
||||
|
||||
/** ID attribute on the curves. If there are no ids, this #Span is empty. */
|
||||
Span<int> stored_ids;
|
||||
|
||||
/**
|
||||
* Handle position attributes must be transformed along with positions. Accessing them in
|
||||
* advance isn't necessary theoretically, but is done to simplify other code and to avoid
|
||||
* some overhead.
|
||||
*/
|
||||
Span<float3> handle_left;
|
||||
Span<float3> handle_right;
|
||||
|
||||
/**
|
||||
* The radius attribute must be filled with a default of 1.0 if it
|
||||
* doesn't exist on some (but not all) of the input curves data-blocks.
|
||||
*/
|
||||
Span<float> radius;
|
||||
};
|
||||
|
||||
/** Start indices in the final output curves data-block. */
|
||||
struct CurvesElementStartIndices {
|
||||
int point = 0;
|
||||
int curve = 0;
|
||||
};
|
||||
|
||||
struct RealizeCurveTask {
|
||||
/* Start index in the final curve. */
|
||||
int start_spline_index = 0;
|
||||
CurvesElementStartIndices start_indices;
|
||||
|
||||
const RealizeCurveInfo *curve_info;
|
||||
/* Transformation applied to the position of control points and handles. */
|
||||
float4x4 transform;
|
||||
|
@ -168,6 +190,8 @@ struct AllCurvesInfo {
|
|||
/** Preprocessed data about every original curve. This is ordered by #order. */
|
||||
Array<RealizeCurveInfo> realize_info;
|
||||
bool create_id_attribute = false;
|
||||
bool create_handle_postion_attributes = false;
|
||||
bool create_radius_attribute = false;
|
||||
};
|
||||
|
||||
/** Collects all tasks that need to be executed to realize all instances. */
|
||||
|
@ -185,7 +209,7 @@ struct GatherTasks {
|
|||
struct GatherOffsets {
|
||||
int pointcloud_offset = 0;
|
||||
MeshElementStartIndices mesh_offsets;
|
||||
int spline_offset = 0;
|
||||
CurvesElementStartIndices curves_offsets;
|
||||
};
|
||||
|
||||
struct GatherTasksInfo {
|
||||
|
@ -230,6 +254,17 @@ struct InstanceContext {
|
|||
}
|
||||
};
|
||||
|
||||
static void copy_transformed_positions(const Span<float3> src,
|
||||
const float4x4 &transform,
|
||||
MutableSpan<float3> dst)
|
||||
{
|
||||
threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
dst[i] = transform * src[i];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Gather Realize Tasks
|
||||
* \{ */
|
||||
|
@ -448,12 +483,13 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
|||
if (curves != nullptr && curves->geometry.curve_size > 0) {
|
||||
const int curve_index = gather_info.curves.order.index_of(curves);
|
||||
const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
|
||||
gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.spline_offset,
|
||||
gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.curves_offsets,
|
||||
&curve_info,
|
||||
base_transform,
|
||||
base_instance_context.curves,
|
||||
base_instance_context.id});
|
||||
gather_info.r_offsets.spline_offset += curves->geometry.curve_size;
|
||||
gather_info.r_offsets.curves_offsets.point += curves->geometry.point_size;
|
||||
gather_info.r_offsets.curves_offsets.curve += curves->geometry.curve_size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -571,12 +607,8 @@ static void execute_realize_pointcloud_task(const RealizeInstancesOptions &optio
|
|||
pointcloud.totpoint};
|
||||
MutableSpan<int> dst_ids = all_dst_ids.slice(task.start_index, pointcloud.totpoint);
|
||||
|
||||
/* Copy transformed positions. */
|
||||
threading::parallel_for(IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
dst_positions[i] = task.transform * src_positions[i];
|
||||
}
|
||||
});
|
||||
copy_transformed_positions(src_positions, task.transform, dst_positions);
|
||||
|
||||
/* Create point ids. */
|
||||
if (!all_dst_ids.is_empty()) {
|
||||
if (options.keep_original_ids) {
|
||||
|
@ -1007,7 +1039,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
|
|||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Curve
|
||||
/** \name Curves
|
||||
* \{ */
|
||||
|
||||
static OrderedAttributes gather_generic_curve_attributes_to_propagate(
|
||||
|
@ -1023,9 +1055,6 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate(
|
|||
in_geometry_set.gather_attributes_for_propagation(
|
||||
src_component_types, GEO_COMPONENT_TYPE_CURVE, true, attributes_to_propagate);
|
||||
attributes_to_propagate.remove("position");
|
||||
attributes_to_propagate.remove("cyclic");
|
||||
attributes_to_propagate.remove("resolution");
|
||||
attributes_to_propagate.remove("tilt");
|
||||
attributes_to_propagate.remove("radius");
|
||||
attributes_to_propagate.remove("handle_right");
|
||||
attributes_to_propagate.remove("handle_left");
|
||||
|
@ -1071,19 +1100,43 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
|
|||
/* Access attributes. */
|
||||
CurveComponent component;
|
||||
component.replace(const_cast<Curves *>(curves), GeometryOwnershipType::ReadOnly);
|
||||
curve_info.spline_attributes.reinitialize(info.attributes.size());
|
||||
curve_info.attributes.reinitialize(info.attributes.size());
|
||||
for (const int attribute_index : info.attributes.index_range()) {
|
||||
const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
|
||||
if (domain != ATTR_DOMAIN_CURVE) {
|
||||
continue;
|
||||
}
|
||||
const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
|
||||
const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
|
||||
if (component.attribute_exists(attribute_id)) {
|
||||
GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
|
||||
curve_info.spline_attributes[attribute_index].emplace(std::move(attribute));
|
||||
curve_info.attributes[attribute_index].emplace(std::move(attribute));
|
||||
}
|
||||
}
|
||||
if (info.create_id_attribute) {
|
||||
ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
|
||||
if (ids_lookup) {
|
||||
curve_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>();
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve the radius attribute, if it exists. */
|
||||
if (component.attribute_exists("radius")) {
|
||||
curve_info.radius = component
|
||||
.attribute_get_for_read<float>("radius", ATTR_DOMAIN_POINT, 0.0f)
|
||||
.get_internal_span();
|
||||
info.create_radius_attribute = true;
|
||||
}
|
||||
|
||||
/* Retrieve handle position attributes, if they exist. */
|
||||
if (component.attribute_exists("handle_right")) {
|
||||
curve_info.handle_left = component
|
||||
.attribute_get_for_read<float3>(
|
||||
"handle_left", ATTR_DOMAIN_POINT, float3(0))
|
||||
.get_internal_span();
|
||||
curve_info.handle_right = component
|
||||
.attribute_get_for_read<float3>(
|
||||
"handle_right", ATTR_DOMAIN_POINT, float3(0))
|
||||
.get_internal_span();
|
||||
info.create_handle_postion_attributes = true;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
@ -1092,108 +1145,129 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
|
|||
const AllCurvesInfo &all_curves_info,
|
||||
const RealizeCurveTask &task,
|
||||
const OrderedAttributes &ordered_attributes,
|
||||
MutableSpan<SplinePtr> dst_splines,
|
||||
MutableSpan<GMutableSpan> dst_spline_attributes)
|
||||
bke::CurvesGeometry &dst_curves,
|
||||
MutableSpan<GMutableSpan> dst_attribute_spans,
|
||||
MutableSpan<int> all_dst_ids,
|
||||
MutableSpan<float3> all_handle_left,
|
||||
MutableSpan<float3> all_handle_right,
|
||||
MutableSpan<float> all_radii)
|
||||
{
|
||||
const RealizeCurveInfo &curve_info = *task.curve_info;
|
||||
const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_info.curves);
|
||||
const RealizeCurveInfo &curves_info = *task.curve_info;
|
||||
const Curves &curves_id = *curves_info.curves;
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
const Span<SplinePtr> src_splines = curve->splines();
|
||||
const IndexRange dst_point_range{task.start_indices.point, curves.points_size()};
|
||||
const IndexRange dst_curve_range{task.start_indices.curve, curves.curves_size()};
|
||||
|
||||
/* Initialize point attributes. */
|
||||
threading::parallel_for(src_splines.index_range(), 100, [&](const IndexRange src_spline_range) {
|
||||
for (const int src_spline_index : src_spline_range) {
|
||||
const int dst_spline_index = src_spline_index + task.start_spline_index;
|
||||
const Spline &src_spline = *src_splines[src_spline_index];
|
||||
SplinePtr dst_spline = src_spline.copy_without_attributes();
|
||||
dst_spline->transform(task.transform);
|
||||
const int spline_size = dst_spline->size();
|
||||
copy_transformed_positions(
|
||||
curves.positions(), task.transform, dst_curves.positions().slice(dst_point_range));
|
||||
|
||||
const CustomDataAttributes &src_point_attributes = src_spline.attributes;
|
||||
CustomDataAttributes &dst_point_attributes = dst_spline->attributes;
|
||||
|
||||
/* Create point ids. */
|
||||
if (all_curves_info.create_id_attribute) {
|
||||
dst_point_attributes.create("id", CD_PROP_INT32);
|
||||
MutableSpan<int> dst_point_ids = dst_point_attributes.get_for_write("id")->typed<int>();
|
||||
std::optional<GSpan> src_point_ids_opt = src_point_attributes.get_for_read("id");
|
||||
if (options.keep_original_ids) {
|
||||
if (src_point_ids_opt.has_value()) {
|
||||
const Span<int> src_point_ids = src_point_ids_opt->typed<int>();
|
||||
dst_point_ids.copy_from(src_point_ids);
|
||||
}
|
||||
else {
|
||||
dst_point_ids.fill(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (src_point_ids_opt.has_value()) {
|
||||
const Span<int> src_point_ids = src_point_ids_opt->typed<int>();
|
||||
for (const int i : IndexRange(dst_spline->size())) {
|
||||
dst_point_ids[i] = noise::hash(task.id, src_point_ids[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const int i : IndexRange(dst_spline->size())) {
|
||||
/* Mix spline index into the id, because otherwise points on different splines will
|
||||
* get the same id. */
|
||||
dst_point_ids[i] = noise::hash(task.id, src_spline_index, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy generic point attributes. */
|
||||
for (const int attribute_index : ordered_attributes.index_range()) {
|
||||
const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
|
||||
if (domain != ATTR_DOMAIN_POINT) {
|
||||
continue;
|
||||
}
|
||||
const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
|
||||
const CPPType &cpp_type = *custom_data_type_to_cpp_type(data_type);
|
||||
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
|
||||
const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
|
||||
const std::optional<GSpan> src_span_opt = src_point_attributes.get_for_read(attribute_id);
|
||||
void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), "Curve Attribute");
|
||||
if (src_span_opt.has_value()) {
|
||||
const GSpan src_span = *src_span_opt;
|
||||
cpp_type.copy_construct_n(src_span.data(), dst_buffer, spline_size);
|
||||
}
|
||||
else {
|
||||
if (attribute_fallback == nullptr) {
|
||||
attribute_fallback = cpp_type.default_value();
|
||||
}
|
||||
cpp_type.fill_construct_n(attribute_fallback, dst_buffer, spline_size);
|
||||
}
|
||||
dst_point_attributes.create_by_move(attribute_id, data_type, dst_buffer);
|
||||
}
|
||||
|
||||
dst_splines[dst_spline_index] = std::move(dst_spline);
|
||||
}
|
||||
});
|
||||
/* Initialize spline attributes. */
|
||||
for (const int attribute_index : ordered_attributes.index_range()) {
|
||||
const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
|
||||
if (domain != ATTR_DOMAIN_CURVE) {
|
||||
continue;
|
||||
}
|
||||
const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
|
||||
const CPPType &cpp_type = *custom_data_type_to_cpp_type(data_type);
|
||||
|
||||
GMutableSpan dst_span = dst_spline_attributes[attribute_index].slice(task.start_spline_index,
|
||||
src_splines.size());
|
||||
if (curve_info.spline_attributes[attribute_index].has_value()) {
|
||||
const GSpan src_span = *curve_info.spline_attributes[attribute_index];
|
||||
cpp_type.copy_construct_n(src_span.data(), dst_span.data(), src_splines.size());
|
||||
/* Copy and transform handle positions if necessary. */
|
||||
if (all_curves_info.create_handle_postion_attributes) {
|
||||
if (curves_info.handle_left.is_empty()) {
|
||||
all_handle_left.fill(float3(0));
|
||||
}
|
||||
else {
|
||||
const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
|
||||
if (attribute_fallback == nullptr) {
|
||||
attribute_fallback = cpp_type.default_value();
|
||||
}
|
||||
cpp_type.fill_construct_n(attribute_fallback, dst_span.data(), src_splines.size());
|
||||
copy_transformed_positions(
|
||||
curves_info.handle_left, task.transform, all_handle_left.slice(dst_point_range));
|
||||
}
|
||||
if (curves_info.handle_right.is_empty()) {
|
||||
all_handle_right.fill(float3(0));
|
||||
}
|
||||
else {
|
||||
copy_transformed_positions(
|
||||
curves_info.handle_right, task.transform, all_handle_right.slice(dst_point_range));
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy radius attribute with 1.0 default if it doesn't exist. */
|
||||
if (all_curves_info.create_radius_attribute) {
|
||||
if (curves_info.radius.is_empty()) {
|
||||
all_radii.slice(dst_point_range).fill(1.0f);
|
||||
}
|
||||
else {
|
||||
all_radii.slice(dst_point_range).copy_from(curves_info.radius);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy curve offsets. */
|
||||
const Span<int> src_offsets = curves.offsets();
|
||||
const MutableSpan<int> dst_offsets = dst_curves.offsets().slice(dst_curve_range);
|
||||
threading::parallel_for(curves.curves_range(), 2048, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
dst_offsets[i] = task.start_indices.point + src_offsets[i];
|
||||
}
|
||||
});
|
||||
|
||||
/* Create id attribute. */
|
||||
if (!all_dst_ids.is_empty()) {
|
||||
MutableSpan<int> dst_ids = all_dst_ids.slice(task.start_indices.point, curves.points_size());
|
||||
if (options.keep_original_ids) {
|
||||
if (curves_info.stored_ids.is_empty()) {
|
||||
dst_ids.fill(0);
|
||||
}
|
||||
else {
|
||||
dst_ids.copy_from(curves_info.stored_ids);
|
||||
}
|
||||
}
|
||||
else {
|
||||
threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange vert_range) {
|
||||
if (curves_info.stored_ids.is_empty()) {
|
||||
for (const int i : vert_range) {
|
||||
dst_ids[i] = noise::hash(task.id, i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const int i : vert_range) {
|
||||
const int original_id = curves_info.stored_ids[i];
|
||||
dst_ids[i] = noise::hash(task.id, original_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy generic attributes. */
|
||||
threading::parallel_for(
|
||||
dst_attribute_spans.index_range(), 10, [&](const IndexRange attribute_range) {
|
||||
for (const int attribute_index : attribute_range) {
|
||||
const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
|
||||
IndexRange element_slice;
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
element_slice = IndexRange(task.start_indices.point, curves.points_size());
|
||||
break;
|
||||
case ATTR_DOMAIN_CURVE:
|
||||
element_slice = IndexRange(task.start_indices.curve, curves.curves_size());
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
GMutableSpan dst_span = dst_attribute_spans[attribute_index].slice(element_slice);
|
||||
const CPPType &cpp_type = dst_span.type();
|
||||
const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
|
||||
if (curves_info.attributes[attribute_index].has_value()) {
|
||||
const GSpan src_span = *curves_info.attributes[attribute_index];
|
||||
threading::parallel_for(
|
||||
IndexRange(element_slice.size()), 1024, [&](const IndexRange sub_range) {
|
||||
cpp_type.copy_assign_n(src_span.slice(sub_range).data(),
|
||||
dst_span.slice(sub_range).data(),
|
||||
sub_range.size());
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (attribute_fallback == nullptr) {
|
||||
attribute_fallback = cpp_type.default_value();
|
||||
}
|
||||
threading::parallel_for(
|
||||
IndexRange(element_slice.size()), 1024, [&](const IndexRange sub_range) {
|
||||
cpp_type.fill_assign_n(
|
||||
attribute_fallback, dst_span.slice(sub_range).data(), sub_range.size());
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
||||
|
@ -1208,42 +1282,90 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
|||
|
||||
const RealizeCurveTask &last_task = tasks.last();
|
||||
const Curves &last_curves = *last_task.curve_info->curves;
|
||||
const int tot_splines = last_task.start_spline_index + last_curves.geometry.curve_size;
|
||||
const int points_size = last_task.start_indices.point + last_curves.geometry.point_size;
|
||||
const int curves_size = last_task.start_indices.curve + last_curves.geometry.curve_size;
|
||||
|
||||
Array<SplinePtr> dst_splines(tot_splines);
|
||||
/* Allocate new curves data-block. */
|
||||
Curves *dst_curves_id = bke::curves_new_nomain(points_size, curves_size);
|
||||
bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
|
||||
dst_curves.offsets().last() = points_size;
|
||||
CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
|
||||
dst_component.replace(dst_curves_id);
|
||||
|
||||
std::unique_ptr<CurveEval> dst_curve = std::make_unique<CurveEval>();
|
||||
dst_curve->attributes.reallocate(tot_splines);
|
||||
CustomDataAttributes &spline_attributes = dst_curve->attributes;
|
||||
/* Prepare id attribute. */
|
||||
OutputAttribute_Typed<int> point_ids;
|
||||
MutableSpan<int> point_ids_span;
|
||||
if (all_curves_info.create_id_attribute) {
|
||||
point_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
|
||||
point_ids_span = point_ids.as_span();
|
||||
}
|
||||
|
||||
/* Prepare spline attributes. */
|
||||
Vector<GMutableSpan> dst_spline_attributes;
|
||||
/* Prepare generic output attributes. */
|
||||
Vector<OutputAttribute> dst_attributes;
|
||||
Vector<GMutableSpan> dst_attribute_spans;
|
||||
for (const int attribute_index : ordered_attributes.index_range()) {
|
||||
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
|
||||
const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
|
||||
const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
|
||||
if (domain == ATTR_DOMAIN_CURVE) {
|
||||
spline_attributes.create(attribute_id, data_type);
|
||||
dst_spline_attributes.append(*spline_attributes.get_for_write(attribute_id));
|
||||
}
|
||||
else {
|
||||
dst_spline_attributes.append({CPPType::get<float>()});
|
||||
}
|
||||
const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
|
||||
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
|
||||
attribute_id, domain, data_type);
|
||||
dst_attribute_spans.append(dst_attribute.as_span());
|
||||
dst_attributes.append(std::move(dst_attribute));
|
||||
}
|
||||
|
||||
/* Prepare handle position attributes if necessary. */
|
||||
OutputAttribute_Typed<float3> handle_left;
|
||||
OutputAttribute_Typed<float3> handle_right;
|
||||
MutableSpan<float3> handle_left_span;
|
||||
MutableSpan<float3> handle_right_span;
|
||||
if (all_curves_info.create_handle_postion_attributes) {
|
||||
handle_left = dst_component.attribute_try_get_for_output_only<float3>("handle_left",
|
||||
ATTR_DOMAIN_POINT);
|
||||
handle_right = dst_component.attribute_try_get_for_output_only<float3>("handle_right",
|
||||
ATTR_DOMAIN_POINT);
|
||||
handle_left_span = handle_left.as_span();
|
||||
handle_right_span = handle_right.as_span();
|
||||
}
|
||||
|
||||
/* Prepare radius attribute if necessary. */
|
||||
OutputAttribute_Typed<float> radius;
|
||||
MutableSpan<float> radius_span;
|
||||
if (all_curves_info.create_radius_attribute) {
|
||||
radius = dst_component.attribute_try_get_for_output_only<float>("radius", ATTR_DOMAIN_POINT);
|
||||
radius_span = radius.as_span();
|
||||
}
|
||||
|
||||
/* Actually execute all tasks. */
|
||||
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
|
||||
for (const int task_index : task_range) {
|
||||
const RealizeCurveTask &task = tasks[task_index];
|
||||
execute_realize_curve_task(
|
||||
options, all_curves_info, task, ordered_attributes, dst_splines, dst_spline_attributes);
|
||||
execute_realize_curve_task(options,
|
||||
all_curves_info,
|
||||
task,
|
||||
ordered_attributes,
|
||||
dst_curves,
|
||||
dst_attribute_spans,
|
||||
point_ids_span,
|
||||
handle_left_span,
|
||||
handle_right_span,
|
||||
radius_span);
|
||||
}
|
||||
});
|
||||
|
||||
dst_curve->add_splines(dst_splines);
|
||||
|
||||
CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
|
||||
dst_component.replace(curve_eval_to_curves(*dst_curve));
|
||||
/* Save modified attributes. */
|
||||
for (OutputAttribute &dst_attribute : dst_attributes) {
|
||||
dst_attribute.save();
|
||||
}
|
||||
if (point_ids) {
|
||||
point_ids.save();
|
||||
}
|
||||
if (radius) {
|
||||
radius.save();
|
||||
}
|
||||
if (all_curves_info.create_handle_postion_attributes) {
|
||||
handle_left.save();
|
||||
handle_right.save();
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
Loading…
Reference in New Issue