Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorLukas Stockner <lukasstockner97>2022-09-03 18:21:44 +0300
committerLukas Stockner <lukas.stockner@freenet.de>2022-09-07 01:35:44 +0300
commit6951e8890ae3d0923e377cff6023d78202d81a03 (patch)
tree3d7a3230f79078aa2ab2e852d6f8ce9d908f28ac /source
parent6b6428fcbcc7b210e6d3dcf51df9c6de3070a9db (diff)
Mikktspace: Optimized port to C++
This commit is a big overhaul to the Mikktspace module, which is used to compute tangents. I'm not calling it a rewrite since it's the result of a lot of iterations on the original code, but pretty much everything is reworked somehow. Overall goal was to a) make it faster and b) make it maintainable. Notable changes: - Since the callbacks for requesting geometry data were a big bottleneck before, I've ported it to C++ and made it header-only, templating on the data source. That way, the compiler generates code specific to the caller, which allows it to inline the data source and specialize for some cases (e.g. subd vs. non-subd in Cycles). - The one input parameter, an optional angle threshold, was not used anywhere. Turns out that removing it allows for considerable algorithmic simplification, removing a lot of the complexity in the later stages. Therefore, I've just removed the option in the new code. - The code computes several outputs, but only one (the tangent itself) is ever used in Blender. Therefore, I've removed the others to simplify the code. They could easily be brought back if needed, none of the algorithmic simplifications are conflicting with them. - The original code had fallback paths for many steps in case temporary memory allocation fails, but that never actually gets used anyways since malloc() doesn't really ever return NULL in practise, so I removed them. - In general, I've restructured A LOT of the code to make the algorithms clearer and make use of some C++ features (vectors, std::array, booleans, classes), though there's still some of cleanup that could be done. - Parallelized duplicate detection, neighbor detection, triangle tangent computation, degenerate triangle handling and tangent space accumulation. - Replaced several algorithms with faster equivalents: Duplicate detection uses a (concurrent) hash set now, neighbor detection uses Radixsort and splits vertices by index pairs etc. As for results, the exact speedup depends on the scene of course, but let's consider the file from T97378: - Blender 3.1 (before D14675): 6.07sec - Blender 3.2 (with D14675): 4.62sec - rBf0a36599007d (last nightly build): 4.42sec - With this commit: 0.90sec This speedup will mostly be noticed at the start of Cycles renders and, even more importantly, in Eevee when doing something that changes the geometry (e.g. animating) on a model using normal maps. Differential Revision: https://developer.blender.org/D15589
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.cc288
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.cc447
2 files changed, 245 insertions, 490 deletions
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.cc b/source/blender/blenkernel/intern/editmesh_tangent.cc
index 5a01f64826d..a65532d083d 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.cc
+++ b/source/blender/blenkernel/intern/editmesh_tangent.cc
@@ -20,7 +20,7 @@
#include "MEM_guardedalloc.h"
/* interface */
-#include "mikktspace.h"
+#include "mikktspace.hh"
/* -------------------------------------------------------------------- */
/** \name Tangent Space Calculation
@@ -30,233 +30,129 @@
#define USE_LOOPTRI_DETECT_QUADS
struct SGLSLEditMeshToTangent {
- const float (*precomputedFaceNormals)[3];
- const float (*precomputedLoopNormals)[3];
- const BMLoop *(*looptris)[3];
- int cd_loop_uv_offset; /* texture coordinates */
- const float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
-#endif
-};
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-/* seems weak but only used on quads */
-static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
-{
- const BMLoop *l = BM_FACE_FIRST_LOOP(f);
- while (vert_index--) {
- l = l->next;
- }
- return l;
-}
-#endif
-
-static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData);
-
+ uint GetNumFaces()
+ {
#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
+ return (uint)num_face_as_quad_map;
#else
- return pMesh->numTessFaces;
+ return (uint)numTessFaces;
#endif
-}
-
-static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData);
- if (pMesh->face_as_quad_map) {
- const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- return 4;
- }
}
- return 3;
-#else
- UNUSED_VARS(pContext, face_num);
- return 3;
-#endif
-}
-
-static void emdm_ts_GetPosition(const SMikkTSpaceContext *pContext,
- float r_co[3],
- const int face_num,
- const int vert_index)
-{
- // BLI_assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData);
- const BMLoop **lt;
- const BMLoop *l;
+ uint GetNumVerticesOfFace(const uint face_num)
+ {
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
+ if (face_as_quad_map) {
+ if (looptris[face_as_quad_map[face_num]][0]->f->len == 4) {
+ return 4;
+ }
}
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
+ return 3;
#else
- lt = pMesh->looptris[face_num];
+ UNUSED_VARS(pContext, face_num);
+ return 3;
#endif
- l = lt[vert_index];
-
- const float *co;
-
-finally:
- co = l->v->co;
- copy_v3_v3(r_co, co);
-}
+ }
-static void emdm_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext,
- float r_uv[2],
- const int face_num,
- const int vert_index)
-{
- // BLI_assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData);
- const BMLoop **lt;
- const BMLoop *l;
+ const BMLoop *GetLoop(const uint face_num, uint vert_index)
+ {
+ // BLI_assert(vert_index >= 0 && vert_index < 4);
+ const BMLoop **lt;
+ const BMLoop *l;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
+ if (face_as_quad_map) {
+ lt = looptris[face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = BM_FACE_FIRST_LOOP(lt[0]->f);
+ while (vert_index--) {
+ l = l->next;
+ }
+ return l;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = looptris[face_num];
}
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
#else
- lt = pMesh->looptris[face_num];
+ lt = looptris[face_num];
#endif
- l = lt[vert_index];
-
-finally:
- if (pMesh->cd_loop_uv_offset != -1) {
- const float *uv = BM_ELEM_CD_GET_FLOAT_P(l, pMesh->cd_loop_uv_offset);
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ return lt[vert_index];
}
-}
-static void emdm_ts_GetNormal(const SMikkTSpaceContext *pContext,
- float r_no[3],
- const int face_num,
- const int vert_index)
-{
- // BLI_assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData);
- const BMLoop **lt;
- const BMLoop *l;
+ mikk::float3 GetPosition(const uint face_num, const uint vert_index)
+ {
+ const BMLoop *l = GetLoop(face_num, vert_index);
+ return mikk::float3(l->v->co);
+ }
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
+ mikk::float3 GetTexCoord(const uint face_num, const uint vert_index)
+ {
+ const BMLoop *l = GetLoop(face_num, vert_index);
+ if (cd_loop_uv_offset != -1) {
+ const float *uv = (const float *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ return mikk::float3(uv[0], uv[1], 1.0f);
+ }
+ else {
+ const float *orco_p = orco[BM_elem_index_get(l->v)];
+ float u, v;
+ map_to_sphere(&u, &v, orco_p[0], orco_p[1], orco_p[2]);
+ return mikk::float3(u, v, 1.0f);
}
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
}
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
- }
- else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
+ mikk::float3 GetNormal(const uint face_num, const uint vert_index)
+ {
+ const BMLoop *l = GetLoop(face_num, vert_index);
+ if (precomputedLoopNormals) {
+ return mikk::float3(precomputedLoopNormals[BM_elem_index_get(l)]);
+ }
+ else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
+ if (precomputedFaceNormals) {
+ return mikk::float3(precomputedFaceNormals[BM_elem_index_get(l->f)]);
+ }
+ else {
+ return mikk::float3(l->f->no);
+ }
}
else {
- copy_v3_v3(r_no, l->f->no);
+ return mikk::float3(l->v->no);
}
}
- else {
- copy_v3_v3(r_no, l->v->no);
+
+ void SetTangentSpace(const uint face_num,
+ const uint vert_index,
+ mikk::float3 T,
+ bool orientation)
+ {
+ const BMLoop *l = GetLoop(face_num, vert_index);
+ float *p_res = tangent[BM_elem_index_get(l)];
+ copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
}
-}
-static void emdm_ts_SetTSpace(const SMikkTSpaceContext *pContext,
- const float fvTangent[3],
- const float fSign,
- const int face_num,
- const int vert_index)
-{
- // BLI_assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData);
- const BMLoop **lt;
- const BMLoop *l;
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const BMLoop *(*looptris)[3];
+ int cd_loop_uv_offset; /* texture coordinates */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
#endif
- l = lt[vert_index];
-
- float *pRes;
-
-finally:
- pRes = pMesh->tangent[BM_elem_index_get(l)];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
-}
+};
static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
- SGLSLEditMeshToTangent *mesh2tangent = static_cast<SGLSLEditMeshToTangent *>(taskdata);
- /* new computation method */
- {
- SMikkTSpaceContext sContext{};
- SMikkTSpaceInterface sInterface{};
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = emdm_ts_GetPosition;
- sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = emdm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
- sInterface.m_setTSpace = nullptr;
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
+ SGLSLEditMeshToTangent *mesh_data = static_cast<SGLSLEditMeshToTangent *>(taskdata);
+
+ mikk::Mikktspace<SGLSLEditMeshToTangent> mikk(*mesh_data);
+ mikk.genTangSpace();
}
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
@@ -392,7 +288,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
}
BM_mesh_elem_index_ensure(bm, htype_index);
- mesh2tangent->looptris = (const BMLoop *(*)[3])(em->looptris);
+ mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
mesh2tangent->tangent = static_cast<float(*)[4]>(loopdata_out->layers[index].data);
BLI_task_pool_push(
diff --git a/source/blender/blenkernel/intern/mesh_tangent.cc b/source/blender/blenkernel/intern/mesh_tangent.cc
index 4ebc6b74705..003b196107f 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.cc
+++ b/source/blender/blenkernel/intern/mesh_tangent.cc
@@ -27,16 +27,46 @@
#include "BLI_strict_flags.h"
#include "atomic_ops.h"
-#include "mikktspace.h"
+#include "mikktspace.hh"
/* -------------------------------------------------------------------- */
/** \name Mesh Tangent Calculations (Single Layer)
* \{ */
-/* Tangent space utils. */
-
-/* User data. */
struct BKEMeshToTangent {
+ uint GetNumFaces()
+ {
+ return (uint)num_polys;
+ }
+
+ uint GetNumVerticesOfFace(const uint face_num)
+ {
+ return (uint)mpolys[face_num].totloop;
+ }
+
+ mikk::float3 GetPosition(const uint face_num, const uint vert_num)
+ {
+ const uint loop_idx = (uint)mpolys[face_num].loopstart + vert_num;
+ return mikk::float3(mverts[mloops[loop_idx].v].co);
+ }
+
+ mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
+ {
+ const float *uv = luvs[(uint)mpolys[face_num].loopstart + vert_num].uv;
+ return mikk::float3(uv[0], uv[1], 1.0f);
+ }
+
+ mikk::float3 GetNormal(const uint face_num, const uint vert_num)
+ {
+ return mikk::float3(lnors[(uint)mpolys[face_num].loopstart + vert_num]);
+ }
+
+ void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
+ {
+ float *p_res = tangents[(uint)mpolys[face_num].loopstart + vert_num];
+ copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
+ }
+
const MPoly *mpolys; /* faces */
const MLoop *mloops; /* faces's vertices */
const MVert *mverts; /* vertices */
@@ -46,59 +76,6 @@ struct BKEMeshToTangent {
int num_polys; /* number of polygons */
};
-/* Mikktspace's API */
-static int get_num_faces(const SMikkTSpaceContext *pContext)
-{
- BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData);
- return p_mesh->num_polys;
-}
-
-static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
-{
- BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData);
- return p_mesh->mpolys[face_idx].totloop;
-}
-
-static void get_position(const SMikkTSpaceContext *pContext,
- float r_co[3],
- const int face_idx,
- const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData);
- const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
- copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
-}
-
-static void get_texture_coordinate(const SMikkTSpaceContext *pContext,
- float r_uv[2],
- const int face_idx,
- const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData);
- copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
-}
-
-static void get_normal(const SMikkTSpaceContext *pContext,
- float r_no[3],
- const int face_idx,
- const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData);
- copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
-}
-
-static void set_tspace(const SMikkTSpaceContext *pContext,
- const float fv_tangent[3],
- const float face_sign,
- const int face_idx,
- const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData);
- float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
- copy_v3_v3(p_res, fv_tangent);
- p_res[3] = face_sign;
-}
-
void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
const int UNUSED(numVerts),
const MLoop *mloops,
@@ -110,23 +87,8 @@ void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
const int numPolys,
ReportList *reports)
{
- BKEMeshToTangent mesh_to_tangent;
- SMikkTSpaceContext s_context{};
- SMikkTSpaceInterface s_interface{};
-
- const MPoly *mp;
- int mp_index;
-
- /* First check we do have a tris/quads only mesh. */
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- if (mp->totloop > 4) {
- BKE_report(
- reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
- return;
- }
- }
-
/* Compute Mikktspace's tangent normals. */
+ BKEMeshToTangent mesh_to_tangent;
mesh_to_tangent.mpolys = mpolys;
mesh_to_tangent.mloops = mloops;
mesh_to_tangent.mverts = mverts;
@@ -135,20 +97,18 @@ void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
mesh_to_tangent.tangents = r_looptangent;
mesh_to_tangent.num_polys = numPolys;
- s_context.m_pUserData = &mesh_to_tangent;
- s_context.m_pInterface = &s_interface;
- s_interface.m_getNumFaces = get_num_faces;
- s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
- s_interface.m_getPosition = get_position;
- s_interface.m_getTexCoord = get_texture_coordinate;
- s_interface.m_getNormal = get_normal;
- s_interface.m_setTSpaceBasic = set_tspace;
- s_interface.m_setTSpace = nullptr;
-
- /* 0 if failed */
- if (genTangSpaceDefault(&s_context) == false) {
- BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
+ mikk::Mikktspace<BKEMeshToTangent> mikk(mesh_to_tangent);
+
+ /* First check we do have a tris/quads only mesh. */
+ for (int i = 0; i < numPolys; i++) {
+ if (mpolys[i].totloop > 4) {
+ BKE_report(
+ reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
+ return;
+ }
}
+
+ mikk.genTangSpace();
}
void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
@@ -203,248 +163,147 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
#define USE_LOOPTRI_DETECT_QUADS
struct SGLSLMeshToTangent {
- const float (*precomputedFaceNormals)[3];
- const float (*precomputedLoopNormals)[3];
- const MLoopTri *looptri;
- const MLoopUV *mloopuv; /* texture coordinates */
- const MPoly *mpoly; /* indices */
- const MLoop *mloop; /* indices */
- const MVert *mvert; /* vertex coordinates */
- const float (*vert_normals)[3];
- const float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
-#endif
-};
-
-/* interface */
-static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SGLSLMeshToTangent *pMesh = static_cast<SGLSLMeshToTangent *>(pContext->m_pUserData);
-
+ uint GetNumFaces()
+ {
#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
+ return (uint)num_face_as_quad_map;
#else
- return pMesh->numTessFaces;
+ return (uint)numTessFaces;
#endif
-}
-
-static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLMeshToTangent *pMesh = static_cast<SGLSLMeshToTangent *>(pContext->m_pUserData);
- if (pMesh->face_as_quad_map) {
- const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- return 4;
- }
}
- return 3;
-#else
- UNUSED_VARS(pContext, face_num);
- return 3;
-#endif
-}
-
-static void dm_ts_GetPosition(const SMikkTSpaceContext *pContext,
- float r_co[3],
- const int face_num,
- const int vert_index)
-{
- // assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = static_cast<SGLSLMeshToTangent *>(pContext->m_pUserData);
- const MLoopTri *lt;
- uint loop_index;
- const float *co;
+ uint GetNumVerticesOfFace(const uint face_num)
+ {
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = (uint)(mp->loopstart + vert_index);
- goto finally;
+ if (face_as_quad_map) {
+ const MLoopTri *lt = &looptri[face_as_quad_map[face_num]];
+ const MPoly *mp = &mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ return 4;
+ }
}
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
+ return 3;
#else
- lt = &pMesh->looptri[face_num];
+ UNUSED_VARS(pContext, face_num);
+ return 3;
#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
- copy_v3_v3(r_co, co);
-}
-
-static void dm_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext,
- float r_uv[2],
- const int face_num,
- const int vert_index)
-{
- // assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = static_cast<SGLSLMeshToTangent *>(pContext->m_pUserData);
- const MLoopTri *lt;
- uint loop_index;
+ }
+ uint GetLoop(const uint face_num, const uint vert_num, const MLoopTri *&lt)
+ {
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = (uint)(mp->loopstart + vert_index);
- goto finally;
+ if (face_as_quad_map) {
+ lt = &looptri[face_as_quad_map[face_num]];
+ const MPoly *mp = &mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ return ((uint)mp->loopstart + vert_num);
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &looptri[face_num];
}
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
#else
- lt = &pMesh->looptri[face_num];
+ lt = &looptri[face_num];
#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- if (pMesh->mloopuv != nullptr) {
- const float *uv = pMesh->mloopuv[loop_index].uv;
- copy_v2_v2(r_uv, uv);
+ return lt->tri[vert_num];
}
- else {
- const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
-}
-static void dm_ts_GetNormal(const SMikkTSpaceContext *pContext,
- float r_no[3],
- const int face_num,
- const int vert_index)
-{
- // assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = static_cast<SGLSLMeshToTangent *>(pContext->m_pUserData);
- const MLoopTri *lt;
- uint loop_index;
+ mikk::float3 GetPosition(const uint face_num, const uint vert_num)
+ {
+ const MLoopTri *lt;
+ uint loop_index = GetLoop(face_num, vert_num, lt);
+ return mikk::float3(mvert[mloop[loop_index].v].co);
+ }
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = (uint)(mp->loopstart + vert_index);
- goto finally;
+ mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
+ {
+ const MLoopTri *lt;
+ uint loop_index = GetLoop(face_num, vert_num, lt);
+ if (mloopuv != nullptr) {
+ const float *uv = mloopuv[loop_index].uv;
+ return mikk::float3(uv[0], uv[1], 1.0f);
+ }
+ else {
+ const float *l_orco = orco[mloop[loop_index].v];
+ float u, v;
+ map_to_sphere(&u, &v, l_orco[0], l_orco[1], l_orco[2]);
+ return mikk::float3(u, v, 1.0f);
}
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
}
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
- }
- else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
+ mikk::float3 GetNormal(const uint face_num, const uint vert_num)
+ {
+ const MLoopTri *lt;
+ uint loop_index = GetLoop(face_num, vert_num, lt);
+ if (precomputedLoopNormals) {
+ return mikk::float3(precomputedLoopNormals[loop_index]);
}
- else {
-#ifdef USE_LOOPTRI_DETECT_QUADS
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- normal_quad_v3(r_no,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
+ else if ((mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
+ if (precomputedFaceNormals) {
+ return mikk::float3(precomputedFaceNormals[lt->poly]);
}
- else
+ else {
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ const MPoly *mp = &mpoly[lt->poly];
+ float normal[3];
+ if (mp->totloop == 4) {
+ normal_quad_v3(normal,
+ mvert[mloop[mp->loopstart + 0].v].co,
+ mvert[mloop[mp->loopstart + 1].v].co,
+ mvert[mloop[mp->loopstart + 2].v].co,
+ mvert[mloop[mp->loopstart + 3].v].co);
+ }
+ else
#endif
- {
- normal_tri_v3(r_no,
- pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
+ {
+ normal_tri_v3(normal,
+ mvert[mloop[lt->tri[0]].v].co,
+ mvert[mloop[lt->tri[1]].v].co,
+ mvert[mloop[lt->tri[2]].v].co);
+ }
+ return mikk::float3(normal);
}
}
+ else {
+ return mikk::float3(vert_normals[mloop[loop_index].v]);
+ }
}
- else {
- copy_v3_v3(r_no, pMesh->vert_normals[pMesh->mloop[loop_index].v]);
- }
-}
-static void dm_ts_SetTSpace(const SMikkTSpaceContext *pContext,
- const float fvTangent[3],
- const float fSign,
- const int face_num,
- const int vert_index)
-{
- // assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = static_cast<SGLSLMeshToTangent *>(pContext->m_pUserData);
- const MLoopTri *lt;
- uint loop_index;
+ void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
+ {
+ const MLoopTri *lt;
+ uint loop_index = GetLoop(face_num, vert_num, lt);
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = (uint)(mp->loopstart + vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
+ copy_v4_fl4(tangent[loop_index], T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
}
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
- float *pRes;
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const MLoopTri *looptri;
+ const MLoopUV *mloopuv; /* texture coordinates */
+ const MPoly *mpoly; /* indices */
+ const MLoop *mloop; /* indices */
+ const MVert *mvert; /* vertex coordinates */
+ const float (*vert_normals)[3];
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
-finally:
- pRes = pMesh->tangent[loop_index];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
-}
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+};
static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
- SGLSLMeshToTangent *mesh2tangent = static_cast<SGLSLMeshToTangent *>(taskdata);
- /* new computation method */
- {
- SMikkTSpaceContext sContext{};
- SMikkTSpaceInterface sInterface{};
-
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = dm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = dm_ts_GetPosition;
- sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = dm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
- sInterface.m_setTSpace = nullptr;
-
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
+ SGLSLMeshToTangent *mesh_data = static_cast<SGLSLMeshToTangent *>(taskdata);
+
+ mikk::Mikktspace<SGLSLMeshToTangent> mikk(*mesh_data);
+ mikk.genTangSpace();
}
void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data,