Blender V5.0
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
8
9#include "BLI_math_vector.hh"
10
11#include "GPU_capabilities.hh"
12
13#include "draw_subdivision.hh"
14#include "extract_mesh.hh"
15
16namespace blender::draw {
17
20
21 /* Data that represents:
22 * - the index of the face of `corner_a` before the 2nd loop is found
23 * - the index of the next radial corner after the 2nd loop is found */
24 int data;
25};
26
31
32inline float edge_factor_calc(const float3 &a, const float3 &b)
33{
34 const float cosine = math::dot(a, b);
35
36 /* Re-scale to the slider range. */
37 float fac = (200 * (cosine - 1.0f)) + 1.0f;
38 CLAMP(fac, 0.0f, 1.0f);
39 /* 1.0 is a reserved value to force hide the wire. */
40 constexpr float factor = 254.0f / 255.0f;
41 return fac * factor;
42}
43
45{
46 const OffsetIndices faces = mr.faces;
47 const Span<int> corner_edges = mr.corner_edges;
48 const Span<float3> face_normals = mr.face_normals;
49 const BitSpan optimal_display_edges = mr.mesh->runtime->subsurf_optimal_display_edges;
50
51 Array<int8_t> edge_face_count(mr.edges_num, 0);
52 Array<MEdgeDataPrev> edge_data(mr.edges_num);
53
54 for (const int face : faces.index_range()) {
55 for (const int corner : faces[face]) {
56 const int edge = corner_edges[corner];
57 if (!optimal_display_edges.is_empty() && !optimal_display_edges[edge]) {
58 vbo_data[corner] = 1.0f;
59 continue;
60 }
61
62 MEdgeDataPrev *medata = &edge_data[edge];
63
64 const int8_t face_count = edge_face_count[edge];
65 vbo_data[corner] = 0;
66 if (face_count < 4) {
67 if (face_count == 0) {
68 /* Prepare to calculate the factor. */
69 medata->corner_a = corner;
70 medata->data = face;
71 }
72 else if (face_count == 1) {
73 /* Calculate the factor for both corners. */
74 const int other_face = medata->data;
75 const float factor = edge_factor_calc(face_normals[other_face], face_normals[face]);
76 vbo_data[medata->corner_a] = factor;
77 vbo_data[corner] = factor;
78
79 /* If the count still changes, use this `data` member to inform the corner. */
80 medata->data = corner;
81 }
82 else {
83 /* Non-manifold edge. Always visible. */
84 const int corner_a = medata->corner_a;
85 const int corner_b = medata->data;
86 vbo_data[corner_a] = 0;
87 vbo_data[corner_b] = 0;
88 }
89
90 edge_face_count[edge]++;
91 }
92 }
93 }
94}
95
97{
98 BMesh &bm = *mr.bm;
99 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
100 for (const int face_index : range) {
101 const BMFace &face = *BM_face_at_index(&bm, face_index);
102 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
103 for ([[maybe_unused]] const int i : IndexRange(face.len)) {
104 const int index = BM_elem_index_get(loop);
105 if (BM_edge_is_manifold(loop->e)) {
106 const BMFace *other_face = loop->radial_next->f;
107 vbo_data[index] = edge_factor_calc(float3(bm_face_no_get(mr, &face)),
108 float3(bm_face_no_get(mr, other_face)));
109 }
110 else {
111 vbo_data[index] = 0.0f;
112 }
113 loop = loop->next;
114 }
115 }
116 });
117}
118
120{
122 gpu::VertAttrType::SFLOAT_32);
125 MutableSpan vbo_data = vbo->data<float>();
127 extract_edge_factor_mesh(mr, vbo_data);
128 }
129 else {
130 extract_edge_factor_bm(mr, vbo_data);
131 }
132 vbo_data.take_back(mr.loose_indices_num).fill(0.0f);
133 return vbo;
134}
135
137{
139
140 static const GPUVertFormat format = GPU_vertformat_from_attribute("poly_other",
141 gpu::VertAttrType::SINT_32);
142
144 GPU_vertbuf_data_alloc(*vbo, subdiv_cache.num_subdiv_loops);
145 MutableSpan vbo_data = vbo->data<int>();
146
147 Array<MEdgeDataPrev> edge_data(subdiv_cache.num_subdiv_edges);
148 Array<int> tmp_edge_corner_count(subdiv_cache.num_subdiv_edges, 0);
149 int *subdiv_loop_subdiv_edge_index = subdiv_cache.subdiv_loop_subdiv_edge_index;
150
151 for (int corner : IndexRange(subdiv_cache.num_subdiv_loops)) {
152 const int edge = subdiv_loop_subdiv_edge_index[corner];
153 const int quad = corner / 4;
154 const int corner_count = tmp_edge_corner_count[edge]++;
155
156 vbo_data[corner] = -1;
157 if (corner_count == 0) {
158 edge_data[edge].corner_a = corner;
159 edge_data[edge].data = quad;
160 }
161 else if (corner_count == 1) {
162 const int corner_a = edge_data[edge].corner_a;
163 const int quad_a = edge_data[edge].data;
164 vbo_data[corner_a] = quad;
165 vbo_data[corner] = quad_a;
166 edge_data[edge].data = corner;
167 }
168 else if (corner_count == 2) {
169 const int corner_a = edge_data[edge].corner_a;
170 const int corner_b = edge_data[edge].data;
171 vbo_data[corner_a] = -1;
172 vbo_data[corner_b] = -1;
173 }
174 }
175
176 return vbo;
177}
178
180 const MeshRenderData &mr,
181 gpu::VertBuf &pos_nor)
182{
184 GPU_vertformat_from_attribute("wd", gpu::VertAttrType::SFLOAT_32),
185 subdiv_cache.num_subdiv_loops + subdiv_loose_edges_num(mr, subdiv_cache) * 2));
186
187 if (mr.faces_num > 0) {
188 gpu::VertBuf *poly_other_map = build_poly_other_map_vbo(subdiv_cache);
189
191 subdiv_cache, &pos_nor, subdiv_cache.edges_draw_flag, poly_other_map, vbo.get());
192
193 GPU_vertbuf_discard(poly_other_map);
194 }
195
196 const int loose_edges_num = subdiv_loose_edges_num(mr, subdiv_cache);
197 if (loose_edges_num == 0) {
198 return vbo;
199 }
200
201 /* Make sure buffer is active for sending loose data. */
202 GPU_vertbuf_use(vbo.get());
203
204 const int offset = subdiv_cache.num_subdiv_loops;
205 const float values[2] = {1.0f, 1.0f};
206 for (const int i : IndexRange(loose_edges_num)) {
207 GPU_vertbuf_update_sub(vbo.get(), (offset + i * 2) * sizeof(float), sizeof(values), values);
208 }
209 return vbo;
210}
211
212} // namespace blender::draw
#define CLAMP(a, b, c)
blender::gpu::VertBuf * GPU_vertbuf_create_on_device(const GPUVertFormat &format, uint v_len)
void GPU_vertbuf_use(blender::gpu::VertBuf *)
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
#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 *)
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, blender::gpu::VertAttrType type)
BMesh * bm
constexpr MutableSpan take_back(const int64_t n) const
Definition BLI_span.hh:640
constexpr T * data() const
Definition BLI_span.hh:539
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
MutableSpan< T > data()
Extraction of Mesh data into VBO to feed to GPU.
blender::gpu::Batch * quad
format
static char faces[256]
float edge_factor_calc(const float3 &a, const float3 &b)
void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache &cache, gpu::VertBuf *pos, gpu::VertBuf *edge_draw_flag, gpu::VertBuf *poly_other_map, gpu::VertBuf *edge_fac)
int subdiv_loose_edges_num(const MeshRenderData &mr, const DRWSubdivCache &cache)
static void extract_edge_factor_mesh(const MeshRenderData &mr, MutableSpan< float > vbo_data)
gpu::VertBufPtr extract_edge_factor_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBuf &pos)
static void extract_edge_factor_bm(const MeshRenderData &mr, MutableSpan< float > vbo_data)
gpu::VertBufPtr extract_edge_factor(const MeshRenderData &mr)
static gpu::VertBuf * build_poly_other_map_vbo(const DRWSubdivCache &subdiv_cache)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
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:93
VecBase< float, 3 > float3
MeshRuntimeHandle * runtime
OffsetIndices< int > faces
i
Definition text_draw.cc:230