Files
test2/source/blender/geometry/GEO_mesh_triangulate.hh
Hans Goudey ea875f6f32 Geometry Nodes: Port triangulate node from BMesh to Mesh
Add a Mesh implementation of triangulation, which is currently just
implemented for BMesh. The main benefit of this is performance and
decreased memory usage. The benefit is especially large because the
node currently converts to BMesh, triangulates, and then converts back.
But the BMesh implementation is entirely single threaded, so it will
always be much slower.

The new implementation uses the principle of "never just process a
single element at a time" but it also tries to avoid processing _too_
many elements at once, to decrease the size of temporary buffers.
Practically that means the work is organized into chunks of selected
faces, but within each chunk, each task is done in a separate loop.
Arguably I went a bit far with some optimizations, and some of the
complexity isn't necessary, but I hope everything is clear anyway.

Unlike some other Mesh ports like the extrude node or the split edges
code, this generates a new mesh. I still go back and forth on that
aspect, but reusing the same mesh would have required reallocating
face attributes from scratch anyway. Implicit sharing is used to
avoid copying vertex attributes though.

The result mesh is reorganized a bit. Unselected face data comes first,
then selected triangles, then triangulated NGons, then triangulated
quads. This makes attribute interpolation and internal calculations
more efficient.

The "Minimum Vertices" socket is replaced with versioning. In the new
implementation it would have an impact on code complexity, and for a
builtin "atomic" node it makes more sense as part of the selection.

The performance difference depends on the number of CPU threads, the
number of attributes, and the selection size. As all of those numbers
go up, the benefit will grow. The "modes" also affect the performance,
obviously.

With a Ryzen 7950x, I tested performance in a few situations (in ms):
|                            | Selection | Before | After | Change |
| -------------------------- | --------- | ------ | ----- | ------ |
| 1.4 m quads (fixed)        | 50%       | 1533   | 15.9  | 96x    |
| 10 m quads (shortest)      | 100%      | 9700   | 165.0 | 59x    |
| 1 m 10-side Ngons (beauty) | 90%       | 3785   | 115.9 | 33x    |
| 1 m quads many attributes  | 100%      | 54600  | 332.3 | 164x   |

In follow-up commits, I'll move other areas to use mesh triangulation
instead of BMesh. This is the last geometry node using BMesh besides
the Ico Sphere primitive.

Pull Request: https://projects.blender.org/blender/blender/pulls/112264
2024-11-23 00:25:52 +01:00

49 lines
1.3 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <optional>
#include "BLI_index_mask.hh"
#include "BKE_attribute.hh"
struct Mesh;
namespace blender::geometry {
/** \warning Values are saved in files. */
enum class TriangulateNGonMode {
/** Add a "beauty" pass on top of the standard ear-clipping algorithm. */
Beauty = 0,
EarClip = 1,
};
/** \warning Values are saved in files. */
enum class TriangulateQuadMode {
/** Complex method to determine the best looking edge. */
Beauty = 0,
/** Create a new edge from the first corner to the last. */
Fixed = 1,
/** Create a new edge from the second corner to the third. */
Alternate = 2,
/** Create a new edge along the shortest diagonal. */
ShortEdge = 3,
/** Create a new edge along the longest diagonal. */
LongEdge = 4,
};
/**
* \return #std::nullopt if the mesh is not changed (when every selected face is already a
* triangle).
*/
std::optional<Mesh *> mesh_triangulate(const Mesh &src_mesh,
const IndexMask &selection,
TriangulateNGonMode ngon_mode,
TriangulateQuadMode quad_mode,
const bke::AttributeFilter &attribute_filter);
} // namespace blender::geometry