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