Blender V4.3
extract_mesh_vbo_tan.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 "MEM_guardedalloc.h"
10
11#include "BLI_string.h"
12
13#include "BKE_editmesh.hh"
15#include "BKE_mesh.hh"
16#include "BKE_mesh_tangent.hh"
17
18#include "extract_mesh.hh"
19
20#include "draw_subdivision.hh"
21
22namespace blender::draw {
23
25 const MeshBatchCache &cache,
27 GPUVertCompType comp_type,
28 GPUVertFetchMode fetch_mode,
29 CustomData *r_loop_data,
30 int *r_v_len,
31 int *r_tan_len,
32 char r_tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME],
33 bool *r_use_orco_tan)
34{
36
37 const CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata :
38 &mr.mesh->corner_data;
39 const CustomData *cd_vdata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->vdata :
40 &mr.mesh->vert_data;
41 uint32_t tan_layers = cache.cd_used.tan;
42 const float3 *orco_ptr = static_cast<const float3 *>(CustomData_get_layer(cd_vdata, CD_ORCO));
43 Span<float3> orco = orco_ptr ? Span(orco_ptr, mr.verts_num) : Span<float3>();
44 Array<float3> orco_allocated;
45 bool use_orco_tan = cache.cd_used.tan_orco != 0;
46
47 int tan_len = 0;
48
49 /* FIXME(#91838): This is to avoid a crash when orco tangent was requested but there are valid
50 * uv layers. It would be better to fix the root cause. */
51 if (tan_layers == 0 && use_orco_tan &&
53 {
54 tan_layers = 1;
55 use_orco_tan = false;
56 }
57
58 const Span<int3> corner_tris = mr.mesh->corner_tris();
59 const Span<int> corner_tri_faces = mr.mesh->corner_tri_faces();
60 const Span<float3> vert_normals = mr.mesh->vert_normals();
61
62 for (int i = 0; i < MAX_MTFACE; i++) {
63 if (tan_layers & (1 << i)) {
64 char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
65 const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_PROP_FLOAT2, i);
66 GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
67 /* Tangent layer name. */
68 SNPRINTF(attr_name, "t%s", attr_safe_name);
69 GPU_vertformat_attr_add(format, attr_name, comp_type, 4, fetch_mode);
70 /* Active render layer name. */
71 if (i == CustomData_get_render_layer(cd_ldata, CD_PROP_FLOAT2)) {
73 }
74 /* Active display layer name. */
75 if (i == CustomData_get_active_layer(cd_ldata, CD_PROP_FLOAT2)) {
77 }
78
79 STRNCPY(r_tangent_names[tan_len++], layer_name);
80 }
81 }
82 if (use_orco_tan && orco.is_empty()) {
83 /* If `orco` is not available compute it ourselves */
84 orco_allocated.reinitialize(mr.verts_num);
85
87 BMesh *bm = mr.bm;
88 for (int v = 0; v < mr.verts_num; v++) {
89 const BMVert *eve = BM_vert_at_index(bm, v);
90 /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords.
91 * not the distorted ones. */
92 copy_v3_v3(orco_allocated[v], eve->co);
93 }
94 }
95 else {
96 for (int v = 0; v < mr.verts_num; v++) {
97 copy_v3_v3(orco_allocated[v], mr.vert_positions[v]);
98 }
99 }
100 /* TODO: This is not thread-safe. Draw extraction should not modify the mesh. */
101 BKE_mesh_orco_verts_transform(const_cast<Mesh *>(mr.mesh), orco_allocated, false);
102 orco = orco_allocated;
103 }
104
105 /* Start Fresh */
106 CustomData_reset(r_loop_data);
107 if (tan_len != 0 || use_orco_tan) {
108 short tangent_mask = 0;
109 bool calc_active_tangent = false;
110 if (mr.extract_type == MR_EXTRACT_BMESH) {
112 calc_active_tangent,
113 r_tangent_names,
114 tan_len,
117 orco,
118 r_loop_data,
119 mr.corners_num,
120 &tangent_mask);
121 }
122 else {
124 mr.faces,
125 mr.corner_verts.data(),
126 corner_tris.data(),
127 corner_tri_faces.data(),
129 mr.sharp_faces,
130 cd_ldata,
131 calc_active_tangent,
132 r_tangent_names,
133 tan_len,
134 vert_normals,
135 mr.face_normals,
137 orco,
138 r_loop_data,
139 mr.corner_verts.size(),
140 &tangent_mask);
141 }
142 }
143
144 if (use_orco_tan) {
145 char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
146 const char *layer_name = CustomData_get_layer_name(r_loop_data, CD_TANGENT, 0);
147 GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
148 SNPRINTF(attr_name, "t%s", attr_safe_name);
149 GPU_vertformat_attr_add(format, attr_name, comp_type, 4, fetch_mode);
152 }
153
154 int v_len = mr.corners_num;
155 if (format->attr_len == 0) {
157 /* VBO will not be used, only allocate minimum of memory. */
158 v_len = 1;
159 }
160
161 *r_use_orco_tan = use_orco_tan;
162 *r_v_len = v_len;
163 *r_tan_len = tan_len;
164}
165
167 const MeshBatchCache &cache,
168 const bool use_hq,
169 gpu::VertBuf &vbo)
170{
171 GPUVertCompType comp_type = use_hq ? GPU_COMP_I16 : GPU_COMP_I10;
173
174 GPUVertFormat format = {0};
175 CustomData corner_data;
176 int v_len = 0;
177 int tan_len = 0;
178 bool use_orco_tan;
179 char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
181 cache,
182 &format,
183 comp_type,
184 fetch_mode,
185 &corner_data,
186 &v_len,
187 &tan_len,
188 tangent_names,
189 &use_orco_tan);
190
192 GPU_vertbuf_data_alloc(vbo, v_len);
193
194 if (use_hq) {
195 short4 *tan_data = vbo.data<short4>().data();
196 for (int i = 0; i < tan_len; i++) {
197 const char *name = tangent_names[i];
198 const float(*layer_data)[4] = (const float(*)[4])CustomData_get_layer_named(
199 &corner_data, CD_TANGENT, name);
200 for (int corner = 0; corner < mr.corners_num; corner++) {
201 normal_float_to_short_v3(*tan_data, layer_data[corner]);
202 (*tan_data)[3] = (layer_data[corner][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
203 tan_data++;
204 }
205 }
206 if (use_orco_tan) {
207 const float(*layer_data)[4] = (const float(*)[4])CustomData_get_layer_n(
208 &corner_data, CD_TANGENT, 0);
209 for (int corner = 0; corner < mr.corners_num; corner++) {
210 normal_float_to_short_v3(*tan_data, layer_data[corner]);
211 (*tan_data)[3] = (layer_data[corner][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
212 tan_data++;
213 }
214 }
215 }
216 else {
217 GPUPackedNormal *tan_data = vbo.data<GPUPackedNormal>().data();
218 for (int i = 0; i < tan_len; i++) {
219 const char *name = tangent_names[i];
220 const float(*layer_data)[4] = (const float(*)[4])CustomData_get_layer_named(
221 &corner_data, CD_TANGENT, name);
222 for (int corner = 0; corner < mr.corners_num; corner++) {
223 *tan_data = GPU_normal_convert_i10_v3(layer_data[corner]);
224 tan_data->w = (layer_data[corner][3] > 0.0f) ? 1 : -2;
225 tan_data++;
226 }
227 }
228 if (use_orco_tan) {
229 const float(*layer_data)[4] = (const float(*)[4])CustomData_get_layer_n(
230 &corner_data, CD_TANGENT, 0);
231 for (int corner = 0; corner < mr.corners_num; corner++) {
232 *tan_data = GPU_normal_convert_i10_v3(layer_data[corner]);
233 tan_data->w = (layer_data[corner][3] > 0.0f) ? 1 : -2;
234 tan_data++;
235 }
236 }
237 }
238
239 CustomData_free(&corner_data, mr.corners_num);
240}
241
243{
244 static GPUVertFormat format = {0};
245 if (format.attr_len == 0) {
247 }
248 return format;
249}
250
252 const DRWSubdivCache &subdiv_cache,
253 const MeshBatchCache &cache,
254 gpu::VertBuf &vbo)
255{
256 GPUVertCompType comp_type = GPU_COMP_F32;
258 GPUVertFormat format = {0};
259 CustomData corner_data;
260 int coarse_len = 0;
261 int tan_len = 0;
262 bool use_orco_tan;
263 char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
265 cache,
266 &format,
267 comp_type,
268 fetch_mode,
269 &corner_data,
270 &coarse_len,
271 &tan_len,
272 tangent_names,
273 &use_orco_tan);
274
276
277 gpu::VertBuf *coarse_vbo = GPU_vertbuf_calloc();
278 /* Dynamic as we upload and interpolate layers one at a time. */
280 GPU_vertbuf_data_alloc(*coarse_vbo, coarse_len);
281
282 /* Index of the tangent layer in the compact buffer. Used layers are stored in a single buffer.
283 */
284 int pack_layer_index = 0;
285 for (int i = 0; i < tan_len; i++) {
286 float4 *tan_data = coarse_vbo->data<float4>().data();
287 const char *name = tangent_names[i];
288 const float(*layer_data)[4] = (const float(*)[4])CustomData_get_layer_named(
289 &corner_data, CD_TANGENT, name);
290 for (int corner = 0; corner < mr.corners_num; corner++) {
291 copy_v3_v3(*tan_data, layer_data[corner]);
292 (*tan_data)[3] = (layer_data[corner][3] > 0.0f) ? 1.0f : -1.0f;
293 tan_data++;
294 }
295
296 /* Ensure data is uploaded properly. */
297 GPU_vertbuf_tag_dirty(coarse_vbo);
298 /* Include stride in offset. */
299 const int dst_offset = int(subdiv_cache.num_subdiv_loops) * 4 * pack_layer_index++;
300 draw_subdiv_interp_custom_data(subdiv_cache, *coarse_vbo, vbo, GPU_COMP_F32, 4, dst_offset);
301 }
302 if (use_orco_tan) {
303 float4 *tan_data = coarse_vbo->data<float4>().data();
304 const float(*layer_data)[4] = (const float(*)[4])CustomData_get_layer_n(
305 &corner_data, CD_TANGENT, 0);
306 for (int corner = 0; corner < mr.corners_num; corner++) {
307 copy_v3_v3(*tan_data, layer_data[corner]);
308 (*tan_data)[3] = (layer_data[corner][3] > 0.0f) ? 1.0f : -1.0f;
309 tan_data++;
310 }
311
312 /* Ensure data is uploaded properly. */
313 GPU_vertbuf_tag_dirty(coarse_vbo);
314 /* Include stride in offset. */
315 const int dst_offset = int(subdiv_cache.num_subdiv_loops) * 4 * pack_layer_index++;
316 draw_subdiv_interp_custom_data(subdiv_cache, *coarse_vbo, vbo, GPU_COMP_F32, 4, dst_offset);
317 }
318
319 CustomData_free(&corner_data, mr.corners_num);
320 GPU_vertbuf_discard(coarse_vbo);
321}
322
323} // namespace blender::draw
const void * CustomData_get_layer_n(const CustomData *data, eCustomDataType type, int n)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_reset(CustomData *data)
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_layer_index(const CustomData *data, eCustomDataType type)
void CustomData_free(CustomData *data, int totelem)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
int CustomData_get_render_layer(const CustomData *data, eCustomDataType type)
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_len, blender::Span< blender::float3 > face_normals, blender::Span< blender::float3 > corner_normals, blender::Span< blender::float3 > vert_orco, CustomData *dm_loopdata_out, uint dm_loopdata_out_len, short *tangent_mask_curr_p)
void BKE_mesh_orco_verts_transform(Mesh *mesh, blender::MutableSpan< blender::float3 > orco, bool invert)
void BKE_mesh_calc_loop_tangent_ex(blender::Span< blender::float3 > vert_positions, blender::OffsetIndices< int > faces, const int *corner_verts, const blender::int3 *corner_tris, const int *corner_tri_faces, uint corner_tris_len, const blender::Span< bool > sharp_faces, const CustomData *loopdata, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_len, blender::Span< blender::float3 > vert_normals, blender::Span< blender::float3 > face_normals, blender::Span< blender::float3 > corner_normals, blender::Span< blender::float3 > vert_orco, CustomData *loopdata_out, uint loopdata_out_len, short *tangent_mask_curr_p)
MINLINE void normal_float_to_short_v3(short out[3], const float in[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define MAX_CUSTOMDATA_LAYER_NAME
@ CD_PROP_FLOAT2
#define MAX_MTFACE
void GPU_vertbuf_init_build_on_device(blender::gpu::VertBuf &verts, const GPUVertFormat &format, uint v_len)
void GPU_vertbuf_tag_dirty(blender::gpu::VertBuf *verts)
#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_init_with_format_ex(blender::gpu::VertBuf &verts, const GPUVertFormat &format, GPUUsageType)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
@ GPU_USAGE_DYNAMIC
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len)
GPUVertFetchMode
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
#define GPU_MAX_SAFE_ATTR_NAME
BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias)
void GPU_vertformat_deinterleave(GPUVertFormat *format)
GPUVertCompType
@ GPU_COMP_I10
@ GPU_COMP_F32
@ GPU_COMP_I16
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT BMesh * bm
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
ATTR_WARN_UNUSED_RESULT const BMVert * v
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr bool is_empty() const
Definition BLI_span.hh:261
MutableSpan< T > data()
draw_view in_light_buf[] float
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.
format
void extract_tangents(const MeshRenderData &mr, const MeshBatchCache &cache, const bool use_hq, gpu::VertBuf &vbo)
static const GPUVertFormat & get_coarse_tan_format()
static void extract_tan_init_common(const MeshRenderData &mr, const MeshBatchCache &cache, GPUVertFormat *format, GPUVertCompType comp_type, GPUVertFetchMode fetch_mode, CustomData *r_loop_data, int *r_v_len, int *r_tan_len, char r_tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME], bool *r_use_orco_tan)
void extract_tangents_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, const MeshBatchCache &cache, gpu::VertBuf &vbo)
void draw_subdiv_interp_custom_data(const DRWSubdivCache &cache, gpu::VertBuf &src_data, gpu::VertBuf &dst_data, int comp_type, int dimensions, int dst_offset)
unsigned int uint32_t
Definition stdint.h:80
float co[3]
CustomData vdata
CustomData ldata
CustomData corner_data
CustomData vert_data
VArraySpan< bool > sharp_faces
OffsetIndices< int > faces