[Bf-blender-cvs] [6c6f591f909] master: Curves: Port realize instances node to the new data-block

Hans Goudey noreply at git.blender.org
Wed Mar 9 16:58:21 CET 2022


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. @@



More information about the Bf-blender-cvs mailing list