Blender  V3.3
editmesh_tangent.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "BLI_math.h"
8 #include "BLI_task.h"
9 
10 #include "DNA_customdata_types.h"
11 #include "DNA_defs.h"
12 #include "DNA_meshdata_types.h"
13 
14 #include "BKE_customdata.h"
15 #include "BKE_editmesh.h"
16 #include "BKE_editmesh_tangent.h"
17 #include "BKE_mesh.h"
18 #include "BKE_mesh_tangent.h" /* for utility functions */
19 
20 #include "MEM_guardedalloc.h"
21 
22 /* interface */
23 #include "mikktspace.h"
24 
25 /* -------------------------------------------------------------------- */
29 /* Necessary complexity to handle looptri's as quads for correct tangents */
30 #define USE_LOOPTRI_DETECT_QUADS
31 
32 typedef struct {
33  const float (*precomputedFaceNormals)[3];
34  const float (*precomputedLoopNormals)[3];
35  const BMLoop *(*looptris)[3];
36  int cd_loop_uv_offset; /* texture coordinates */
37  const float (*orco)[3];
38  float (*tangent)[4]; /* destination */
40 
41 #ifdef USE_LOOPTRI_DETECT_QUADS
42  /* map from 'fake' face index to looptri,
43  * quads will point to the first looptri of the quad */
44  const int *face_as_quad_map;
46 #endif
47 
49 
50 #ifdef USE_LOOPTRI_DETECT_QUADS
51 /* seems weak but only used on quads */
52 static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
53 {
54  const BMLoop *l = BM_FACE_FIRST_LOOP(f);
55  while (vert_index--) {
56  l = l->next;
57  }
58  return l;
59 }
60 #endif
61 
62 static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
63 {
64  SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
65 
66 #ifdef USE_LOOPTRI_DETECT_QUADS
67  return pMesh->num_face_as_quad_map;
68 #else
69  return pMesh->numTessFaces;
70 #endif
71 }
72 
73 static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
74 {
75 #ifdef USE_LOOPTRI_DETECT_QUADS
76  SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
77  if (pMesh->face_as_quad_map) {
78  const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
79  if (lt[0]->f->len == 4) {
80  return 4;
81  }
82  }
83  return 3;
84 #else
85  UNUSED_VARS(pContext, face_num);
86  return 3;
87 #endif
88 }
89 
90 static void emdm_ts_GetPosition(const SMikkTSpaceContext *pContext,
91  float r_co[3],
92  const int face_num,
93  const int vert_index)
94 {
95  // BLI_assert(vert_index >= 0 && vert_index < 4);
96  SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
97  const BMLoop **lt;
98  const BMLoop *l;
99 
100 #ifdef USE_LOOPTRI_DETECT_QUADS
101  if (pMesh->face_as_quad_map) {
102  lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
103  if (lt[0]->f->len == 4) {
104  l = bm_loop_at_face_index(lt[0]->f, vert_index);
105  goto finally;
106  }
107  /* fall through to regular triangle */
108  }
109  else {
110  lt = pMesh->looptris[face_num];
111  }
112 #else
113  lt = pMesh->looptris[face_num];
114 #endif
115  l = lt[vert_index];
116 
117  const float *co;
118 
119 finally:
120  co = l->v->co;
121  copy_v3_v3(r_co, co);
122 }
123 
125  float r_uv[2],
126  const int face_num,
127  const int vert_index)
128 {
129  // BLI_assert(vert_index >= 0 && vert_index < 4);
130  SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
131  const BMLoop **lt;
132  const BMLoop *l;
133 
134 #ifdef USE_LOOPTRI_DETECT_QUADS
135  if (pMesh->face_as_quad_map) {
136  lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
137  if (lt[0]->f->len == 4) {
138  l = bm_loop_at_face_index(lt[0]->f, vert_index);
139  goto finally;
140  }
141  /* fall through to regular triangle */
142  }
143  else {
144  lt = pMesh->looptris[face_num];
145  }
146 #else
147  lt = pMesh->looptris[face_num];
148 #endif
149  l = lt[vert_index];
150 
151 finally:
152  if (pMesh->cd_loop_uv_offset != -1) {
153  const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
154  copy_v2_v2(r_uv, uv);
155  }
156  else {
157  const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
158  map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
159  }
160 }
161 
162 static void emdm_ts_GetNormal(const SMikkTSpaceContext *pContext,
163  float r_no[3],
164  const int face_num,
165  const int vert_index)
166 {
167  // BLI_assert(vert_index >= 0 && vert_index < 4);
168  SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
169  const BMLoop **lt;
170  const BMLoop *l;
171 
172 #ifdef USE_LOOPTRI_DETECT_QUADS
173  if (pMesh->face_as_quad_map) {
174  lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
175  if (lt[0]->f->len == 4) {
176  l = bm_loop_at_face_index(lt[0]->f, vert_index);
177  goto finally;
178  }
179  /* fall through to regular triangle */
180  }
181  else {
182  lt = pMesh->looptris[face_num];
183  }
184 #else
185  lt = pMesh->looptris[face_num];
186 #endif
187  l = lt[vert_index];
188 
189 finally:
190  if (pMesh->precomputedLoopNormals) {
192  }
193  else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
194  if (pMesh->precomputedFaceNormals) {
196  }
197  else {
198  copy_v3_v3(r_no, l->f->no);
199  }
200  }
201  else {
202  copy_v3_v3(r_no, l->v->no);
203  }
204 }
205 
206 static void emdm_ts_SetTSpace(const SMikkTSpaceContext *pContext,
207  const float fvTangent[3],
208  const float fSign,
209  const int face_num,
210  const int vert_index)
211 {
212  // BLI_assert(vert_index >= 0 && vert_index < 4);
213  SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
214  const BMLoop **lt;
215  const BMLoop *l;
216 
217 #ifdef USE_LOOPTRI_DETECT_QUADS
218  if (pMesh->face_as_quad_map) {
219  lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
220  if (lt[0]->f->len == 4) {
221  l = bm_loop_at_face_index(lt[0]->f, vert_index);
222  goto finally;
223  }
224  /* fall through to regular triangle */
225  }
226  else {
227  lt = pMesh->looptris[face_num];
228  }
229 #else
230  lt = pMesh->looptris[face_num];
231 #endif
232  l = lt[vert_index];
233 
234  float *pRes;
235 
236 finally:
237  pRes = pMesh->tangent[BM_elem_index_get(l)];
238  copy_v3_v3(pRes, fvTangent);
239  pRes[3] = fSign;
240 }
241 
242 static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata)
243 {
244  struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
245  /* new computation method */
246  {
247  SMikkTSpaceContext sContext = {NULL};
248  SMikkTSpaceInterface sInterface = {NULL};
249  sContext.m_pUserData = mesh2tangent;
250  sContext.m_pInterface = &sInterface;
251  sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
253  sInterface.m_getPosition = emdm_ts_GetPosition;
255  sInterface.m_getNormal = emdm_ts_GetNormal;
256  sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
257  /* 0 if failed */
258  genTangSpaceDefault(&sContext);
259  }
260 }
261 
263  bool calc_active_tangent,
264  const char (*tangent_names)[MAX_NAME],
265  int tangent_names_len,
266  const float (*poly_normals)[3],
267  const float (*loop_normals)[3],
268  const float (*vert_orco)[3],
269  /* result */
270  CustomData *loopdata_out,
271  const uint loopdata_out_len,
272  short *tangent_mask_curr_p)
273 {
274  BMesh *bm = em->bm;
275 
276  int act_uv_n = -1;
277  int ren_uv_n = -1;
278  bool calc_act = false;
279  bool calc_ren = false;
280  char act_uv_name[MAX_NAME];
281  char ren_uv_name[MAX_NAME];
282  short tangent_mask = 0;
283  short tangent_mask_curr = *tangent_mask_curr_p;
284 
286  calc_active_tangent,
287  tangent_names,
288  tangent_names_len,
289  &calc_act,
290  &calc_ren,
291  &act_uv_n,
292  &ren_uv_n,
293  act_uv_name,
294  ren_uv_name,
295  &tangent_mask);
296 
297  if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
298  for (int i = 0; i < tangent_names_len; i++) {
299  if (tangent_names[i][0]) {
301  &bm->ldata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
302  }
303  }
304  if ((tangent_mask & DM_TANGENT_MASK_ORCO) &&
305  CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1) {
307  loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
308  }
309  if (calc_act && act_uv_name[0]) {
311  &bm->ldata, loopdata_out, (int)loopdata_out_len, act_uv_name);
312  }
313  if (calc_ren && ren_uv_name[0]) {
315  &bm->ldata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
316  }
317  int totface = em->tottri;
318 #ifdef USE_LOOPTRI_DETECT_QUADS
320  int *face_as_quad_map = NULL;
321 
322  /* map faces to quads */
323  if (em->tottri != bm->totface) {
324  /* Over allocate, since we don't know how many ngon or quads we have. */
325 
326  /* map fake face index to looptri */
327  face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
328  int i, j;
329  for (i = 0, j = 0; j < totface; i++, j++) {
330  face_as_quad_map[i] = j;
331  /* step over all quads */
332  if (em->looptris[j][0]->f->len == 4) {
333  j++; /* skips the nest looptri */
334  }
335  }
337  }
338  else {
339  num_face_as_quad_map = totface;
340  }
341 #endif
342  /* Calculation */
343  if (em->tottri != 0) {
346 
347  tangent_mask_curr = 0;
348  /* Calculate tangent layers */
350  int index = 0;
351  int n = 0;
352  CustomData_update_typemap(loopdata_out);
353  const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
354  for (n = 0; n < tangent_layer_num; n++) {
355  index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
356  BLI_assert(n < MAX_MTFACE);
357  SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
358  mesh2tangent->numTessFaces = em->tottri;
359 #ifdef USE_LOOPTRI_DETECT_QUADS
360  mesh2tangent->face_as_quad_map = face_as_quad_map;
362 #endif
363  mesh2tangent->precomputedFaceNormals = poly_normals;
364  /* NOTE: we assume we do have tessellated loop normals at this point
365  * (in case it is object-enabled), have to check this is valid. */
366  mesh2tangent->precomputedLoopNormals = loop_normals;
368 
369  /* needed for indexing loop-tangents */
370  int htype_index = BM_LOOP;
371  if (mesh2tangent->cd_loop_uv_offset == -1) {
372  mesh2tangent->orco = vert_orco;
373  if (!mesh2tangent->orco) {
374  continue;
375  }
376  /* needed for orco lookups */
377  htype_index |= BM_VERT;
378  tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
379  }
380  else {
381  /* Fill the resulting tangent_mask */
383  &bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name);
384  int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
385  BLI_assert(uv_ind != -1 && uv_start != -1);
386  BLI_assert(uv_ind - uv_start < MAX_MTFACE);
387  tangent_mask_curr |= 1 << (uv_ind - uv_start);
388  }
389  if (mesh2tangent->precomputedFaceNormals) {
390  /* needed for face normal lookups */
391  htype_index |= BM_FACE;
392  }
393  BM_mesh_elem_index_ensure(bm, htype_index);
394 
395  mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
396  mesh2tangent->tangent = loopdata_out->layers[index].data;
397 
399  }
400 
401  BLI_assert(tangent_mask_curr == tangent_mask);
404  }
405  else {
406  tangent_mask_curr = tangent_mask;
407  }
408 #ifdef USE_LOOPTRI_DETECT_QUADS
409  if (face_as_quad_map) {
411  }
412 # undef USE_LOOPTRI_DETECT_QUADS
413 #endif
414  }
415 
416  *tangent_mask_curr_p = tangent_mask_curr;
417 
418  int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
419  if (act_uv_index >= 0) {
420  int tan_index = CustomData_get_named_layer_index(
421  loopdata_out, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
422  CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
423  } /* else tangent has been built from orco */
424 
425  /* Update render layer index */
426  int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
427  if (ren_uv_index >= 0) {
428  int tan_index = CustomData_get_named_layer_index(
429  loopdata_out, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
430  CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
431  } /* else tangent has been built from orco */
432 }
433 
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
int CustomData_number_of_layers(const struct CustomData *data, int type)
@ CD_CALLOC
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name)
void CustomData_set_layer_render_index(struct CustomData *data, int type, int n)
Definition: customdata.cc:2590
int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n)
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.cc:2792
int CustomData_get_layer_index(const struct CustomData *data, int type)
void CustomData_set_layer_active_index(struct CustomData *data, int type, int n)
Definition: customdata.cc:2578
int CustomData_get_n_offset(const struct CustomData *data, int type, int n)
void CustomData_update_typemap(struct CustomData *data)
Definition: customdata.cc:2193
#define DM_TANGENT_MASK_ORCO
void BKE_mesh_add_loop_tangent_named_layer_for_uv(struct CustomData *uv_data, struct CustomData *tan_data, int numLoopData, const char *layer_name)
Definition: mesh_tangent.c:448
void BKE_mesh_calc_loop_tangent_step_0(const struct CustomData *loopData, bool calc_active_tangent, const char(*tangent_names)[64], 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:46
void map_to_sphere(float *r_u, float *r_v, float x, float y, float z)
Definition: math_geom.c:4932
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:67
@ TASK_PRIORITY_HIGH
Definition: BLI_task.h:57
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition: task_pool.cc:480
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition: task_pool.cc:390
void BLI_task_pool_free(TaskPool *pool)
Definition: task_pool.cc:440
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition: task_pool.cc:459
#define UNUSED_VARS(...)
#define UNUSED(x)
@ CD_MLOOPUV
@ CD_TANGENT
#define MAX_MTFACE
#define MAX_NAME
Definition: DNA_defs.h:48
Read Guarded memory(de)allocation.
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_LOOP
Definition: bmesh_class.h:385
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
ATTR_WARN_UNUSED_RESULT const BMLoop * l
static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata)
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, bool calc_active_tangent, const char(*tangent_names)[MAX_NAME], int tangent_names_len, const float(*poly_normals)[3], const float(*loop_normals)[3], const float(*vert_orco)[3], CustomData *loopdata_out, const uint loopdata_out_len, short *tangent_mask_curr_p)
static void emdm_ts_GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_num, const int vert_index)
static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
static const BMLoop * bm_loop_at_face_index(const BMFace *f, int vert_index)
static void emdm_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_num, const int vert_index)
static void emdm_ts_SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, const int face_num, const int vert_index)
static void emdm_ts_GetPosition(const SMikkTSpaceContext *pContext, float r_co[3], const int face_num, const int vert_index)
TaskPool * task_pool
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
tbool genTangSpaceDefault(const SMikkTSpaceContext *pContext)
Definition: mikktspace.c:253
struct BMLoop *(* looptris)[3]
Definition: BKE_editmesh.h:48
struct BMesh * bm
Definition: BKE_editmesh.h:40
int len
Definition: bmesh_class.h:267
float no[3]
Definition: bmesh_class.h:271
struct BMVert * v
Definition: bmesh_class.h:153
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
float no[3]
Definition: bmesh_class.h:88
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
CustomDataLayer * layers
const float(* precomputedFaceNormals)[3]
const BMLoop *(* looptris)[3]
const float(* orco)[3]
const float(* precomputedLoopNormals)[3]
SMikkTSpaceInterface * m_pInterface
Definition: mikktspace.h:112
void(* m_getNormal)(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert)
Definition: mikktspace.h:61
void(* m_getPosition)(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert)
Definition: mikktspace.h:57
void(* m_getTexCoord)(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert)
Definition: mikktspace.h:65
void(* m_setTSpaceBasic)(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert)
Definition: mikktspace.h:82
int(* m_getNumFaces)(const SMikkTSpaceContext *pContext)
Definition: mikktspace.h:49
int(* m_getNumVerticesOfFace)(const SMikkTSpaceContext *pContext, const int iFace)
Definition: mikktspace.h:53