Blender V5.0
extract_mesh_vbo_lnor.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_array_utils.hh"
10
12
13#include "extract_mesh.hh"
14
15#include "draw_subdivision.hh"
16
17namespace blender::draw {
18
19template<typename GPUType>
20static void extract_vert_normals(const Span<int> corner_verts,
21 const Span<float3> vert_normals,
23{
24 Array<GPUType> vert_normals_converted(vert_normals.size());
25 gpu::convert_normals(vert_normals, vert_normals_converted.as_mutable_span());
26 array_utils::gather(vert_normals_converted.as_span(), corner_verts, normals);
27}
28
29template<typename GPUType>
31{
32 const OffsetIndices faces = mr.faces;
33 const Span<float3> face_normals = mr.face_normals;
34 threading::parallel_for(faces.index_range(), 4096, [&](const IndexRange range) {
35 for (const int face : range) {
36 normals.slice(faces[face]).fill(gpu::convert_normal<GPUType>(face_normals[face]));
37 }
38 });
39}
40
41template<typename GPUType>
43{
44 const auto get_vert_normals = [&]() {
45 return mr.use_simplify_normals ? mr.mesh->vert_normals_true() : mr.mesh->vert_normals();
46 };
49 }
51 extract_vert_normals(mr.corner_verts, get_vert_normals(), normals);
52 }
53 else if (!mr.corner_normals.is_empty()) {
55 }
56 else if (mr.sharp_faces.is_empty()) {
57 extract_vert_normals(mr.corner_verts, get_vert_normals(), normals);
58 }
59 else {
60 const OffsetIndices faces = mr.faces;
61 const Span<int> corner_verts = mr.corner_verts;
62 const Span<bool> sharp_faces = mr.sharp_faces;
63 const Span<float3> vert_normals = get_vert_normals();
64 const Span<float3> face_normals = mr.face_normals;
65 threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
66 for (const int face : range) {
67 if (sharp_faces[face]) {
68 normals.slice(faces[face]).fill(gpu::convert_normal<GPUType>(face_normals[face]));
69 }
70 else {
71 for (const int corner : faces[face]) {
72 normals[corner] = gpu::convert_normal<GPUType>(vert_normals[corner_verts[corner]]);
73 }
74 }
75 }
76 });
77 }
78}
79
80template<typename GPUType>
82{
83 const BMesh &bm = *mr.bm;
84 if (mr.bm_free_normal_offset_vert != -1) {
85 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
86 for (const int face_index : range) {
87 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
88 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
89 const IndexRange face_range(BM_elem_index_get(loop), face.len);
90 for (const int corner : face_range) {
91 normals[corner] = gpu::convert_normal<GPUType>(
92 BM_ELEM_CD_GET_FLOAT_P(loop->v, mr.bm_free_normal_offset_vert));
93 loop = loop->next;
94 }
95 }
96 });
97 }
98 else if (!mr.bm_vert_normals.is_empty()) {
99 Array<GPUType> vert_normals_converted(mr.bm_vert_normals.size());
100 gpu::convert_normals(mr.bm_vert_normals, vert_normals_converted.as_mutable_span());
101 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
102 for (const int face_index : range) {
103 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
104 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
105 const IndexRange face_range(BM_elem_index_get(loop), face.len);
106 for (const int corner : face_range) {
107 normals[corner] = vert_normals_converted[BM_elem_index_get(loop->v)];
108 loop = loop->next;
109 }
110 }
111 });
112 }
113 else {
114 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
115 for (const int face_index : range) {
116 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
117 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
118 const IndexRange face_range(BM_elem_index_get(loop), face.len);
119 for (const int corner : face_range) {
120 normals[corner] = gpu::convert_normal<GPUType>(loop->v->no);
121 loop = loop->next;
122 }
123 }
124 });
125 }
126}
127
128template<typename GPUType>
130{
131 const BMesh &bm = *mr.bm;
132 if (mr.bm_free_normal_offset_face != -1) {
133 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
134 for (const int face_index : range) {
135 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
136 const IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
137 normals.slice(face_range)
138 .fill(gpu::convert_normal<GPUType>(
139 BM_ELEM_CD_GET_FLOAT_P(&face, mr.bm_free_normal_offset_face)));
140 }
141 });
142 }
143 else if (!mr.bm_face_normals.is_empty()) {
144 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
145 for (const int face_index : range) {
146 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
147 const IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
148 normals.slice(face_range)
149 .fill(gpu::convert_normal<GPUType>(mr.bm_face_normals[face_index]));
150 }
151 });
152 }
153 else {
154 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
155 for (const int face_index : range) {
156 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
157 const IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
158 normals.slice(face_range).fill(gpu::convert_normal<GPUType>(face.no));
159 }
160 });
161 }
162}
163
164template<typename GPUType>
166{
167 const BMesh &bm = *mr.bm;
170 }
173 }
174 else if (mr.bm_free_normal_offset_corner != -1) {
175 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
176 for (const int face_index : range) {
177 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
178 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
179 const IndexRange face_range(BM_elem_index_get(loop), face.len);
180 for (const int corner : face_range) {
181 normals[corner] = gpu::convert_normal<GPUType>(
182 BM_ELEM_CD_GET_FLOAT_P(loop, mr.bm_free_normal_offset_corner));
183 loop = loop->next;
184 }
185 }
186 });
187 }
188 else if (!mr.bm_loop_normals.is_empty()) {
189 gpu::convert_normals(mr.bm_loop_normals, normals);
190 }
191 else {
192 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
193 for (const int face_index : range) {
194 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
195 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
196 const IndexRange face_range(BM_elem_index_get(loop), face.len);
197
198 if (!BM_elem_flag_test(&face, BM_ELEM_SMOOTH)) {
199 if (!mr.bm_face_normals.is_empty()) {
200 normals.slice(face_range)
201 .fill(gpu::convert_normal<GPUType>(mr.bm_face_normals[face_index]));
202 }
203 else {
204 normals.slice(face_range).fill(gpu::convert_normal<GPUType>(face.no));
205 }
206 }
207 else {
208 if (!mr.bm_vert_normals.is_empty()) {
209 for (const int corner : face_range) {
210 normals[corner] = gpu::convert_normal<GPUType>(
211 mr.bm_vert_normals[BM_elem_index_get(loop->v)]);
212 loop = loop->next;
213 }
214 }
215 else {
216 for (const int corner : face_range) {
217 normals[corner] = gpu::convert_normal<GPUType>(loop->v->no);
218 loop = loop->next;
219 }
220 }
221 }
222 }
223 });
224 }
225}
226
227gpu::VertBufPtr extract_normals(const MeshRenderData &mr, const bool use_hq)
228{
229 const int size = mr.corners_num + mr.loose_indices_num;
230 if (use_hq) {
231 static const GPUVertFormat format = []() {
233 GPU_vertformat_attr_add(&format, "nor", gpu::VertAttrType::SNORM_16_16_16_16);
236 return format;
237 }();
240 MutableSpan vbo_data = vbo->data<short4>();
241 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
242 MutableSpan loose_data = vbo_data.take_back(mr.loose_indices_num);
243
245 extract_normals_mesh(mr, corners_data);
246 }
247 else {
248 extract_normals_bm(mr, corners_data);
249 }
250
251 loose_data.fill(short4(0));
252 return vbo;
253 }
254 static const GPUVertFormat format = []() {
256 GPU_vertformat_attr_add(&format, "nor", gpu::VertAttrType::SNORM_10_10_10_2);
259 return format;
260 }();
263 MutableSpan vbo_data = vbo->data<gpu::PackedNormal>();
264 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
265 MutableSpan loose_data = vbo_data.take_back(mr.loose_indices_num);
266
268 extract_normals_mesh(mr, corners_data);
269 }
270 else {
271 extract_normals_bm(mr, corners_data);
272 }
273
274 loose_data.fill(gpu::PackedNormal{});
275 return vbo;
276}
277
279{
280 static const GPUVertFormat format = []() {
282 GPU_vertformat_attr_add(&format, "nor", gpu::VertAttrType::SFLOAT_32_32_32);
285 return format;
286 }();
287 return format;
288}
289
291 const DRWSubdivCache &subdiv_cache,
292 gpu::VertBuf &lnor)
293{
294 const int vbo_size = subdiv_full_vbo_size(mr, subdiv_cache);
295 const int loose_geom_start = subdiv_cache.num_subdiv_loops;
296
297 /* Push VBO content to the GPU and bind the VBO so that #GPU_vertbuf_update_sub can work. */
298 GPU_vertbuf_use(&lnor);
299
300 /* Default to zeroed attribute. The overlay shader should expect this and render engines should
301 * never draw loose geometry. */
302 const float3 default_normal(0.0f, 0.0f, 0.0f);
303 for (const int i : IndexRange::from_begin_end(loose_geom_start, vbo_size)) {
304 /* TODO(fclem): This has HORRENDOUS performance. Prefer clearing the buffer on device with
305 * something like glClearBufferSubData. */
306 GPU_vertbuf_update_sub(&lnor, i * sizeof(float3), sizeof(float3), &default_normal);
307 }
308}
309
311 const DRWSubdivCache &subdiv_cache,
313{
314 const int vbo_size = subdiv_full_vbo_size(mr, subdiv_cache);
315
318 if (subdiv_cache.num_subdiv_loops == 0) {
319 update_loose_normals(mr, subdiv_cache, *lnor);
320 return lnor;
321 }
322
323 if (subdiv_cache.use_custom_loop_normals) {
324 const Mesh *coarse_mesh = subdiv_cache.mesh;
325 static GPUVertFormat src_normals_format = GPU_vertformat_from_attribute(
326 "vnor", gpu::VertAttrType::SFLOAT_32_32_32);
328 GPU_vertbuf_data_alloc(*src, coarse_mesh->corners_num);
329 src->data<float3>().copy_from(coarse_mesh->corner_normals());
330 draw_subdiv_interp_corner_normals(subdiv_cache, *src, *lnor);
331
332 update_loose_normals(mr, subdiv_cache, *lnor);
333 return lnor;
334 }
335
337 subdiv_cache.subdiv_loop_subdiv_vert_index, subdiv_cache.num_subdiv_loops));
338
339 /* Calculate vertex normals (stored here per subdivided vertex rather than per subdivided face
340 * corner). The values are used for smooth shaded faces later. */
341 static GPUVertFormat vert_normals_format = GPU_vertformat_from_attribute(
342 "vnor", gpu::VertAttrType::SFLOAT_32_32_32);
343 gpu::VertBufPtr vert_normals = gpu::VertBufPtr(
344 GPU_vertbuf_create_on_device(vert_normals_format, subdiv_cache.num_subdiv_verts));
346 &pos,
348 subdiv_cache.subdiv_vertex_face_adjacency,
349 subdiv_corner_verts.get(),
350 vert_normals.get());
351
352 /* Compute final normals for face corners, either using the vertex normal corresponding to the
353 * corner, or by calculating the face normal.
354 *
355 * TODO: Avoid using face normals or vertex normals if possible, using `mr.normals_domain`. */
357 subdiv_cache, &pos, vert_normals.get(), subdiv_corner_verts.get(), lnor.get());
358
359 update_loose_normals(mr, subdiv_cache, *lnor);
360
361 return lnor;
362}
363
364} // namespace blender::draw
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)
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_vertformat_alias_add(GPUVertFormat *, blender::StringRef alias)
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, blender::gpu::VertAttrType type)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
BMesh * bm
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr bool is_empty() const
Definition BLI_span.hh:260
Span< T > as_span() const
Definition BLI_array.hh:243
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
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
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:629
constexpr int64_t size() const
Definition BLI_span.hh:252
Extraction of Mesh data into VBO to feed to GPU.
static float normals[][3]
uint pos
VecBase< short, 4 > short4
format
static char faces[256]
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
static void extract_face_normals_bm(const MeshRenderData &mr, MutableSpan< GPUType > normals)
gpu::VertBufPtr extract_vert_normals(const MeshRenderData &mr)
void draw_subdiv_build_lnor_buffer(const DRWSubdivCache &cache, gpu::VertBuf *pos, gpu::VertBuf *vert_normals, gpu::VertBuf *subdiv_corner_verts, gpu::VertBuf *lnor)
void draw_subdiv_interp_corner_normals(const DRWSubdivCache &cache, gpu::VertBuf &src_data, gpu::VertBuf &dst_data)
static void extract_vert_normals_bm(const MeshRenderData &mr, MutableSpan< GPUType > normals)
gpu::VertBufPtr extract_normals(const MeshRenderData &mr, bool use_hq)
int subdiv_full_vbo_size(const MeshRenderData &mr, const DRWSubdivCache &cache)
static void extract_normals_mesh(const MeshRenderData &mr, MutableSpan< GPUType > normals)
static void update_loose_normals(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, gpu::VertBuf &lnor)
static void extract_normals_bm(const MeshRenderData &mr, MutableSpan< GPUType > normals)
static const GPUVertFormat & get_normals_format()
gpu::VertBuf * draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops)
gpu::VertBufPtr extract_normals_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, gpu::VertBuf &pos)
static void extract_face_normals(const MeshRenderData &mr, MutableSpan< GPUType > normals)
void draw_subdiv_accumulate_normals(const DRWSubdivCache &cache, gpu::VertBuf *pos, gpu::VertBuf *face_adjacency_offsets, gpu::VertBuf *face_adjacency_lists, gpu::VertBuf *vertex_loop_map, gpu::VertBuf *vert_normals)
void convert_normals(Span< float3 > src, MutableSpan< GPUType > dst)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
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
blender::VecBase< int16_t, 4 > short4
VecBase< float, 3 > float3
int corners_num
gpu::VertBuf * subdiv_vertex_face_adjacency_offsets
VArraySpan< bool > sharp_faces
OffsetIndices< int > faces
bke::MeshNormalDomain normals_domain
i
Definition text_draw.cc:230