Blender V4.3
extract_mesh_ibo_lines_adjacency.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_map.hh"
10#include "BLI_ordered_edge.hh"
11#include "BLI_vector.hh"
12
13#include "BKE_editmesh.hh"
14
15#include "GPU_index_buffer.hh"
16
17#include "draw_subdivision.hh"
18#include "extract_mesh.hh"
19
20namespace blender::draw {
21
22#define NO_EDGE INT_MAX
23
25 Map<OrderedEdge, int> &edge_hash,
27 bool &is_manifold)
28{
29 for (const auto item : edge_hash.items()) {
30 int v_data = item.value;
31 if (v_data == NO_EDGE) {
32 continue;
33 }
34
35 int v2 = item.key.v_low;
36 int v3 = item.key.v_high;
37
38 int l1 = uint(abs(v_data)) - 1;
39 if (v_data < 0) { /* `inv_opposite`. */
40 std::swap(v2, v3);
41 }
42 int l2 = vert_to_corner[v2];
43 int l3 = vert_to_corner[v3];
44 GPU_indexbuf_add_line_adj_verts(&elb, l1, l2, l3, l1);
45 is_manifold = false;
46 }
47}
48
49inline void rotate_vector(uint3 &value)
50{
51 const uint tmp = value[0];
52 value[0] = value[2];
53 value[2] = value[1];
54 value[1] = tmp;
55}
56
58inline void lines_adjacency_triangle(uint3 vert_tri,
59 uint3 corner_tri,
60 MutableSpan<int> vert_to_corner,
61 Map<OrderedEdge, int> &edge_hash,
63 bool &is_manifold)
64{
65 /* Iterate around the triangle's edges. */
66 for (int e = 0; e < 3; e++) {
67 rotate_vector(vert_tri);
68 rotate_vector(corner_tri);
69
70 bool inv_indices = (vert_tri[1] > vert_tri[2]);
71 edge_hash.add_or_modify(
72 {vert_tri[1], vert_tri[2]},
73 [&](int *value) {
74 int new_value = int(corner_tri[0]) + 1; /* 0 cannot be signed so add one. */
75 *value = inv_indices ? -new_value : new_value;
76 /* Store loop indices for remaining non-manifold edges. */
77 vert_to_corner[vert_tri[1]] = corner_tri[1];
78 vert_to_corner[vert_tri[2]] = corner_tri[2];
79 },
80 [&](int *value) {
81 int v_data = *value;
82 if (v_data == NO_EDGE) {
83 int new_value = int(corner_tri[0]) + 1; /* 0 cannot be signed so add one. */
84 *value = inv_indices ? -new_value : new_value;
85 /* Store loop indices for remaining non-manifold edges. */
86 vert_to_corner[vert_tri[1]] = corner_tri[1];
87 vert_to_corner[vert_tri[2]] = corner_tri[2];
88 }
89 else {
90 /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
91 *value = NO_EDGE;
92 bool inv_opposite = (v_data < 0);
93 const int corner_opposite = abs(v_data) - 1;
94 /* TODO: Make this part thread-safe. */
95 if (inv_opposite == inv_indices) {
96 /* Don't share edge if triangles have non matching winding. */
98 &elb, corner_tri[0], corner_tri[1], corner_tri[2], corner_tri[0]);
100 &elb, corner_opposite, corner_tri[1], corner_tri[2], corner_opposite);
101 is_manifold = false;
102 }
103 else {
105 &elb, corner_tri[0], corner_tri[1], corner_tri[2], corner_opposite);
106 }
107 }
108 });
109 }
110}
111
112static void calc_adjacency_bm(const MeshRenderData &mr,
113 MutableSpan<int> vert_to_corner,
114 Map<OrderedEdge, int> &edge_hash,
116 bool &is_manifold)
117{
119 for (const int i : looptris.index_range()) {
120 const std::array<BMLoop *, 3> &tri = looptris[i];
121 if (BM_elem_flag_test(tri[0]->f, BM_ELEM_HIDDEN)) {
122 continue;
123 }
125 uint3(BM_elem_index_get(tri[0]->v),
126 BM_elem_index_get(tri[1]->v),
127 BM_elem_index_get(tri[2]->v)),
129 vert_to_corner,
130 edge_hash,
131 elb,
132 is_manifold);
133 }
134}
135
137 MutableSpan<int> vert_to_corner,
138 Map<OrderedEdge, int> &edge_hash,
140 bool &is_manifold)
141{
142 const OffsetIndices faces = mr.faces;
143 const Span<int> corner_verts = mr.corner_verts;
144 const Span<bool> hide_poly = mr.hide_poly;
145 const Span<int3> corner_tris = mr.mesh->corner_tris();
146 for (const int face : faces.index_range()) {
147 if (!hide_poly.is_empty() && hide_poly[face]) {
148 continue;
149 }
150 const IndexRange tris = bke::mesh::face_triangles_range(faces, face);
151 for (const int3 &tri : corner_tris.slice(tris)) {
153 uint3(corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]),
154 uint3(tri),
155 vert_to_corner,
156 edge_hash,
157 elb,
158 is_manifold);
159 }
160 }
161}
162
163void extract_lines_adjacency(const MeshRenderData &mr, gpu::IndexBuf &ibo, bool &r_is_manifold)
164{
165 /* Similar to poly_to_tri_count().
166 * There is always (loop + triangle - 1) edges inside a face.
167 * Accumulate for all faces and you get : */
168 const int tess_edge_len = mr.corners_num + mr.corner_tris_num - mr.faces_num;
169 Map<OrderedEdge, int> edge_hash;
170 edge_hash.reserve(tess_edge_len);
171 Array<int> vert_to_corner(mr.verts_num, 0);
172 bool is_manifold = true;
173
174 GPUIndexBufBuilder builder;
175 GPU_indexbuf_init(&builder, GPU_PRIM_LINES_ADJ, tess_edge_len, mr.corners_num);
176
177 if (mr.extract_type == MR_EXTRACT_MESH) {
178 calc_adjacency_mesh(mr, vert_to_corner, edge_hash, builder, is_manifold);
179 }
180 else {
181 calc_adjacency_bm(mr, vert_to_corner, edge_hash, builder, is_manifold);
182 }
183
184 create_lines_for_remaining_edges(vert_to_corner, edge_hash, builder, is_manifold);
185
186 r_is_manifold = is_manifold;
187
188 GPU_indexbuf_build_in_place(&builder, &ibo);
189}
190
192 gpu::IndexBuf &ibo,
193 bool &r_is_manifold)
194{
195 /* For each face there is (loop + triangle - 1) edges. Since we only have quads, and a quad
196 * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in
197 * total: (number_of_loops + number_of_quads). */
198 const uint tess_edge_len = subdiv_cache.num_subdiv_loops + subdiv_cache.num_subdiv_quads;
199
200 Array<int> vert_to_corner(subdiv_cache.num_subdiv_verts, 0);
201 Map<OrderedEdge, int> edge_hash;
202 edge_hash.reserve(tess_edge_len);
203
204 bool is_manifold = true;
205
206 GPUIndexBufBuilder builder;
207 GPU_indexbuf_init(&builder, GPU_PRIM_LINES_ADJ, tess_edge_len, subdiv_cache.num_subdiv_loops);
208
209 for (const int subdiv_quad_index : IndexRange(subdiv_cache.num_subdiv_quads)) {
210 const uint loop_index = subdiv_quad_index * 4;
211 const uint corner_0 = loop_index + 0;
212 const uint corner_1 = loop_index + 1;
213 const uint corner_2 = loop_index + 2;
214 const uint corner_3 = loop_index + 3;
215
216 const uint vert_0 = subdiv_cache.subdiv_loop_subdiv_vert_index[corner_0];
217 const uint vert_1 = subdiv_cache.subdiv_loop_subdiv_vert_index[corner_1];
218 const uint vert_2 = subdiv_cache.subdiv_loop_subdiv_vert_index[corner_2];
219 const uint vert_3 = subdiv_cache.subdiv_loop_subdiv_vert_index[corner_3];
220
221 lines_adjacency_triangle({vert_0, vert_1, vert_2},
222 {corner_0, corner_1, corner_2},
223 vert_to_corner,
224 edge_hash,
225 builder,
226 is_manifold);
227 lines_adjacency_triangle({vert_0, vert_2, vert_3},
228 {corner_0, corner_2, corner_3},
229 vert_to_corner,
230 edge_hash,
231 builder,
232 is_manifold);
233 }
234
235 create_lines_for_remaining_edges(vert_to_corner, edge_hash, builder, is_manifold);
236
237 r_is_manifold = is_manifold;
238
239 GPU_indexbuf_build_in_place(&builder, &ibo);
240}
241
242#undef NO_EDGE
243
244} // namespace blender::draw
unsigned int uint
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, blender::gpu::IndexBuf *)
void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3, uint v4)
@ GPU_PRIM_LINES_ADJ
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
ItemIterator items() const
Definition BLI_map.hh:864
void reserve(int64_t n)
Definition BLI_map.hh:979
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:457
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
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
Extraction of Mesh data into VBO to feed to GPU.
IndexRange face_triangles_range(OffsetIndices< int > faces, int face_i)
Definition BKE_mesh.hh:296
void extract_lines_adjacency_subdiv(const DRWSubdivCache &subdiv_cache, gpu::IndexBuf &ibo, bool &r_is_manifold)
static void calc_adjacency_mesh(const MeshRenderData &mr, MutableSpan< int > vert_to_corner, Map< OrderedEdge, int > &edge_hash, GPUIndexBufBuilder &elb, bool &is_manifold)
void lines_adjacency_triangle(uint3 vert_tri, uint3 corner_tri, MutableSpan< int > vert_to_corner, Map< OrderedEdge, int > &edge_hash, GPUIndexBufBuilder &elb, bool &is_manifold)
static void calc_adjacency_bm(const MeshRenderData &mr, MutableSpan< int > vert_to_corner, Map< OrderedEdge, int > &edge_hash, GPUIndexBufBuilder &elb, bool &is_manifold)
static void create_lines_for_remaining_edges(MutableSpan< int > vert_to_corner, Map< OrderedEdge, int > &edge_hash, GPUIndexBufBuilder &elb, bool &is_manifold)
void extract_lines_adjacency(const MeshRenderData &mr, gpu::IndexBuf &ibo, bool &r_is_manifold)
T abs(const T &a)
VecBase< uint32_t, 3 > uint3
blender::Array< std::array< BMLoop *, 3 > > looptris
OffsetIndices< int > faces