Blender V4.3
mesh_tessellate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14#include "BLI_array_utils.hh"
16#include "BLI_math_geom.h"
17#include "BLI_math_matrix.h"
18#include "BLI_math_vector.h"
19#include "BLI_memarena.h"
20#include "BLI_polyfill_2d.h"
21#include "BLI_task.hh"
22
23#include "BKE_mesh.hh"
24
25#include "BLI_strict_flags.h" /* Keep last. */
26
27namespace blender::bke::mesh {
28
29/* -------------------------------------------------------------------- */
39 const Span<float3> positions,
40 const int face_start,
41 const int face_size,
42 int3 *tri,
43 MemArena **pf_arena_p,
44 const bool face_normal,
45 const float normal_precalc[3])
46{
47 auto create_tri = [&](int i1, int i2, int i3) {
48 (*tri)[0] = face_start + i1;
49 (*tri)[1] = face_start + i2;
50 (*tri)[2] = face_start + i3;
51 };
52
53 switch (face_size) {
54 case 3: {
55 create_tri(0, 1, 2);
56 break;
57 }
58 case 4: {
59 create_tri(0, 1, 2);
60 int3 *tri_a = tri++;
61 create_tri(0, 2, 3);
62 int3 *tri_b = tri;
63 if (UNLIKELY(is_quad_flip_v3_first_third_fast(positions[corner_verts[(*tri_a)[0]]],
64 positions[corner_verts[(*tri_a)[1]]],
65 positions[corner_verts[(*tri_a)[2]]],
66 positions[corner_verts[(*tri_b)[2]]])))
67 {
68 /* Flip out of degenerate 0-2 state. */
69 (*tri_a)[2] = (*tri_b)[2];
70 (*tri_b)[0] = (*tri_a)[1];
71 }
72 break;
73 }
74 default: {
75 float axis_mat[3][3];
76
77 /* Calculate `axis_mat` to project verts to 2D. */
78 if (face_normal == false) {
79 float normal[3];
80 const float *co_curr, *co_prev;
81
82 zero_v3(normal);
83
84 /* Calc normal, flipped: to get a positive 2D cross product. */
85 co_prev = positions[corner_verts[face_start + face_size - 1]];
86 for (int j = 0; j < face_size; j++) {
87 co_curr = positions[corner_verts[face_start + j]];
88 add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
89 co_prev = co_curr;
90 }
91 if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
92 normal[2] = 1.0f;
93 }
94 axis_dominant_v3_to_m3_negate(axis_mat, normal);
95 }
96 else {
97 axis_dominant_v3_to_m3_negate(axis_mat, normal_precalc);
98 }
99
100 const int totfilltri = face_size - 2;
101
102 MemArena *pf_arena = *pf_arena_p;
103 if (UNLIKELY(pf_arena == nullptr)) {
104 pf_arena = *pf_arena_p = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
105 }
106
107 uint(*tris)[3] = static_cast<uint(*)[3]>(
108 BLI_memarena_alloc(pf_arena, sizeof(*tris) * size_t(totfilltri)));
109 float(*projverts)[2] = static_cast<float(*)[2]>(
110 BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(face_size)));
111
112 for (int j = 0; j < face_size; j++) {
113 mul_v2_m3v3(projverts[j], axis_mat, positions[corner_verts[face_start + j]]);
114 }
115
116 BLI_polyfill_calc_arena(projverts, uint(face_size), 1, tris, pf_arena);
117
118 /* Apply fill. */
119 for (int j = 0; j < totfilltri; j++, tri++) {
120 create_tri(int(tris[j][0]), int(tris[j][1]), int(tris[j][2]));
121 }
122
123 BLI_memarena_clear(pf_arena);
124
125 break;
126 }
127 }
128}
129
130static void mesh_calc_tessellation_for_face(const Span<int> corner_verts,
131 const Span<float3> positions,
132 const int face_start,
133 const int face_size,
134 int3 *tri,
135 MemArena **pf_arena_p)
136{
138 corner_verts, positions, face_start, face_size, tri, pf_arena_p, false, nullptr);
139}
140
142 const Span<float3> positions,
143 const int face_start,
144 const int face_size,
145 int3 *tri,
146 MemArena **pf_arena_p,
147 const float normal_precalc[3])
148{
150 corner_verts, positions, face_start, face_size, tri, pf_arena_p, true, normal_precalc);
151}
152
153struct LocalData {
154 MemArena *pf_arena = nullptr;
155
157 {
158 if (pf_arena) {
160 }
161 }
162};
163
164static void corner_tris_calc_impl(const Span<float3> positions,
165 const OffsetIndices<int> faces,
166 const Span<int> corner_verts,
167 const Span<float3> face_normals,
168 MutableSpan<int3> corner_tris)
169{
171 if (face_normals.is_empty()) {
172 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
173 LocalData &local_data = all_local_data.local();
174 for (const int64_t i : range) {
175 const int face_start = int(faces[i].start());
176 const int face_size = int(faces[i].size());
177 const int tris_start = poly_to_tri_count(int(i), face_start);
178 mesh_calc_tessellation_for_face(corner_verts,
179 positions,
180 face_start,
181 face_size,
182 &corner_tris[tris_start],
183 &local_data.pf_arena);
184 }
185 });
186 }
187 else {
188 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
189 LocalData &local_data = all_local_data.local();
190 for (const int64_t i : range) {
191 const int face_start = int(faces[i].start());
192 const int face_size = int(faces[i].size());
193 const int tris_start = poly_to_tri_count(int(i), face_start);
194 mesh_calc_tessellation_for_face_with_normal(corner_verts,
195 positions,
196 face_start,
197 face_size,
198 &corner_tris[tris_start],
199 &local_data.pf_arena,
200 face_normals[i]);
201 }
202 });
203 }
204}
205
206void corner_tris_calc(const Span<float3> vert_positions,
207 const OffsetIndices<int> faces,
208 const Span<int> corner_verts,
209 MutableSpan<int3> corner_tris)
210{
211 corner_tris_calc_impl(vert_positions, faces, corner_verts, {}, corner_tris);
212}
213
215{
216 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
217 for (const int64_t i : range) {
218 const IndexRange face = faces[i];
219 const int start = poly_to_tri_count(int(i), int(face.start()));
220 const int num = face_triangles_num(int(face.size()));
221 tri_faces.slice(start, num).fill(int(i));
222 }
223 });
224}
225
227 const OffsetIndices<int> faces,
228 const Span<int> corner_verts,
229 const Span<float3> face_normals,
230 MutableSpan<int3> corner_tris)
231{
232 BLI_assert(!face_normals.is_empty() || faces.is_empty());
233 corner_tris_calc_impl(vert_positions, faces, corner_verts, face_normals, corner_tris);
234}
235
238void vert_tris_from_corner_tris(const Span<int> corner_verts,
239 const Span<int3> corner_tris,
240 MutableSpan<int3> vert_tris)
241{
242 array_utils::gather(corner_verts, corner_tris.cast<int>(), vert_tris.cast<int>());
243}
244
245int3 corner_tri_get_real_edges(const Span<int2> edges,
246 const Span<int> corner_verts,
247 const Span<int> corner_edges,
248 const int3 &corner_tri)
249{
250 int3 real_edges;
251 for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
252 const int corner_1 = int(corner_tri[i]);
253 const int corner_2 = int(corner_tri[i_next]);
254 const int vert_1 = corner_verts[corner_1];
255 const int vert_2 = corner_verts[corner_2];
256 const int edge_i = corner_edges[corner_1];
257 const int2 edge = edges[edge_i];
258
259 const bool is_real = (vert_1 == edge[0] && vert_2 == edge[1]) ||
260 (vert_1 == edge[1] && vert_2 == edge[0]);
261
262 real_edges[i] = is_real ? edge_i : -1;
263 }
264 return real_edges;
265}
266
267} // namespace blender::bke::mesh
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
bool is_quad_flip_v3_first_third_fast(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v3(float n[3])
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
void void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
void BLI_polyfill_calc_arena(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3], struct MemArena *arena)
unsigned int uint
#define UNLIKELY(x)
constexpr MutableSpan< NewT > cast() const
Definition BLI_span.hh:736
Span< NewT > constexpr cast() const
Definition BLI_span.hh:419
constexpr bool is_empty() const
Definition BLI_span.hh:261
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span< int > corner_verts, const Span< float3 > positions, const int face_start, const int face_size, int3 *tri, MemArena **pf_arena_p, const bool face_normal, const float normal_precalc[3])
void corner_tris_calc(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, MutableSpan< int3 > corner_tris)
static void corner_tris_calc_impl(const Span< float3 > positions, const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< float3 > face_normals, MutableSpan< int3 > corner_tris)
static void mesh_calc_tessellation_for_face_with_normal(const Span< int > corner_verts, const Span< float3 > positions, const int face_start, const int face_size, int3 *tri, MemArena **pf_arena_p, const float normal_precalc[3])
void vert_tris_from_corner_tris(Span< int > corner_verts, Span< int3 > corner_tris, MutableSpan< int3 > vert_tris)
void corner_tris_calc_with_normals(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< float3 > face_normals, MutableSpan< int3 > corner_tris)
void corner_tris_calc_face_indices(OffsetIndices< int > faces, MutableSpan< int > tri_faces)
static void mesh_calc_tessellation_for_face(const Span< int > corner_verts, const Span< float3 > positions, const int face_start, const int face_size, int3 *tri, MemArena **pf_arena_p)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95