Commit: 6c6f591f909a02967daff87ab348601953f61670 Author: Hans Goudey Date: Wed Mar 9 09:56:14 2022 -0600 Branches: master https://developer.blender.org/rB6c6f591f909a02967daff87ab348601953f61670
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 =================================================================== M source/blender/geometry/intern/realize_instances.cc =================================================================== diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 4f7024eea82..c2337c37d1f 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -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 Span<SplinePtr> src_splines = curve->splines(); - - /* 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(); - - 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_ @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
