Blender V4.3
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
9#include "BLI_array_utils.hh"
10
11#include "extract_mesh.hh"
12
13#include "draw_subdivision.hh"
14
15namespace blender::draw {
16
17template<typename GPUType>
19{
20 threading::parallel_for(src.index_range(), 2048, [&](const IndexRange range) {
21 for (const int i : range) {
22 dst[i] = convert_normal<GPUType>(src[i]);
23 }
24 });
25}
26
28{
29 convert_normals_impl(src, normals);
30}
31template<> void convert_normals(const Span<float3> src, MutableSpan<short4> normals)
32{
33 convert_normals_impl(src, normals);
34}
35
36template<typename GPUType>
37static void extract_vert_normals(const Span<int> corner_verts,
38 const Span<float3> vert_normals,
40{
41 Array<GPUType> vert_normals_converted(vert_normals.size());
42 convert_normals(vert_normals, vert_normals_converted.as_mutable_span());
43 array_utils::gather(vert_normals_converted.as_span(), corner_verts, normals);
44}
45
46template<typename GPUType>
48{
49 const OffsetIndices faces = mr.faces;
50 const Span<float3> face_normals = mr.face_normals;
51 threading::parallel_for(faces.index_range(), 4096, [&](const IndexRange range) {
52 for (const int face : range) {
53 normals.slice(faces[face]).fill(convert_normal<GPUType>(face_normals[face]));
54 }
55 });
56}
57
58template<typename GPUType>
60{
61 if (mr.normals_domain == bke::MeshNormalDomain::Face) {
62 extract_face_normals(mr, normals);
63 }
64 else if (mr.normals_domain == bke::MeshNormalDomain::Point) {
65 extract_vert_normals(mr.corner_verts, mr.mesh->vert_normals(), normals);
66 }
67 else if (!mr.corner_normals.is_empty()) {
69 }
70 else if (mr.sharp_faces.is_empty()) {
71 extract_vert_normals(mr.corner_verts, mr.mesh->vert_normals(), normals);
72 }
73 else {
74 const OffsetIndices faces = mr.faces;
75 const Span<int> corner_verts = mr.corner_verts;
76 const Span<bool> sharp_faces = mr.sharp_faces;
77 const Span<float3> vert_normals = mr.mesh->vert_normals();
78 const Span<float3> face_normals = mr.face_normals;
79 threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
80 for (const int face : range) {
81 if (sharp_faces[face]) {
82 normals.slice(faces[face]).fill(convert_normal<GPUType>(face_normals[face]));
83 }
84 else {
85 for (const int corner : faces[face]) {
86 normals[corner] = convert_normal<GPUType>(vert_normals[corner_verts[corner]]);
87 }
88 }
89 }
90 });
91 }
92}
93
94template<typename GPUType>
96{
97 const bool use_face_select = (mr.mesh->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
100 selection = mr.select_poly;
101 }
102 else if (mr.mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
103 selection = mr.select_vert;
104 }
105 if (selection.is_empty() && mr.hide_poly.is_empty() && (!mr.edit_bmesh || !mr.orig_index_vert)) {
106 return;
107 }
108 const OffsetIndices faces = mr.faces;
109 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
110 if (!selection.is_empty()) {
111 if (use_face_select) {
112 for (const int face : range) {
113 if (selection[face]) {
114 for (const int corner : faces[face]) {
115 normals[corner].w = 1;
116 }
117 }
118 }
119 }
120 else {
121 const Span<int> corner_verts = mr.corner_verts;
122 for (const int face : range) {
123 for (const int corner : faces[face]) {
124 if (selection[corner_verts[corner]]) {
125 normals[corner].w = 1;
126 }
127 }
128 }
129 }
130 }
131 if (!mr.hide_poly.is_empty()) {
132 const Span<bool> hide_poly = mr.hide_poly;
133 for (const int face : range) {
134 if (hide_poly[face]) {
135 for (const int corner : faces[face]) {
136 normals[corner].w = -1;
137 }
138 }
139 }
140 }
141 if (mr.edit_bmesh && mr.orig_index_vert) {
142 const Span<int> corner_verts = mr.corner_verts;
143 const Span<int> orig_indices(mr.orig_index_vert, mr.verts_num);
144 for (const int face : range) {
145 for (const int corner : faces[face]) {
146 if (orig_indices[corner_verts[corner]] == ORIGINDEX_NONE) {
147 normals[corner].w = -1;
148 }
149 }
150 }
151 }
152 });
153}
154
155template<typename GPUType>
157{
158 const BMesh &bm = *mr.bm;
159 if (!mr.bm_loop_normals.is_empty()) {
160 convert_normals(mr.bm_loop_normals, normals);
161 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
162 for (const int face_index : range) {
163 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
164 if (BM_elem_flag_test(&face, BM_ELEM_HIDDEN)) {
165 const IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
166 for (GPUType &value : normals.slice(face_range)) {
167 value.w = -1;
168 }
169 }
170 }
171 });
172 }
173 else {
174 const bke::MeshNormalDomain domain = mr.normals_domain;
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
181 if (domain == bke::MeshNormalDomain::Face || !BM_elem_flag_test(&face, BM_ELEM_SMOOTH)) {
182 normals.slice(face_range).fill(convert_normal<GPUType>(bm_face_no_get(mr, &face)));
183 }
184 else {
185 for ([[maybe_unused]] const int i : IndexRange(face.len)) {
186 const int index = BM_elem_index_get(loop);
187 normals[index] = convert_normal<GPUType>(bm_vert_no_get(mr, loop->v));
188 loop = loop->next;
189 }
190 }
191
192 if (BM_elem_flag_test(&face, BM_ELEM_HIDDEN)) {
193 for (GPUType &value : normals.slice(face_range)) {
194 value.w = -1;
195 }
196 }
197 }
198 });
199 }
200}
201
202void extract_normals(const MeshRenderData &mr, const bool use_hq, gpu::VertBuf &vbo)
203{
204 const int size = mr.corners_num + mr.loose_indices_num;
205 if (use_hq) {
206 static GPUVertFormat format = {0};
207 if (format.attr_len == 0) {
210 }
212 GPU_vertbuf_data_alloc(vbo, size);
213 MutableSpan vbo_data = vbo.data<short4>();
214 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
215 MutableSpan loose_data = vbo_data.take_back(mr.loose_indices_num);
216
217 if (mr.extract_type == MR_EXTRACT_MESH) {
218 extract_normals_mesh(mr, corners_data);
219 extract_paint_overlay_flags(mr, corners_data);
220 }
221 else {
222 extract_normals_bm(mr, corners_data);
223 }
224
225 loose_data.fill(short4(0));
226 }
227 else {
228 static GPUVertFormat format = {0};
229 if (format.attr_len == 0) {
232 }
234 GPU_vertbuf_data_alloc(vbo, size);
235 MutableSpan vbo_data = vbo.data<GPUPackedNormal>();
236 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
237 MutableSpan loose_data = vbo_data.take_back(mr.loose_indices_num);
238
239 if (mr.extract_type == MR_EXTRACT_MESH) {
240 extract_normals_mesh(mr, corners_data);
241 extract_paint_overlay_flags(mr, corners_data);
242 }
243 else {
244 extract_normals_bm(mr, corners_data);
245 }
246
247 loose_data.fill(GPUPackedNormal{});
248 }
249}
250
252{
253 static GPUVertFormat format = {0};
254 if (format.attr_len == 0) {
258 }
259 return format;
260}
261
263 const DRWSubdivCache &subdiv_cache,
264 gpu::VertBuf &pos_nor,
265 gpu::VertBuf &lnor)
266{
267 const int vbo_size = subdiv_full_vbo_size(mr, subdiv_cache);
268 const int loose_geom_start = subdiv_cache.num_subdiv_loops;
269
271 draw_subdiv_build_lnor_buffer(subdiv_cache, &pos_nor, &lnor);
272
273 /* Push VBO content to the GPU and bind the VBO so that #GPU_vertbuf_update_sub can work. */
274 GPU_vertbuf_use(&lnor);
275
276 /* Default to zeroed attribute. The overlay shader should expect this and render engines should
277 * never draw loose geometry. */
278 const float4 default_normal(0.0f, 0.0f, 0.0f, 0.0f);
279 for (const int i : IndexRange::from_begin_end(loose_geom_start, vbo_size)) {
280 /* TODO(fclem): This has HORRENDOUS performance. Prefer clearing the buffer on device with
281 * something like glClearBufferSubData. */
282 GPU_vertbuf_update_sub(&lnor, i * sizeof(float4), sizeof(float4), &default_normal);
283 }
284}
285} // namespace blender::draw
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
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)
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)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias)
@ GPU_COMP_I10
@ GPU_COMP_F32
@ GPU_COMP_I16
ATTR_WARN_UNUSED_RESULT BMesh * bm
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
bool is_empty() const
Definition BLI_array.hh:253
constexpr MutableSpan take_back(const int64_t n) const
Definition BLI_span.hh:641
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:630
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
MutableSpan< T > data()
Extraction of Mesh data into VBO to feed to GPU.
format
static const GPUVertFormat & get_subdiv_lnor_format()
void convert_normals(Span< float3 > src, MutableSpan< GPUType > dst)
void extract_normals(const MeshRenderData &mr, bool use_hq, gpu::VertBuf &vbo)
void extract_normals_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, gpu::VertBuf &pos_nor, gpu::VertBuf &lnor)
void draw_subdiv_build_lnor_buffer(const DRWSubdivCache &cache, gpu::VertBuf *pos_nor, gpu::VertBuf *lnor)
int subdiv_full_vbo_size(const MeshRenderData &mr, const DRWSubdivCache &cache)
static void extract_paint_overlay_flags(const MeshRenderData &mr, MutableSpan< GPUType > normals)
static void extract_normals_mesh(const MeshRenderData &mr, MutableSpan< GPUType > normals)
static void extract_normals_bm(const MeshRenderData &mr, MutableSpan< GPUType > normals)
static void extract_face_normals(const MeshRenderData &mr, MutableSpan< GPUType > normals)
void extract_vert_normals(const MeshRenderData &mr, gpu::VertBuf &vbo)
static void convert_normals_impl(const Span< float3 > src, MutableSpan< GPUType > dst)
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
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]
int totface
char editflag
VArraySpan< bool > select_vert
VArraySpan< bool > sharp_faces
VArraySpan< bool > select_poly
OffsetIndices< int > faces
bke::MeshNormalDomain normals_domain