Blender V4.3
editmesh_tangent.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_geom.h"
10#include "BLI_math_vector.h"
11#include "BLI_task.h"
12
14#include "DNA_defs.h"
15
16#include "BKE_customdata.hh"
17#include "BKE_editmesh.hh"
19#include "BKE_mesh.hh"
20#include "BKE_mesh_tangent.hh" /* for utility functions */
21
22#include "MEM_guardedalloc.h"
23
24/* interface */
25#include "mikktspace.hh"
26
27using blender::float3;
28using blender::Span;
29
30/* -------------------------------------------------------------------- */
34/* Necessary complexity to handle looptris as quads for correct tangents. */
35#define USE_LOOPTRI_DETECT_QUADS
36
39 {
40#ifdef USE_LOOPTRI_DETECT_QUADS
42#else
43 return uint(numTessFaces);
44#endif
45 }
46
48 {
49#ifdef USE_LOOPTRI_DETECT_QUADS
50 if (face_as_quad_map) {
51 if (looptris[face_as_quad_map[face_num]][0]->f->len == 4) {
52 return 4;
53 }
54 }
55 return 3;
56#else
57 UNUSED_VARS(pContext, face_num);
58 return 3;
59#endif
60 }
61
62 const BMLoop *GetLoop(const uint face_num, uint vert_index)
63 {
64 // BLI_assert(vert_index >= 0 && vert_index < 4);
65 BMLoop *const *ltri;
66 const BMLoop *l;
67
68#ifdef USE_LOOPTRI_DETECT_QUADS
69 if (face_as_quad_map) {
70 ltri = looptris[face_as_quad_map[face_num]].data();
71 if (ltri[0]->f->len == 4) {
72 l = BM_FACE_FIRST_LOOP(ltri[0]->f);
73 while (vert_index--) {
74 l = l->next;
75 }
76 return l;
77 }
78 /* fall through to regular triangle */
79 }
80 else {
81 ltri = looptris[face_num].data();
82 }
83#else
84 ltri = looptris[face_num].data();
85#endif
86 return ltri[vert_index];
87 }
88
89 mikk::float3 GetPosition(const uint face_num, const uint vert_index)
90 {
91 const BMLoop *l = GetLoop(face_num, vert_index);
92 return mikk::float3(l->v->co);
93 }
94
95 mikk::float3 GetTexCoord(const uint face_num, const uint vert_index)
96 {
97 const BMLoop *l = GetLoop(face_num, vert_index);
98 if (cd_loop_uv_offset != -1) {
99 const float *uv = (const float *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
100 return mikk::float3(uv[0], uv[1], 1.0f);
101 }
102 const float *orco_p = orco[BM_elem_index_get(l->v)];
103 float u, v;
104 map_to_sphere(&u, &v, orco_p[0], orco_p[1], orco_p[2]);
105 return mikk::float3(u, v, 1.0f);
106 }
107
108 mikk::float3 GetNormal(const uint face_num, const uint vert_index)
109 {
110 const BMLoop *l = GetLoop(face_num, vert_index);
111 if (!corner_normals.is_empty()) {
113 }
114 if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
115 if (!face_normals.is_empty()) {
117 }
118 return mikk::float3(l->f->no);
119 }
120 return mikk::float3(l->v->no);
121 }
122
123 void SetTangentSpace(const uint face_num,
124 const uint vert_index,
125 mikk::float3 T,
126 bool orientation)
127 {
128 const BMLoop *l = GetLoop(face_num, vert_index);
129 float *p_res = tangent[BM_elem_index_get(l)];
130 copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
131 }
132
136 int cd_loop_uv_offset; /* texture coordinates */
138 float (*tangent)[4]; /* destination */
140
141#ifdef USE_LOOPTRI_DETECT_QUADS
142 /* map from 'fake' face index to looptris,
143 * quads will point to the first looptri of the quad */
146#endif
147};
148
149static void emDM_calc_loop_tangents_thread(TaskPool *__restrict /*pool*/, void *taskdata)
150{
151 SGLSLEditMeshToTangent *mesh_data = static_cast<SGLSLEditMeshToTangent *>(taskdata);
152
154 mikk.genTangSpace();
155}
156
158 bool calc_active_tangent,
159 const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
160 int tangent_names_len,
161 const Span<float3> face_normals,
162 const Span<float3> corner_normals,
163 const Span<float3> vert_orco,
164 /* result */
165 CustomData *loopdata_out,
166 const uint loopdata_out_len,
167 short *tangent_mask_curr_p)
168{
169 BMesh *bm = em->bm;
170
171 int act_uv_n = -1;
172 int ren_uv_n = -1;
173 bool calc_act = false;
174 bool calc_ren = false;
175 char act_uv_name[MAX_NAME];
176 char ren_uv_name[MAX_NAME];
177 short tangent_mask = 0;
178 short tangent_mask_curr = *tangent_mask_curr_p;
179
181 calc_active_tangent,
182 tangent_names,
183 tangent_names_len,
184 &calc_act,
185 &calc_ren,
186 &act_uv_n,
187 &ren_uv_n,
188 act_uv_name,
189 ren_uv_name,
190 &tangent_mask);
191
192 if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
193 for (int i = 0; i < tangent_names_len; i++) {
194 if (tangent_names[i][0]) {
196 &bm->ldata, loopdata_out, int(loopdata_out_len), tangent_names[i]);
197 }
198 }
199 if ((tangent_mask & DM_TANGENT_MASK_ORCO) &&
200 CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1)
201 {
203 loopdata_out, CD_TANGENT, CD_SET_DEFAULT, int(loopdata_out_len), "");
204 }
205 if (calc_act && act_uv_name[0]) {
207 &bm->ldata, loopdata_out, int(loopdata_out_len), act_uv_name);
208 }
209 if (calc_ren && ren_uv_name[0]) {
211 &bm->ldata, loopdata_out, int(loopdata_out_len), ren_uv_name);
212 }
213 int totface = em->looptris.size();
214#ifdef USE_LOOPTRI_DETECT_QUADS
215 int num_face_as_quad_map;
216 int *face_as_quad_map = nullptr;
217
218 /* map faces to quads */
219 if (em->looptris.size() != bm->totface) {
220 /* Over allocate, since we don't know how many ngon or quads we have. */
221
222 /* map fake face index to looptri */
223 face_as_quad_map = static_cast<int *>(MEM_mallocN(sizeof(int) * totface, __func__));
224 int i, j;
225 for (i = 0, j = 0; j < totface; i++, j++) {
226 face_as_quad_map[i] = j;
227 /* step over all quads */
228 if (em->looptris[j][0]->f->len == 4) {
229 j++; /* Skips the next looptri. */
230 }
231 }
232 num_face_as_quad_map = i;
233 }
234 else {
235 num_face_as_quad_map = totface;
236 }
237#endif
238 /* Calculation */
239 if (em->looptris.size() != 0) {
242
243 tangent_mask_curr = 0;
244 /* Calculate tangent layers */
246 int index = 0;
247 int n = 0;
248 CustomData_update_typemap(loopdata_out);
249 const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
250 for (n = 0; n < tangent_layer_num; n++) {
251 index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
253 SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
254 mesh2tangent->numTessFaces = em->looptris.size();
255#ifdef USE_LOOPTRI_DETECT_QUADS
256 mesh2tangent->face_as_quad_map = face_as_quad_map;
257 mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
258#endif
259 mesh2tangent->face_normals = face_normals;
260 /* NOTE: we assume we do have tessellated loop normals at this point
261 * (in case it is object-enabled), have to check this is valid. */
262 mesh2tangent->corner_normals = corner_normals;
264
265 /* needed for indexing loop-tangents */
266 int htype_index = BM_LOOP;
267 if (mesh2tangent->cd_loop_uv_offset == -1) {
268 mesh2tangent->orco = vert_orco;
269 if (mesh2tangent->orco.is_empty()) {
270 continue;
271 }
272 /* needed for orco lookups */
273 htype_index |= BM_VERT;
274 tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
275 }
276 else {
277 /* Fill the resulting tangent_mask */
279 &bm->ldata, CD_PROP_FLOAT2, loopdata_out->layers[index].name);
281 BLI_assert(uv_ind != -1 && uv_start != -1);
282 BLI_assert(uv_ind - uv_start < MAX_MTFACE);
283 tangent_mask_curr |= 1 << (uv_ind - uv_start);
284 }
285 if (!mesh2tangent->face_normals.is_empty()) {
286 /* needed for face normal lookups */
287 htype_index |= BM_FACE;
288 }
289 BM_mesh_elem_index_ensure(bm, htype_index);
290
291 mesh2tangent->looptris = em->looptris;
292 mesh2tangent->tangent = static_cast<float(*)[4]>(loopdata_out->layers[index].data);
293
295 task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, nullptr);
296 }
297
298 BLI_assert(tangent_mask_curr == tangent_mask);
301 }
302 else {
303 tangent_mask_curr = tangent_mask;
304 }
305#ifdef USE_LOOPTRI_DETECT_QUADS
306 if (face_as_quad_map) {
307 MEM_freeN(face_as_quad_map);
308 }
309# undef USE_LOOPTRI_DETECT_QUADS
310#endif
311 }
312
313 *tangent_mask_curr_p = tangent_mask_curr;
314
315 int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_PROP_FLOAT2, act_uv_n);
316 if (act_uv_index >= 0) {
317 int tan_index = CustomData_get_named_layer_index(
318 loopdata_out, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
319 CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
320 } /* else tangent has been built from orco */
321
322 /* Update render layer index */
323 int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_PROP_FLOAT2, ren_uv_n);
324 if (ren_uv_index >= 0) {
325 int tan_index = CustomData_get_named_layer_index(
326 loopdata_out, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
327 CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
328 } /* else tangent has been built from orco */
329}
330
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)
int CustomData_get_n_offset(const CustomData *data, eCustomDataType type, int n)
@ CD_SET_DEFAULT
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)
int CustomData_get_layer_index(const CustomData *data, eCustomDataType type)
void CustomData_update_typemap(CustomData *data)
void CustomData_set_layer_active_index(CustomData *data, eCustomDataType type, int n)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
void BKE_mesh_add_loop_tangent_named_layer_for_uv(const CustomData *uv_data, CustomData *tan_data, int numLoopData, const char *layer_name)
#define DM_TANGENT_MASK_ORCO
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)
#define BLI_assert(a)
Definition BLI_assert.h:50
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)
unsigned int uint
@ TASK_PRIORITY_HIGH
Definition BLI_task.h:57
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:471
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:394
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:431
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:450
#define UNUSED_VARS(...)
#define MAX_CUSTOMDATA_LAYER_NAME
@ CD_PROP_FLOAT2
#define MAX_MTFACE
#define MAX_NAME
Definition DNA_defs.h:50
Read Guarded memory(de)allocation.
@ BM_LOOP
@ BM_ELEM_SMOOTH
#define BM_FACE_FIRST_LOOP(p)
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_FACE
#define BM_VERT
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
int64_t size() const
Definition BLI_array.hh:245
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_len, 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)
static void emDM_calc_loop_tangents_thread(TaskPool *__restrict, void *taskdata)
TaskPool * task_pool
draw_view in_light_buf[] float
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
blender::Array< std::array< BMLoop *, 3 > > looptris
float no[3]
struct BMVert * v
struct BMFace * f
struct BMLoop * next
float co[3]
float no[3]
CustomData ldata
int totface
CustomDataLayer * layers
mikk::float3 GetNormal(const uint face_num, const uint vert_index)
mikk::float3 GetPosition(const uint face_num, const uint vert_index)
mikk::float3 GetTexCoord(const uint face_num, const uint vert_index)
const BMLoop * GetLoop(const uint face_num, uint vert_index)
Span< std::array< BMLoop *, 3 > > looptris
uint GetNumVerticesOfFace(const uint face_num)
void SetTangentSpace(const uint face_num, const uint vert_index, mikk::float3 T, bool orientation)