Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-03-08 04:06:40 +0300
committerHans Goudey <h.goudey@me.com>2022-03-08 04:06:40 +0300
commit901a03725ed58166e5b2401dfadd7c1cb7e490a2 (patch)
treeace4bc1b2a7dd9135aa5b0291d3d1bda2a46e1b7 /source/blender
parentc238728105272b0f11ff5b03a701cc180bf68bb8 (diff)
Curves: Port mesh to curve node to new data-block
The main improvement is a code simplification, because attributes don't have to be transferred separately for each curve, and all attributes can be handled generically. Performance improves significantly when the output contains many curves. Basic testing with a 2 million curve output shows an approximate 10x performance improvement.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/geometry/GEO_mesh_to_curve.hh6
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc152
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc3
4 files changed, 56 insertions, 111 deletions
diff --git a/source/blender/geometry/GEO_mesh_to_curve.hh b/source/blender/geometry/GEO_mesh_to_curve.hh
index a99ee9c7fee..c480e4178cf 100644
--- a/source/blender/geometry/GEO_mesh_to_curve.hh
+++ b/source/blender/geometry/GEO_mesh_to_curve.hh
@@ -2,11 +2,10 @@
#include "BLI_index_mask.hh"
-#include "BKE_spline.hh"
-
#pragma once
struct Mesh;
+struct Curves;
class MeshComponent;
/** \file
@@ -20,7 +19,6 @@ namespace blender::geometry {
* intersections of more than three edges will become breaks in splines. Attributes that
* are not built-in on meshes and not curves are transferred to the result curve.
*/
-std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
- const IndexMask selection);
+Curves *mesh_to_curve_convert(const MeshComponent &mesh_component, const IndexMask selection);
} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 121a1b5de39..0c2377fde6d 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -2,7 +2,6 @@
#include "BLI_array.hh"
#include "BLI_set.hh"
-#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "DNA_mesh_types.h"
@@ -10,85 +9,48 @@
#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
-#include "BKE_spline.hh"
#include "GEO_mesh_to_curve.hh"
namespace blender::geometry {
template<typename T>
-static void copy_attribute_to_points(const VArray<T> &source_data,
- Span<int> map,
- MutableSpan<T> dest_data)
+static void copy_with_map(const VArray<T> &src, Span<int> map, MutableSpan<T> dst)
{
- for (const int point_index : map.index_range()) {
- const int vert_index = map[point_index];
- dest_data[point_index] = source_data[vert_index];
- }
+ devirtualize_varray(src, [&](const auto &src) {
+ threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int vert_index = map[i];
+ dst[i] = src[vert_index];
+ }
+ });
+ });
}
-static std::unique_ptr<CurveEval> create_curve_from_vert_indices(
- const MeshComponent &mesh_component, Span<Vector<int>> vert_indices, IndexRange cyclic_splines)
+static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_component,
+ const Span<int> vert_indices,
+ const Span<int> curve_offsets,
+ const IndexRange cyclic_splines)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- curve->resize(vert_indices.size());
-
- MutableSpan<SplinePtr> splines = curve->splines();
+ Curves *curves_id = bke::curves_new_nomain(vert_indices.size(), curve_offsets.size());
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ curves.offsets().drop_back(1).copy_from(curve_offsets);
+ curves.offsets().last() = vert_indices.size();
+ curves.curve_types().fill(CURVE_TYPE_POLY);
- for (const int i : vert_indices.index_range()) {
- splines[i] = std::make_unique<PolySpline>();
- splines[i]->resize(vert_indices[i].size());
- }
- for (const int i : cyclic_splines) {
- splines[i]->set_cyclic(true);
- }
+ curves.cyclic().fill(false);
+ curves.cyclic().slice(cyclic_splines).fill(true);
Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
- /* Copy builtin control point attributes. */
- if (source_attribute_ids.contains("tilt")) {
- const VArray<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
- "tilt", ATTR_DOMAIN_POINT, 0.0f);
- threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
- for (const int i : range) {
- copy_attribute_to_points<float>(tilt_attribute, vert_indices[i], splines[i]->tilts());
- }
- });
- source_attribute_ids.remove_contained("tilt");
- }
- else {
- for (SplinePtr &spline : splines) {
- spline->tilts().fill(0.0f);
- }
- }
-
- if (source_attribute_ids.contains("radius")) {
- const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
- "radius", ATTR_DOMAIN_POINT, 1.0f);
- threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
- for (const int i : range) {
- copy_attribute_to_points<float>(radius_attribute, vert_indices[i], splines[i]->radii());
- }
- });
- source_attribute_ids.remove_contained("radius");
- }
- else {
- for (SplinePtr &spline : splines) {
- spline->radii().fill(1.0f);
- }
- }
-
- VArray<float3> mesh_positions = mesh_component.attribute_get_for_read(
- "position", ATTR_DOMAIN_POINT, float3(0));
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- copy_attribute_to_points(mesh_positions, vert_indices[i], splines[i]->positions());
- }
- });
+ CurveComponent curves_component;
+ curves_component.replace(curves_id, GeometryOwnershipType::Editable);
for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) {
- if (mesh_component.attribute_is_builtin(attribute_id)) {
+ if (mesh_component.attribute_is_builtin(attribute_id) &&
+ !curves_component.attribute_is_builtin(attribute_id)) {
/* Don't copy attributes that are built-in on meshes but not on curves. */
continue;
}
@@ -105,33 +67,24 @@ static std::unique_ptr<CurveEval> create_curve_from_vert_indices(
continue;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute.type());
-
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- /* Create attribute on the spline points. */
- splines[i]->attributes.create(attribute_id, data_type);
- std::optional<fn::GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(
- attribute_id);
- BLI_assert(spline_attribute);
-
- /* Copy attribute based on the map for this spline. */
- attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_attribute_to_points<T>(
- mesh_attribute.typed<T>(), vert_indices[i], spline_attribute->typed<T>());
- });
- }
+ /* Copy attribute based on the map for this spline. */
+ attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ bke::OutputAttribute_Typed<T> attribute =
+ curves_component.attribute_try_get_for_output_only<T>(attribute_id, ATTR_DOMAIN_POINT);
+ copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.as_span());
+ attribute.save();
});
}
- curve->assert_valid_point_attributes();
- return curve;
+ return curves_id;
}
struct CurveFromEdgesOutput {
/** The indices in the mesh for each control point of each result splines. */
- Vector<Vector<int>> vert_indices;
+ Vector<int> vert_indices;
+ /** The first index of each curve in the result. */
+ Vector<int> curve_offsets;
/** A subset of splines that should be set cyclic. */
IndexRange cyclic_splines;
};
@@ -139,7 +92,9 @@ struct CurveFromEdgesOutput {
static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
Span<std::pair<int, int>> edges)
{
- Vector<Vector<int>> vert_indices;
+ Vector<int> vert_indices;
+ vert_indices.reserve(edges.size());
+ Vector<int> curve_offsets;
/* Compute the number of edges connecting to each vertex. */
Array<int> neighbor_count(verts.size(), 0);
@@ -191,15 +146,16 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
continue;
}
- Vector<int> spline_indices;
- spline_indices.append(current_vert);
+ /* Start a new curve in the output. */
+ curve_offsets.append(vert_indices.size());
+ vert_indices.append(current_vert);
/* Follow connected edges until we read a vertex with more than two connected edges. */
while (true) {
int last_vert = current_vert;
current_vert = next_vert;
- spline_indices.append(current_vert);
+ vert_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@@ -212,13 +168,11 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
const int next_b = neighbors[offset + 1];
next_vert = (last_vert == next_a) ? next_b : next_a;
}
-
- vert_indices.append(std::move(spline_indices));
}
}
/* All splines added after this are cyclic. */
- const int cyclic_start = vert_indices.size();
+ const int cyclic_start = curve_offsets.size();
/* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
for (const int start_vert : verts.index_range()) {
@@ -229,16 +183,15 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
int current_vert = start_vert;
int next_vert = neighbors[neighbor_offsets[current_vert]];
- Vector<int> spline_indices;
-
- spline_indices.append(current_vert);
+ curve_offsets.append(vert_indices.size());
+ vert_indices.append(current_vert);
/* Follow connected edges until we loop back to the start vertex. */
while (next_vert != start_vert) {
const int last_vert = current_vert;
current_vert = next_vert;
- spline_indices.append(current_vert);
+ vert_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@@ -247,13 +200,11 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
const int next_b = neighbors[offset + 1];
next_vert = (last_vert == next_a) ? next_b : next_a;
}
-
- vert_indices.append(std::move(spline_indices));
}
- const int final_size = vert_indices.size();
+ const IndexRange cyclic_curves = curve_offsets.index_range().drop_front(cyclic_start);
- return {std::move(vert_indices), IndexRange(cyclic_start, final_size - cyclic_start)};
+ return {std::move(vert_indices), std::move(curve_offsets), cyclic_curves};
}
/**
@@ -270,8 +221,7 @@ static Vector<std::pair<int, int>> get_selected_edges(const Mesh &mesh, const In
return selected_edges;
}
-std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
- const IndexMask selection)
+Curves *mesh_to_curve_convert(const MeshComponent &mesh_component, const IndexMask selection)
{
const Mesh &mesh = *mesh_component.get_for_read();
Vector<std::pair<int, int>> selected_edges = get_selected_edges(*mesh_component.get_for_read(),
@@ -280,7 +230,7 @@ std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_compo
selected_edges);
return create_curve_from_vert_indices(
- mesh_component, output.vert_indices, output.cyclic_splines);
+ mesh_component, output.vert_indices, output.curve_offsets, output.cyclic_splines);
}
} // namespace blender::geometry
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
index 8991261a21a..72cb540df4a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
@@ -45,10 +45,8 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(
- component, IndexMask(selected_edge_indices));
-
- params.set_output("Curve", GeometrySet::create_with_curves(curve_eval_to_curves(*curve)));
+ Curves *curves = geometry::mesh_to_curve_convert(component, IndexMask(selected_edge_indices));
+ params.set_output("Curve", GeometrySet::create_with_curves(curves));
}
} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index d2b824141d7..f6ee3d00dee 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -34,8 +34,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(component, selection);
- geometry_set.replace_curves(curve_eval_to_curves(*curve));
+ geometry_set.replace_curves(geometry::mesh_to_curve_convert(component, selection));
geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
});