Blender V4.5
mesh_tangent.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_geom.h"
14#include "BLI_math_vector.h"
15#include "BLI_string.h"
16#include "BLI_task.h"
17#include "BLI_utildefines.h"
18
19#include "BKE_attribute.hh"
20#include "BKE_customdata.hh"
21#include "BKE_mesh.hh"
22#include "BKE_mesh_tangent.hh"
23#include "BKE_report.hh"
24
25#include "mikktspace.hh"
26
27#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
28
29using blender::float2;
30using blender::float3;
31using blender::int3;
33using blender::Span;
34
35/* -------------------------------------------------------------------- */
38
41 {
42 return uint(num_faces);
43 }
44
46 {
47 return uint(faces[face_num].size());
48 }
49
50 mikk::float3 GetPosition(const uint face_num, const uint vert_num)
51 {
52 const uint loop_idx = uint(faces[face_num].start()) + vert_num;
53 return mikk::float3(positions[corner_verts[loop_idx]]);
54 }
55
56 mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
57 {
58 const float *uv = luvs[uint(faces[face_num].start()) + vert_num];
59 return mikk::float3(uv[0], uv[1], 1.0f);
60 }
61
62 mikk::float3 GetNormal(const uint face_num, const uint vert_num)
63 {
64 return mikk::float3(corner_normals[uint(faces[face_num].start()) + vert_num]);
65 }
66
67 void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
68 {
69 float *p_res = tangents[uint(faces[face_num].start()) + vert_num];
70 copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
71 }
72
73 OffsetIndices<int> faces; /* faces */
74 const int *corner_verts; /* faces vertices */
75 const float (*positions)[3]; /* vertices */
76 const float (*luvs)[2]; /* texture coordinates */
77 const float (*corner_normals)[3]; /* loops' normals */
78 float (*tangents)[4]; /* output tangents */
79 int num_faces; /* number of polygons */
80};
81
82void BKE_mesh_calc_loop_tangent_single_ex(const float (*vert_positions)[3],
83 const int /*numVerts*/,
84 const int *corner_verts,
85 float (*r_looptangent)[4],
86 const float (*corner_normals)[3],
87 const float (*loop_uvs)[2],
88 const int /*numLoops*/,
89 const OffsetIndices<int> faces,
91{
92 /* Compute Mikktspace's tangent normals. */
93 BKEMeshToTangent mesh_to_tangent;
94 mesh_to_tangent.faces = faces;
95 mesh_to_tangent.corner_verts = corner_verts;
96 mesh_to_tangent.positions = vert_positions;
97 mesh_to_tangent.luvs = loop_uvs;
98 mesh_to_tangent.corner_normals = corner_normals;
99 mesh_to_tangent.tangents = r_looptangent;
100 mesh_to_tangent.num_faces = int(faces.size());
101
103
104 /* First check we do have a tris/quads only mesh. */
105 for (const int64_t i : faces.index_range()) {
106 if (faces[i].size() > 4) {
108 reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
109 return;
110 }
111 }
112
113 mikk.genTangSpace();
114}
115
117 const char *uvmap,
118 float (*r_looptangents)[4],
120{
121 using namespace blender;
122 using namespace blender::bke;
123 if (!uvmap) {
125 }
126
127 const AttributeAccessor attributes = mesh->attributes();
128 const VArraySpan uv_map = *attributes.lookup<float2>(uvmap, AttrDomain::Corner);
129 if (uv_map.is_empty()) {
131 RPT_ERROR,
132 "Tangent space computation needs a UV Map, \"%s\" not found, aborting",
133 uvmap);
134 return;
135 }
136
138 reinterpret_cast<const float(*)[3]>(mesh->vert_positions().data()),
139 mesh->verts_num,
140 mesh->corner_verts().data(),
141 r_looptangents,
142 reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data()),
143 reinterpret_cast<const float(*)[2]>(uv_map.data()),
144 mesh->corners_num,
145 mesh->faces(),
146 reports);
147}
148
150
151/* -------------------------------------------------------------------- */
154
155/* Necessary complexity to handle corner_tris as quads for correct tangents. */
156#define USE_TRI_DETECT_QUADS
157
160 {
161#ifdef USE_TRI_DETECT_QUADS
163#else
164 return uint(numTessFaces);
165#endif
166 }
167
169 {
170#ifdef USE_TRI_DETECT_QUADS
171 if (face_as_quad_map) {
172 const int face_index = tri_faces[face_as_quad_map[face_num]];
173 if (faces[face_index].size() == 4) {
174 return 4;
175 }
176 }
177 return 3;
178#else
179 UNUSED_VARS(pContext, face_num);
180 return 3;
181#endif
182 }
183
184 uint GetLoop(const uint face_num, const uint vert_num, int3 &tri, int &face_index)
185 {
186#ifdef USE_TRI_DETECT_QUADS
187 if (face_as_quad_map) {
188 tri = corner_tris[face_as_quad_map[face_num]];
189 face_index = tri_faces[face_as_quad_map[face_num]];
190 if (faces[face_index].size() == 4) {
191 return uint(faces[face_index][vert_num]);
192 }
193 /* fall through to regular triangle */
194 }
195 else {
196 tri = corner_tris[face_num];
197 face_index = tri_faces[face_num];
198 }
199#else
200 tri = &corner_tris[face_num];
201#endif
202
203 /* Safe to suppress since the way `face_as_quad_map` is used
204 * prevents out-of-bounds reads on the 4th component of the `int3`. */
205#ifdef __GNUC__
206# pragma GCC diagnostic push
207# pragma GCC diagnostic ignored "-Warray-bounds"
208#endif
209
210 return uint(tri[int(vert_num)]);
211
212#ifdef __GNUC__
213# pragma GCC diagnostic pop
214#endif
215 }
216
217 mikk::float3 GetPosition(const uint face_num, const uint vert_num)
218 {
219 int3 tri;
220 int face_index;
221 uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
222 return mikk::float3(positions[corner_verts[loop_index]]);
223 }
224
225 mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
226 {
227 int3 tri;
228 int face_index;
229 uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
230 if (mloopuv != nullptr) {
231 const float2 &uv = mloopuv[loop_index];
232 return mikk::float3(uv[0], uv[1], 1.0f);
233 }
234 const float *l_orco = orco[corner_verts[loop_index]];
235 float u, v;
236 map_to_sphere(&u, &v, l_orco[0], l_orco[1], l_orco[2]);
237 return mikk::float3(u, v, 1.0f);
238 }
239
240 mikk::float3 GetNormal(const uint face_num, const uint vert_num)
241 {
242 int3 tri;
243 int face_index;
244 uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
245 if (!corner_normals.is_empty()) {
246 return mikk::float3(corner_normals[loop_index]);
247 }
248 if (!sharp_faces.is_empty() && sharp_faces[face_index]) { /* flat */
249 if (!face_normals.is_empty()) {
250 return mikk::float3(face_normals[face_index]);
251 }
252#ifdef USE_TRI_DETECT_QUADS
253 const blender::IndexRange face = faces[face_index];
254 float normal[3];
255 if (face.size() == 4) {
256 normal_quad_v3(normal,
257 positions[corner_verts[face[0]]],
258 positions[corner_verts[face[1]]],
259 positions[corner_verts[face[2]]],
260 positions[corner_verts[face[3]]]);
261 }
262 else
263#endif
264 {
265 normal_tri_v3(normal,
266 positions[corner_verts[tri[0]]],
267 positions[corner_verts[tri[1]]],
268 positions[corner_verts[tri[2]]]);
269 }
270 return mikk::float3(normal);
271 }
272 return mikk::float3(vert_normals[corner_verts[loop_index]]);
273 }
274
275 void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
276 {
277 int3 tri;
278 int face_index;
279 uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
280
281 copy_v4_fl4(tangent[loop_index], T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
282 }
283
287 const int *tri_faces;
288 const float2 *mloopuv; /* texture coordinates */
290 const int *corner_verts; /* indices */
291 Span<float3> positions; /* vertex coordinates */
294 float (*tangent)[4]; /* destination */
297
298#ifdef USE_TRI_DETECT_QUADS
299 /* map from 'fake' face index to corner_tris,
300 * quads will point to the first corner_tris of the quad */
303#endif
304};
305
306static void DM_calc_loop_tangents_thread(TaskPool *__restrict /*pool*/, void *taskdata)
307{
308 SGLSLMeshToTangent *mesh_data = static_cast<SGLSLMeshToTangent *>(taskdata);
309
311 mikk.genTangSpace();
312}
313
315 CustomData *tan_data,
316 int numLoopData,
317 const char *layer_name)
318{
319 if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
320 CustomData_get_named_layer_index(uv_data, CD_PROP_FLOAT2, layer_name) != -1)
321 {
322 CustomData_add_layer_named(tan_data, CD_TANGENT, CD_SET_DEFAULT, numLoopData, layer_name);
323 }
324}
325
327 bool calc_active_tangent,
328 const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
329 int tangent_names_count,
330 bool *rcalc_act,
331 bool *rcalc_ren,
332 int *ract_uv_n,
333 int *rren_uv_n,
334 char *ract_uv_name,
335 char *rren_uv_name,
336 short *rtangent_mask)
337{
338 /* Active uv in viewport */
339 int layer_index = CustomData_get_layer_index(loopData, CD_PROP_FLOAT2);
340 *ract_uv_n = CustomData_get_active_layer(loopData, CD_PROP_FLOAT2);
341 ract_uv_name[0] = 0;
342 if (*ract_uv_n != -1) {
344 ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name, MAX_CUSTOMDATA_LAYER_NAME);
345 }
346
347 /* Active tangent in render */
348 *rren_uv_n = CustomData_get_render_layer(loopData, CD_PROP_FLOAT2);
349 rren_uv_name[0] = 0;
350 if (*rren_uv_n != -1) {
352 rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name, MAX_CUSTOMDATA_LAYER_NAME);
353 }
354
355 /* If active tangent not in tangent_names we take it into account */
356 *rcalc_act = false;
357 *rcalc_ren = false;
358 for (int i = 0; i < tangent_names_count; i++) {
359 if (tangent_names[i][0] == 0) {
360 calc_active_tangent = true;
361 }
362 }
363 if (calc_active_tangent) {
364 *rcalc_act = true;
365 *rcalc_ren = true;
366 for (int i = 0; i < tangent_names_count; i++) {
367 if (STREQ(ract_uv_name, tangent_names[i])) {
368 *rcalc_act = false;
369 }
370 if (STREQ(rren_uv_name, tangent_names[i])) {
371 *rcalc_ren = false;
372 }
373 }
374 }
375 *rtangent_mask = 0;
376
377 const int uv_layer_num = CustomData_number_of_layers(loopData, CD_PROP_FLOAT2);
378 for (int n = 0; n < uv_layer_num; n++) {
379 const char *name = CustomData_get_layer_name(loopData, CD_PROP_FLOAT2, n);
380 bool add = false;
381 for (int i = 0; i < tangent_names_count; i++) {
382 if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
383 add = true;
384 break;
385 }
386 }
387 if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
388 (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name))))
389 {
390 add = true;
391 }
392 if (add) {
393 *rtangent_mask |= short(1 << n);
394 }
395 }
396
397 if (uv_layer_num == 0) {
398 *rtangent_mask |= DM_TANGENT_MASK_ORCO;
399 }
400}
401
404 const Span<int> corner_verts,
405 const Span<int3> corner_tris,
406 const Span<int> corner_tri_faces,
407 const Span<bool> sharp_faces,
408 const CustomData *loopdata,
409 bool calc_active_tangent,
410 const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
411 int tangent_names_len,
412 const Span<float3> vert_normals,
413 const Span<float3> face_normals,
414 const Span<float3> corner_normals,
415 const Span<float3> vert_orco,
416 /* result */
417 CustomData *loopdata_out,
418 const uint loopdata_out_len,
419 short *tangent_mask_curr_p)
420{
421 int act_uv_n = -1;
422 int ren_uv_n = -1;
423 bool calc_act = false;
424 bool calc_ren = false;
425 char act_uv_name[MAX_CUSTOMDATA_LAYER_NAME];
426 char ren_uv_name[MAX_CUSTOMDATA_LAYER_NAME];
427 short tangent_mask = 0;
428 short tangent_mask_curr = *tangent_mask_curr_p;
429
431 calc_active_tangent,
432 tangent_names,
433 tangent_names_len,
434 &calc_act,
435 &calc_ren,
436 &act_uv_n,
437 &ren_uv_n,
438 act_uv_name,
439 ren_uv_name,
440 &tangent_mask);
441 if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
442 /* Check we have all the needed layers */
443 /* Allocate needed tangent layers */
444 for (int i = 0; i < tangent_names_len; i++) {
445 if (tangent_names[i][0]) {
447 loopdata, loopdata_out, int(loopdata_out_len), tangent_names[i]);
448 }
449 }
450 if ((tangent_mask & DM_TANGENT_MASK_ORCO) &&
451 CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1)
452 {
454 loopdata_out, CD_TANGENT, CD_SET_DEFAULT, int(loopdata_out_len), "");
455 }
456 if (calc_act && act_uv_name[0]) {
458 loopdata, loopdata_out, int(loopdata_out_len), act_uv_name);
459 }
460 if (calc_ren && ren_uv_name[0]) {
462 loopdata, loopdata_out, int(loopdata_out_len), ren_uv_name);
463 }
464
465#ifdef USE_TRI_DETECT_QUADS
466 int num_face_as_quad_map;
467 int *face_as_quad_map = nullptr;
468
469 /* map faces to quads */
470 if (corner_tris.size() != faces.size()) {
471 /* Over allocate, since we don't know how many ngon or quads we have. */
472
473 /* Map fake face index to corner_tris. */
474 face_as_quad_map = MEM_malloc_arrayN<int>(size_t(corner_tris.size()), __func__);
475 int k, j;
476 for (k = 0, j = 0; j < int(corner_tris.size()); k++, j++) {
477 face_as_quad_map[k] = j;
478 /* step over all quads */
479 if (faces[corner_tri_faces[j]].size() == 4) {
480 j++; /* Skips the next corner_tri. */
481 }
482 }
483 num_face_as_quad_map = k;
484 }
485 else {
486 num_face_as_quad_map = int(corner_tris.size());
487 }
488#endif
489
490 /* Calculation */
491 if (corner_tris.size() != 0) {
493
494 tangent_mask_curr = 0;
495 /* Calculate tangent layers */
496 SGLSLMeshToTangent data_array[MAX_MTFACE];
497 const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
498 for (int n = 0; n < tangent_layer_num; n++) {
499 int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
501 SGLSLMeshToTangent *mesh2tangent = &data_array[n];
502 mesh2tangent->numTessFaces = int(corner_tris.size());
503#ifdef USE_TRI_DETECT_QUADS
504 mesh2tangent->face_as_quad_map = face_as_quad_map;
505 mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
506#endif
507 mesh2tangent->positions = vert_positions;
508 mesh2tangent->vert_normals = vert_normals;
509 mesh2tangent->faces = faces;
510 mesh2tangent->corner_verts = corner_verts.data();
511 mesh2tangent->corner_tris = corner_tris.data();
512 mesh2tangent->tri_faces = corner_tri_faces.data();
513 mesh2tangent->sharp_faces = sharp_faces;
514 /* NOTE: we assume we do have tessellated loop normals at this point
515 * (in case it is object-enabled), have to check this is valid. */
516 mesh2tangent->corner_normals = corner_normals;
517 mesh2tangent->face_normals = face_normals;
518
519 mesh2tangent->orco = {};
520 mesh2tangent->mloopuv = static_cast<const float2 *>(CustomData_get_layer_named(
521 loopdata, CD_PROP_FLOAT2, loopdata_out->layers[index].name));
522
523 /* Fill the resulting tangent_mask */
524 if (!mesh2tangent->mloopuv) {
525 mesh2tangent->orco = vert_orco;
526 if (mesh2tangent->orco.is_empty()) {
527 continue;
528 }
529
530 tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
531 }
532 else {
534 loopdata, CD_PROP_FLOAT2, loopdata_out->layers[index].name);
535 int uv_start = CustomData_get_layer_index(loopdata, CD_PROP_FLOAT2);
536 BLI_assert(uv_ind != -1 && uv_start != -1);
537 BLI_assert(uv_ind - uv_start < MAX_MTFACE);
538 tangent_mask_curr |= short(1 << (uv_ind - uv_start));
539 }
540
541 mesh2tangent->tangent = static_cast<float(*)[4]>(loopdata_out->layers[index].data);
542 BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, nullptr);
543 }
544
545 BLI_assert(tangent_mask_curr == tangent_mask);
548 }
549 else {
550 tangent_mask_curr = tangent_mask;
551 }
552#ifdef USE_TRI_DETECT_QUADS
553 if (face_as_quad_map) {
554 MEM_freeN(face_as_quad_map);
555 }
556# undef USE_TRI_DETECT_QUADS
557
558#endif
559
560 *tangent_mask_curr_p = tangent_mask_curr;
561
562 /* Update active layer index */
563 if (const char *active_uv_name = CustomData_get_active_layer_name(loopdata, CD_PROP_FLOAT2)) {
564 int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, active_uv_name);
565 if (tan_index != -1) {
566 CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
567 }
568 } /* else tangent has been built from orco */
569
570 /* Update render layer index */
571 if (const char *render_uv_name = CustomData_get_render_layer_name(loopdata, CD_PROP_FLOAT2)) {
572 int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, render_uv_name);
573 if (tan_index != -1) {
574 CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
575 }
576 } /* else tangent has been built from orco */
577 }
578}
579
581 bool calc_active_tangent,
582 const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
583 int tangent_names_len)
584{
585 /* TODO(@ideasman42): store in Mesh.runtime to avoid recalculation. */
586 using namespace blender;
587 using namespace blender::bke;
588 const Span<int3> corner_tris = mesh_eval->corner_tris();
589 const bke::AttributeAccessor attributes = mesh_eval->attributes();
590 const VArraySpan sharp_face = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
591 const float3 *orco = static_cast<const float3 *>(
593 short tangent_mask = 0;
594 BKE_mesh_calc_loop_tangent_ex(mesh_eval->vert_positions(),
595 mesh_eval->faces(),
596 mesh_eval->corner_verts(),
597 corner_tris,
598 mesh_eval->corner_tri_faces(),
599 sharp_face,
600 &mesh_eval->corner_data,
601 calc_active_tangent,
602 tangent_names,
603 tangent_names_len,
604 mesh_eval->vert_normals(),
605 mesh_eval->face_normals(),
606 mesh_eval->corner_normals(),
607 /* may be nullptr */
608 orco ? Span(orco, mesh_eval->verts_num) : Span<float3>(),
609 /* result */
610 &mesh_eval->corner_data,
611 uint(mesh_eval->corners_num),
612 &tangent_mask);
613}
614
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_layer_index_n(const CustomData *data, eCustomDataType type, int n)
void CustomData_set_layer_render_index(CustomData *data, eCustomDataType type, int n)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
int CustomData_get_named_layer_index(const CustomData *data, eCustomDataType type, blender::StringRef name)
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_set_layer_active_index(CustomData *data, eCustomDataType type, int n)
const char * CustomData_get_render_layer_name(const CustomData *data, eCustomDataType type)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
int CustomData_get_render_layer(const CustomData *data, eCustomDataType type)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
#define DM_TANGENT_MASK_ORCO
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define BLI_assert(a)
Definition BLI_assert.h:46
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:58
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:41
bool map_to_sphere(float *r_u, float *r_v, float x, float y, float z)
MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned int uint
@ TASK_PRIORITY_HIGH
Definition BLI_task.h:53
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:531
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:480
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:517
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:522
#define UNUSED_VARS(...)
#define STREQ(a, b)
@ CD_PROP_FLOAT2
Read Guarded memory(de)allocation.
ReportList * reports
Definition WM_types.hh:1025
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
AttributeSet attributes
constexpr int64_t size() const
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup(const StringRef attribute_id) const
TaskPool * task_pool
#define MAX_CUSTOMDATA_LAYER_NAME
#define MAX_MTFACE
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define T
static char faces[256]
void BKE_mesh_calc_loop_tangent_ex(const Span< float3 > vert_positions, const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< int3 > corner_tris, const Span< int > corner_tri_faces, const Span< bool > sharp_faces, const CustomData *loopdata, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_len, const Span< float3 > vert_normals, const Span< float3 > face_normals, const Span< float3 > corner_normals, const Span< float3 > vert_orco, CustomData *loopdata_out, const uint loopdata_out_len, short *tangent_mask_curr_p)
void BKE_mesh_calc_loop_tangents(Mesh *mesh_eval, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_len)
void BKE_mesh_add_loop_tangent_named_layer_for_uv(const CustomData *uv_data, CustomData *tan_data, int numLoopData, const char *layer_name)
void BKE_mesh_calc_loop_tangent_single_ex(const float(*vert_positions)[3], const int, const int *corner_verts, float(*r_looptangent)[4], const float(*corner_normals)[3], const float(*loop_uvs)[2], const int, const OffsetIndices< int > faces, ReportList *reports)
static void DM_calc_loop_tangents_thread(TaskPool *__restrict, void *taskdata)
void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_count, bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float(*r_looptangents)[4], ReportList *reports)
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
mikk::float3 GetNormal(const uint face_num, const uint vert_num)
const int * corner_verts
mikk::float3 GetPosition(const uint face_num, const uint vert_num)
void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
float(* tangents)[4]
const float(* corner_normals)[3]
OffsetIndices< int > faces
const float(* luvs)[2]
const float(* positions)[3]
uint GetNumVerticesOfFace(const uint face_num)
CustomDataLayer * layers
int corners_num
CustomData corner_data
CustomData vert_data
int verts_num
Span< float3 > positions
Span< bool > sharp_faces
mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
const int3 * corner_tris
uint GetNumVerticesOfFace(const uint face_num)
uint GetLoop(const uint face_num, const uint vert_num, int3 &tri, int &face_index)
Span< float3 > orco
OffsetIndices< int > faces
const int * corner_verts
const float2 * mloopuv
Span< float3 > face_normals
Span< float3 > vert_normals
void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
const int * face_as_quad_map
mikk::float3 GetNormal(const uint face_num, const uint vert_num)
Span< float3 > corner_normals
const int * tri_faces
mikk::float3 GetPosition(const uint face_num, const uint vert_num)
i
Definition text_draw.cc:230