Blender V4.3
extract_mesh_vbo_edge_fac.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_math_vector.hh"
10
11#include "GPU_capabilities.hh"
12
13#include "draw_subdivision.hh"
14#include "extract_mesh.hh"
15
16#define FORCE_HIDE 255
17namespace blender::draw {
18
21
22 /* Data that represents:
23 * - the index of the face of `corner_a` before the 2nd loop is found
24 * - the index of the next radial corner after the 2nd loop is found */
25 int data;
26};
27
32template<typename T> T edge_factor_calc(const float3 &a, const float3 &b);
33
34template<> inline float edge_factor_calc<float>(const float3 &a, const float3 &b)
35{
36 const float cosine = math::dot(a, b);
37
38 /* Re-scale to the slider range. */
39 float fac = (200 * (cosine - 1.0f)) + 1.0f;
40 CLAMP(fac, 0.0f, 1.0f);
41 /* 1.0 is a reserved value to force hide the wire. */
42 constexpr float factor = 254.0f / 255.0f;
43 return fac * factor;
44}
45
46template<> inline uint8_t edge_factor_calc<uint8_t>(const float3 &a, const float3 &b)
47{
48 const float cosine = math::dot(a, b);
49
50 /* Re-scale to the slider range. */
51 float fac = (200 * (cosine - 1.0f)) + 1.0f;
52 CLAMP(fac, 0.0f, 1.0f);
53 /* 255 is a reserved value to force hide the wire. */
54 return fac * 254;
55}
56
57template<typename T>
59{
60 const OffsetIndices faces = mr.faces;
61 const Span<int> corner_edges = mr.corner_edges;
62 const Span<float3> face_normals = mr.face_normals;
63 const BitSpan optimal_display_edges = mr.mesh->runtime->subsurf_optimal_display_edges;
64
65 Array<int8_t> edge_face_count(mr.edges_num, 0);
66 Array<MEdgeDataPrev> edge_data(mr.edges_num);
67
68 for (const int face : faces.index_range()) {
69 for (const int corner : faces[face]) {
70 const int edge = corner_edges[corner];
71 if (!optimal_display_edges.is_empty() && !optimal_display_edges[edge]) {
72 if constexpr (std::is_same_v<T, float>) {
73 vbo_data[corner] = 1.0f;
74 }
75 else {
76 vbo_data[corner] = FORCE_HIDE;
77 }
78 continue;
79 }
80
81 MEdgeDataPrev *medata = &edge_data[edge];
82
83 const int8_t face_count = edge_face_count[edge];
84 vbo_data[corner] = 0;
85 if (face_count < 4) {
86 if (face_count == 0) {
87 /* Prepare to calculate the factor. */
88 medata->corner_a = corner;
89 medata->data = face;
90 }
91 else if (face_count == 1) {
92 /* Calculate the factor for both corners. */
93 const int other_face = medata->data;
94 const T factor = edge_factor_calc<T>(face_normals[other_face], face_normals[face]);
95 vbo_data[medata->corner_a] = factor;
96 vbo_data[corner] = factor;
97
98 /* If the count still changes, use this `data` member to inform the corner. */
99 medata->data = corner;
100 }
101 else {
102 /* Non-manifold edge. Always visible. */
103 const int corner_a = medata->corner_a;
104 const int corner_b = medata->data;
105 vbo_data[corner_a] = 0;
106 vbo_data[corner_b] = 0;
107 }
108
109 edge_face_count[edge]++;
110 }
111 }
112 }
113}
114
115template<typename T>
117{
118 BMesh &bm = *mr.bm;
119 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
120 for (const int face_index : range) {
121 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
122 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
123 for ([[maybe_unused]] const int i : IndexRange(face.len)) {
124 const int index = BM_elem_index_get(loop);
125 if (BM_edge_is_manifold(loop->e)) {
126 const BMFace *other_face = loop->radial_next->f;
127 vbo_data[index] = edge_factor_calc<T>(float3(bm_face_no_get(mr, &face)),
128 float3(bm_face_no_get(mr, other_face)));
129 }
130 else {
131 vbo_data[index] = T(0);
132 }
133 loop = loop->next;
134 }
135 }
136 });
137}
138
140{
142 static GPUVertFormat format = {0};
143 if (format.attr_len == 0) {
145 }
148 MutableSpan vbo_data = vbo.data<float>();
149 if (mr.extract_type == MR_EXTRACT_MESH) {
150 extract_edge_factor_mesh(mr, vbo_data);
151 }
152 else {
153 extract_edge_factor_bm(mr, vbo_data);
154 }
155 vbo_data.take_back(mr.loose_indices_num).fill(0.0f);
156 }
157 else {
158 static GPUVertFormat format = {0};
159 if (format.attr_len == 0) {
161 }
164 MutableSpan vbo_data = vbo.data<uint8_t>();
165 if (mr.extract_type == MR_EXTRACT_MESH) {
166 extract_edge_factor_mesh(mr, vbo_data);
167 }
168 else {
169 extract_edge_factor_bm(mr, vbo_data);
170 }
171 vbo_data.take_back(mr.loose_indices_num).fill(uint8_t(0));
172 }
173}
174
175/* Different function than the one used for the non-subdivision case, as we directly take care of
176 * the buggy AMD driver case. */
178{
179 static GPUVertFormat format = {0};
180 if (format.attr_len == 0) {
183 }
184 else {
186 }
187 }
188 return format;
189}
190
192{
194
195 static GPUVertFormat format = {0};
196 if (format.attr_len == 0) {
198 }
199
201 GPU_vertbuf_data_alloc(*vbo, subdiv_cache.num_subdiv_loops);
202 MutableSpan vbo_data = vbo->data<int>();
203
204 Array<MEdgeDataPrev> edge_data(subdiv_cache.num_subdiv_edges);
205 Array<int> tmp_edge_corner_count(subdiv_cache.num_subdiv_edges, 0);
206 int *subdiv_loop_subdiv_edge_index = subdiv_cache.subdiv_loop_subdiv_edge_index;
207
208 for (int corner : IndexRange(subdiv_cache.num_subdiv_loops)) {
209 const int edge = subdiv_loop_subdiv_edge_index[corner];
210 const int quad = corner / 4;
211 const int corner_count = tmp_edge_corner_count[edge]++;
212
213 vbo_data[corner] = -1;
214 if (corner_count == 0) {
215 edge_data[edge].corner_a = corner;
216 edge_data[edge].data = quad;
217 }
218 else if (corner_count == 1) {
219 const int corner_a = edge_data[edge].corner_a;
220 const int quad_a = edge_data[edge].data;
221 vbo_data[corner_a] = quad;
222 vbo_data[corner] = quad_a;
223 edge_data[edge].data = corner;
224 }
225 else if (corner_count == 2) {
226 const int corner_a = edge_data[edge].corner_a;
227 const int corner_b = edge_data[edge].data;
228 vbo_data[corner_a] = -1;
229 vbo_data[corner_b] = -1;
230 }
231 }
232
233 return vbo;
234}
235
237 const MeshRenderData &mr,
238 gpu::VertBuf &pos_nor,
239 gpu::VertBuf &vbo)
240{
243 subdiv_cache.num_subdiv_loops +
244 subdiv_loose_edges_num(mr, subdiv_cache) * 2);
245
246 if (mr.faces_num > 0) {
247 gpu::VertBuf *poly_other_map = build_poly_other_map_vbo(subdiv_cache);
248
250 subdiv_cache, &pos_nor, subdiv_cache.edges_draw_flag, poly_other_map, &vbo);
251
252 GPU_vertbuf_discard(poly_other_map);
253 }
254
255 const int loose_edges_num = subdiv_loose_edges_num(mr, subdiv_cache);
256 if (loose_edges_num == 0) {
257 return;
258 }
259
260 /* Make sure buffer is active for sending loose data. */
261 GPU_vertbuf_use(&vbo);
262
263 const int offset = subdiv_cache.num_subdiv_loops;
265 const float values[2] = {1.0f, 1.0f};
266 for (const int i : IndexRange(loose_edges_num)) {
267 GPU_vertbuf_update_sub(&vbo, (offset + i * 2) * sizeof(float), sizeof(values), values);
268 }
269 }
270 else {
271 const uint8_t values[2] = {255, 255};
272 for (const int i : IndexRange(loose_edges_num)) {
273 GPU_vertbuf_update_sub(&vbo, (offset + i * 2) * sizeof(uint8_t), sizeof(values), values);
274 }
275 }
276}
277
278} // namespace blender::draw
#define CLAMP(a, b, c)
int GPU_minimum_per_vertex_stride()
bool GPU_crappy_amd_driver()
void GPU_vertbuf_init_build_on_device(blender::gpu::VertBuf &verts, const GPUVertFormat &format, uint v_len)
void GPU_vertbuf_use(blender::gpu::VertBuf *)
#define GPU_vertbuf_init_with_format(verts, format)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_update_sub(blender::gpu::VertBuf *verts, uint start, uint len, const void *data)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_I32
@ GPU_COMP_U8
ATTR_WARN_UNUSED_RESULT BMesh * bm
constexpr MutableSpan take_back(const int64_t n) const
Definition BLI_span.hh:641
constexpr T * data() const
Definition BLI_span.hh:540
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
MutableSpan< T > data()
local_group_size(16, 16) .push_constant(Type b
Extraction of Mesh data into VBO to feed to GPU.
#define FORCE_HIDE
blender::gpu::Batch * quad
format
void extract_edge_factor_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBuf &pos_nor, gpu::VertBuf &vbo)
int subdiv_loose_edges_num(const MeshRenderData &mr, const DRWSubdivCache &cache)
void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache &cache, gpu::VertBuf *pos_nor, gpu::VertBuf *edge_draw_flag, gpu::VertBuf *poly_other_map, gpu::VertBuf *edge_fac)
T edge_factor_calc(const float3 &a, const float3 &b)
void extract_edge_factor(const MeshRenderData &mr, gpu::VertBuf &vbo)
float edge_factor_calc< float >(const float3 &a, const float3 &b)
uint8_t edge_factor_calc< uint8_t >(const float3 &a, const float3 &b)
static void extract_edge_factor_mesh(const MeshRenderData &mr, MutableSpan< T > vbo_data)
static void extract_edge_factor_bm(const MeshRenderData &mr, MutableSpan< T > vbo_data)
static const GPUVertFormat & get_subdiv_edge_fac_format()
static gpu::VertBuf * build_poly_other_map_vbo(const DRWSubdivCache &subdiv_cache)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
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
unsigned char uint8_t
Definition stdint.h:78
signed char int8_t
Definition stdint.h:75
int totface
MeshRuntimeHandle * runtime
OffsetIndices< int > faces