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
49 lines
1.3 KiB
C++
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
|