Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/editmesh_tangent.cc
| Show All 14 Lines | |||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_editmesh_tangent.h" | #include "BKE_editmesh_tangent.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_tangent.h" /* for utility functions */ | #include "BKE_mesh_tangent.h" /* for utility functions */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| /* interface */ | /* interface */ | ||||
| #include "mikktspace.h" | #include "mikktspace.hh" | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Tangent Space Calculation | /** \name Tangent Space Calculation | ||||
| * \{ */ | * \{ */ | ||||
| /* Necessary complexity to handle looptri's as quads for correct tangents */ | /* Necessary complexity to handle looptri's as quads for correct tangents */ | ||||
| #define USE_LOOPTRI_DETECT_QUADS | #define USE_LOOPTRI_DETECT_QUADS | ||||
| struct SGLSLEditMeshToTangent { | struct SGLSLEditMeshToTangent { | ||||
| const float (*precomputedFaceNormals)[3]; | uint GetNumFaces() | ||||
| 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); | |||||
| #ifdef USE_LOOPTRI_DETECT_QUADS | #ifdef USE_LOOPTRI_DETECT_QUADS | ||||
| return pMesh->num_face_as_quad_map; | return (uint)num_face_as_quad_map; | ||||
| #else | #else | ||||
| return pMesh->numTessFaces; | return (uint)numTessFaces; | ||||
| #endif | #endif | ||||
| } | } | ||||
| static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) | uint GetNumVerticesOfFace(const uint face_num) | ||||
| { | { | ||||
| #ifdef USE_LOOPTRI_DETECT_QUADS | #ifdef USE_LOOPTRI_DETECT_QUADS | ||||
| SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData); | if (face_as_quad_map) { | ||||
| if (pMesh->face_as_quad_map) { | if (looptris[face_as_quad_map[face_num]][0]->f->len == 4) { | ||||
| const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; | |||||
| if (lt[0]->f->len == 4) { | |||||
| return 4; | return 4; | ||||
| } | } | ||||
| } | } | ||||
| return 3; | return 3; | ||||
| #else | #else | ||||
| UNUSED_VARS(pContext, face_num); | UNUSED_VARS(pContext, face_num); | ||||
| return 3; | return 3; | ||||
| #endif | #endif | ||||
| } | } | ||||
| static void emdm_ts_GetPosition(const SMikkTSpaceContext *pContext, | const BMLoop *GetLoop(const uint face_num, uint vert_index) | ||||
| float r_co[3], | |||||
| const int face_num, | |||||
| const int vert_index) | |||||
| { | { | ||||
| // BLI_assert(vert_index >= 0 && vert_index < 4); | // BLI_assert(vert_index >= 0 && vert_index < 4); | ||||
| SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData); | |||||
| const BMLoop **lt; | const BMLoop **lt; | ||||
| const BMLoop *l; | const BMLoop *l; | ||||
| #ifdef USE_LOOPTRI_DETECT_QUADS | #ifdef USE_LOOPTRI_DETECT_QUADS | ||||
| if (pMesh->face_as_quad_map) { | if (face_as_quad_map) { | ||||
| lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; | lt = looptris[face_as_quad_map[face_num]]; | ||||
| if (lt[0]->f->len == 4) { | if (lt[0]->f->len == 4) { | ||||
| l = bm_loop_at_face_index(lt[0]->f, vert_index); | l = BM_FACE_FIRST_LOOP(lt[0]->f); | ||||
| goto finally; | while (vert_index--) { | ||||
| l = l->next; | |||||
| } | |||||
| return l; | |||||
| } | } | ||||
| /* fall through to regular triangle */ | /* fall through to regular triangle */ | ||||
| } | } | ||||
| else { | else { | ||||
| lt = pMesh->looptris[face_num]; | lt = looptris[face_num]; | ||||
| } | } | ||||
| #else | #else | ||||
| lt = pMesh->looptris[face_num]; | lt = looptris[face_num]; | ||||
| #endif | #endif | ||||
| l = lt[vert_index]; | return 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, | mikk::float3 GetPosition(const uint face_num, const uint vert_index) | ||||
| float r_uv[2], | |||||
| const int face_num, | |||||
| const int vert_index) | |||||
| { | { | ||||
| // BLI_assert(vert_index >= 0 && vert_index < 4); | const BMLoop *l = GetLoop(face_num, vert_index); | ||||
| SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData); | return mikk::float3(l->v->co); | ||||
| 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; | |||||
| } | } | ||||
| /* fall through to regular triangle */ | |||||
| } | |||||
| else { | |||||
| lt = pMesh->looptris[face_num]; | |||||
| } | |||||
| #else | |||||
| lt = pMesh->looptris[face_num]; | |||||
| #endif | |||||
| l = lt[vert_index]; | |||||
| finally: | mikk::float3 GetTexCoord(const uint face_num, const uint vert_index) | ||||
| if (pMesh->cd_loop_uv_offset != -1) { | { | ||||
| const float *uv = BM_ELEM_CD_GET_FLOAT_P(l, pMesh->cd_loop_uv_offset); | const BMLoop *l = GetLoop(face_num, vert_index); | ||||
| copy_v2_v2(r_uv, uv); | 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 { | else { | ||||
| const float *orco = pMesh->orco[BM_elem_index_get(l->v)]; | const float *orco_p = orco[BM_elem_index_get(l->v)]; | ||||
| map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); | float u, v; | ||||
| map_to_sphere(&u, &v, orco_p[0], orco_p[1], orco_p[2]); | |||||
| return mikk::float3(u, v, 1.0f); | |||||
| } | } | ||||
| } | } | ||||
| static void emdm_ts_GetNormal(const SMikkTSpaceContext *pContext, | mikk::float3 GetNormal(const uint face_num, const uint vert_index) | ||||
| float r_no[3], | |||||
| const int face_num, | |||||
| const int vert_index) | |||||
| { | { | ||||
| // BLI_assert(vert_index >= 0 && vert_index < 4); | const BMLoop *l = GetLoop(face_num, vert_index); | ||||
| SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData); | if (precomputedLoopNormals) { | ||||
| const BMLoop **lt; | return mikk::float3(precomputedLoopNormals[BM_elem_index_get(l)]); | ||||
| 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; | |||||
| } | |||||
| /* 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 */ | else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */ | ||||
| if (pMesh->precomputedFaceNormals) { | if (precomputedFaceNormals) { | ||||
| copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]); | return mikk::float3(precomputedFaceNormals[BM_elem_index_get(l->f)]); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(r_no, l->f->no); | return mikk::float3(l->f->no); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(r_no, l->v->no); | return mikk::float3(l->v->no); | ||||
| } | } | ||||
| } | } | ||||
| static void emdm_ts_SetTSpace(const SMikkTSpaceContext *pContext, | void SetTangentSpace(const uint face_num, | ||||
| const float fvTangent[3], | const uint vert_index, | ||||
| const float fSign, | mikk::float3 T, | ||||
| const int face_num, | bool orientation) | ||||
| const int vert_index) | |||||
| { | { | ||||
| // BLI_assert(vert_index >= 0 && vert_index < 4); | const BMLoop *l = GetLoop(face_num, vert_index); | ||||
| SGLSLEditMeshToTangent *pMesh = static_cast<SGLSLEditMeshToTangent *>(pContext->m_pUserData); | float *p_res = tangent[BM_elem_index_get(l)]; | ||||
| const BMLoop **lt; | copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f); | ||||
| 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; | |||||
| } | |||||
| /* fall through to regular triangle */ | |||||
| } | |||||
| else { | |||||
| lt = pMesh->looptris[face_num]; | |||||
| } | } | ||||
| #else | |||||
| lt = pMesh->looptris[face_num]; | |||||
| #endif | |||||
| l = lt[vert_index]; | |||||
| float *pRes; | 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; | |||||
| finally: | #ifdef USE_LOOPTRI_DETECT_QUADS | ||||
| pRes = pMesh->tangent[BM_elem_index_get(l)]; | /* map from 'fake' face index to looptri, | ||||
| copy_v3_v3(pRes, fvTangent); | * quads will point to the first looptri of the quad */ | ||||
| pRes[3] = fSign; | const int *face_as_quad_map; | ||||
| } | int num_face_as_quad_map; | ||||
| #endif | |||||
| }; | |||||
| static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata) | static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata) | ||||
| { | { | ||||
| SGLSLEditMeshToTangent *mesh2tangent = static_cast<SGLSLEditMeshToTangent *>(taskdata); | SGLSLEditMeshToTangent *mesh_data = static_cast<SGLSLEditMeshToTangent *>(taskdata); | ||||
| /* new computation method */ | |||||
| { | mikk::Mikktspace<SGLSLEditMeshToTangent> mikk(*mesh_data); | ||||
| SMikkTSpaceContext sContext{}; | mikk.genTangSpace(); | ||||
| 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); | |||||
| } | |||||
| } | } | ||||
| void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, | void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, | ||||
| bool calc_active_tangent, | bool calc_active_tangent, | ||||
| const char (*tangent_names)[MAX_NAME], | const char (*tangent_names)[MAX_NAME], | ||||
| int tangent_names_len, | int tangent_names_len, | ||||
| const float (*poly_normals)[3], | const float (*poly_normals)[3], | ||||
| const float (*loop_normals)[3], | const float (*loop_normals)[3], | ||||
| ▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | #endif | ||||
| tangent_mask_curr |= 1 << (uv_ind - uv_start); | tangent_mask_curr |= 1 << (uv_ind - uv_start); | ||||
| } | } | ||||
| if (mesh2tangent->precomputedFaceNormals) { | if (mesh2tangent->precomputedFaceNormals) { | ||||
| /* needed for face normal lookups */ | /* needed for face normal lookups */ | ||||
| htype_index |= BM_FACE; | htype_index |= BM_FACE; | ||||
| } | } | ||||
| BM_mesh_elem_index_ensure(bm, htype_index); | 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); | mesh2tangent->tangent = static_cast<float(*)[4]>(loopdata_out->layers[index].data); | ||||
| BLI_task_pool_push( | BLI_task_pool_push( | ||||
| task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, nullptr); | task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, nullptr); | ||||
| } | } | ||||
| BLI_assert(tangent_mask_curr == tangent_mask); | BLI_assert(tangent_mask_curr == tangent_mask); | ||||
| BLI_task_pool_work_and_wait(task_pool); | BLI_task_pool_work_and_wait(task_pool); | ||||
| Show All 32 Lines | |||||