Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh_tangent.cc
| Show All 21 Lines | |||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_runtime.h" | #include "BKE_mesh_runtime.h" | ||||
| #include "BKE_mesh_tangent.h" | #include "BKE_mesh_tangent.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BLI_strict_flags.h" | #include "BLI_strict_flags.h" | ||||
| #include "atomic_ops.h" | #include "atomic_ops.h" | ||||
| #include "mikktspace.h" | #include "mikktspace.hh" | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Mesh Tangent Calculations (Single Layer) | /** \name Mesh Tangent Calculations (Single Layer) | ||||
| * \{ */ | * \{ */ | ||||
| /* Tangent space utils. */ | |||||
| /* User data. */ | |||||
| struct BKEMeshToTangent { | struct BKEMeshToTangent { | ||||
| const MPoly *mpolys; /* faces */ | uint GetNumFaces() | ||||
| const MLoop *mloops; /* faces's vertices */ | |||||
| const MVert *mverts; /* vertices */ | |||||
| const MLoopUV *luvs; /* texture coordinates */ | |||||
| const float (*lnors)[3]; /* loops' normals */ | |||||
| float (*tangents)[4]; /* output tangents */ | |||||
| 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 (uint)num_polys; | ||||
| return p_mesh->num_polys; | |||||
| } | } | ||||
| static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx) | uint GetNumVerticesOfFace(const uint face_num) | ||||
| { | { | ||||
| BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData); | return (uint)mpolys[face_num].totloop; | ||||
| return p_mesh->mpolys[face_idx].totloop; | |||||
| } | } | ||||
| static void get_position(const SMikkTSpaceContext *pContext, | mikk::float3 GetPosition(const uint face_num, const uint vert_num) | ||||
| float r_co[3], | |||||
| const int face_idx, | |||||
| const int vert_idx) | |||||
| { | { | ||||
| BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData); | const uint loop_idx = (uint)mpolys[face_num].loopstart + vert_num; | ||||
| const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx; | return mikk::float3(mverts[mloops[loop_idx].v].co); | ||||
| copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co); | |||||
| } | } | ||||
| static void get_texture_coordinate(const SMikkTSpaceContext *pContext, | mikk::float3 GetTexCoord(const uint face_num, const uint vert_num) | ||||
| float r_uv[2], | |||||
| const int face_idx, | |||||
| const int vert_idx) | |||||
| { | { | ||||
| BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData); | const float *uv = luvs[(uint)mpolys[face_num].loopstart + vert_num].uv; | ||||
| copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv); | return mikk::float3(uv[0], uv[1], 1.0f); | ||||
| } | } | ||||
| static void get_normal(const SMikkTSpaceContext *pContext, | mikk::float3 GetNormal(const uint face_num, const uint vert_num) | ||||
| float r_no[3], | |||||
| const int face_idx, | |||||
| const int vert_idx) | |||||
| { | { | ||||
| BKEMeshToTangent *p_mesh = static_cast<BKEMeshToTangent *>(pContext->m_pUserData); | return mikk::float3(lnors[(uint)mpolys[face_num].loopstart + vert_num]); | ||||
| copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]); | |||||
| } | } | ||||
| static void set_tspace(const SMikkTSpaceContext *pContext, | void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation) | ||||
| 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 = tangents[(uint)mpolys[face_num].loopstart + vert_num]; | ||||
| float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx]; | copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f); | ||||
| copy_v3_v3(p_res, fv_tangent); | |||||
| p_res[3] = face_sign; | |||||
| } | } | ||||
| const MPoly *mpolys; /* faces */ | |||||
| const MLoop *mloops; /* faces's vertices */ | |||||
| const MVert *mverts; /* vertices */ | |||||
| const MLoopUV *luvs; /* texture coordinates */ | |||||
| const float (*lnors)[3]; /* loops' normals */ | |||||
| float (*tangents)[4]; /* output tangents */ | |||||
| int num_polys; /* number of polygons */ | |||||
| }; | |||||
| void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts, | void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts, | ||||
HooglyBoogly: The [[ https://wiki.blender.org/wiki/Style_Guide/C_Cpp#Class_Layout | style guide ]] mentions… | |||||
| const int UNUSED(numVerts), | const int UNUSED(numVerts), | ||||
| const MLoop *mloops, | const MLoop *mloops, | ||||
| float (*r_looptangent)[4], | float (*r_looptangent)[4], | ||||
| const float (*loopnors)[3], | const float (*loopnors)[3], | ||||
| const MLoopUV *loopuvs, | const MLoopUV *loopuvs, | ||||
| const int UNUSED(numLoops), | const int UNUSED(numLoops), | ||||
| const MPoly *mpolys, | const MPoly *mpolys, | ||||
| const int numPolys, | const int numPolys, | ||||
| ReportList *reports) | 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. */ | /* Compute Mikktspace's tangent normals. */ | ||||
Not Done Inline ActionsBTW, the timer is usually created with a macro SCOPED_TIMER(__func__); which takes care of the naming for you HooglyBoogly: BTW, the timer is usually created with a macro `SCOPED_TIMER(__func__);` which takes care of… | |||||
| BKEMeshToTangent mesh_to_tangent; | |||||
| mesh_to_tangent.mpolys = mpolys; | mesh_to_tangent.mpolys = mpolys; | ||||
| mesh_to_tangent.mloops = mloops; | mesh_to_tangent.mloops = mloops; | ||||
| mesh_to_tangent.mverts = mverts; | mesh_to_tangent.mverts = mverts; | ||||
| mesh_to_tangent.luvs = loopuvs; | mesh_to_tangent.luvs = loopuvs; | ||||
| mesh_to_tangent.lnors = loopnors; | mesh_to_tangent.lnors = loopnors; | ||||
| mesh_to_tangent.tangents = r_looptangent; | mesh_to_tangent.tangents = r_looptangent; | ||||
| mesh_to_tangent.num_polys = numPolys; | mesh_to_tangent.num_polys = numPolys; | ||||
| s_context.m_pUserData = &mesh_to_tangent; | mikk::Mikktspace<BKEMeshToTangent> mikk(mesh_to_tangent); | ||||
| s_context.m_pInterface = &s_interface; | |||||
| s_interface.m_getNumFaces = get_num_faces; | /* First check we do have a tris/quads only mesh. */ | ||||
| s_interface.m_getNumVerticesOfFace = get_num_verts_of_face; | for (int i = 0; i < numPolys; i++) { | ||||
| s_interface.m_getPosition = get_position; | if (mpolys[i].totloop > 4) { | ||||
| s_interface.m_getTexCoord = get_texture_coordinate; | BKE_report( | ||||
| s_interface.m_getNormal = get_normal; | reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting"); | ||||
| s_interface.m_setTSpaceBasic = set_tspace; | return; | ||||
| 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.genTangSpace(); | |||||
| } | } | ||||
| void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, | void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, | ||||
| const char *uvmap, | const char *uvmap, | ||||
| float (*r_looptangents)[4], | float (*r_looptangents)[4], | ||||
| ReportList *reports) | ReportList *reports) | ||||
| { | { | ||||
| const MLoopUV *loopuvs; | const MLoopUV *loopuvs; | ||||
| Show All 38 Lines | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Mesh Tangent Calculations (All Layers) | /** \name Mesh Tangent Calculations (All Layers) | ||||
| * \{ */ | * \{ */ | ||||
| /* 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 SGLSLMeshToTangent { | struct SGLSLMeshToTangent { | ||||
| const float (*precomputedFaceNormals)[3]; | uint GetNumFaces() | ||||
| 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); | |||||
| #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 dm_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 | ||||
| SGLSLMeshToTangent *pMesh = static_cast<SGLSLMeshToTangent *>(pContext->m_pUserData); | if (face_as_quad_map) { | ||||
| if (pMesh->face_as_quad_map) { | const MLoopTri *lt = &looptri[face_as_quad_map[face_num]]; | ||||
| const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; | const MPoly *mp = &mpoly[lt->poly]; | ||||
| const MPoly *mp = &pMesh->mpoly[lt->poly]; | |||||
| if (mp->totloop == 4) { | if (mp->totloop == 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 dm_ts_GetPosition(const SMikkTSpaceContext *pContext, | uint GetLoop(const uint face_num, const uint vert_num, const MLoopTri *<) | ||||
| 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; | |||||
| #ifdef USE_LOOPTRI_DETECT_QUADS | #ifdef USE_LOOPTRI_DETECT_QUADS | ||||
| if (pMesh->face_as_quad_map) { | if (face_as_quad_map) { | ||||
| lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; | lt = &looptri[face_as_quad_map[face_num]]; | ||||
| const MPoly *mp = &pMesh->mpoly[lt->poly]; | const MPoly *mp = &mpoly[lt->poly]; | ||||
| if (mp->totloop == 4) { | if (mp->totloop == 4) { | ||||
| loop_index = (uint)(mp->loopstart + vert_index); | return ((uint)mp->loopstart + vert_num); | ||||
| goto finally; | |||||
| } | } | ||||
| /* fall through to regular triangle */ | /* fall through to regular triangle */ | ||||
| } | } | ||||
| else { | else { | ||||
| lt = &pMesh->looptri[face_num]; | lt = &looptri[face_num]; | ||||
| } | } | ||||
| #else | #else | ||||
| lt = &pMesh->looptri[face_num]; | lt = &looptri[face_num]; | ||||
| #endif | #endif | ||||
| loop_index = lt->tri[vert_index]; | return lt->tri[vert_num]; | ||||
| finally: | |||||
| co = pMesh->mvert[pMesh->mloop[loop_index].v].co; | |||||
| copy_v3_v3(r_co, co); | |||||
| } | } | ||||
| static void dm_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext, | mikk::float3 GetPosition(const uint face_num, const uint vert_num) | ||||
| 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; | const MLoopTri *lt; | ||||
| uint loop_index; | 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; | |||||
| } | |||||
| /* 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: | mikk::float3 GetTexCoord(const uint face_num, const uint vert_num) | ||||
| if (pMesh->mloopuv != nullptr) { | { | ||||
| const float *uv = pMesh->mloopuv[loop_index].uv; | const MLoopTri *lt; | ||||
| copy_v2_v2(r_uv, uv); | 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 { | else { | ||||
| const float *orco = pMesh->orco[pMesh->mloop[loop_index].v]; | const float *l_orco = orco[mloop[loop_index].v]; | ||||
| map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); | float u, v; | ||||
| map_to_sphere(&u, &v, l_orco[0], l_orco[1], l_orco[2]); | |||||
| return mikk::float3(u, v, 1.0f); | |||||
| } | } | ||||
| } | } | ||||
| static void dm_ts_GetNormal(const SMikkTSpaceContext *pContext, | mikk::float3 GetNormal(const uint face_num, const uint vert_num) | ||||
| 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; | const MLoopTri *lt; | ||||
| uint loop_index; | uint loop_index = GetLoop(face_num, vert_num, lt); | ||||
| if (precomputedLoopNormals) { | |||||
| #ifdef USE_LOOPTRI_DETECT_QUADS | return mikk::float3(precomputedLoopNormals[loop_index]); | ||||
| 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 { | else if ((mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */ | ||||
| lt = &pMesh->looptri[face_num]; | if (precomputedFaceNormals) { | ||||
| } | return mikk::float3(precomputedFaceNormals[lt->poly]); | ||||
| #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]); | |||||
| } | } | ||||
| else { | else { | ||||
| #ifdef USE_LOOPTRI_DETECT_QUADS | #ifdef USE_LOOPTRI_DETECT_QUADS | ||||
| const MPoly *mp = &pMesh->mpoly[lt->poly]; | const MPoly *mp = &mpoly[lt->poly]; | ||||
| float normal[3]; | |||||
| if (mp->totloop == 4) { | if (mp->totloop == 4) { | ||||
| normal_quad_v3(r_no, | normal_quad_v3(normal, | ||||
| pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co, | mvert[mloop[mp->loopstart + 0].v].co, | ||||
| pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co, | mvert[mloop[mp->loopstart + 1].v].co, | ||||
| pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co, | mvert[mloop[mp->loopstart + 2].v].co, | ||||
| pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co); | mvert[mloop[mp->loopstart + 3].v].co); | ||||
| } | } | ||||
| else | else | ||||
| #endif | #endif | ||||
| { | { | ||||
| normal_tri_v3(r_no, | normal_tri_v3(normal, | ||||
| pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co, | mvert[mloop[lt->tri[0]].v].co, | ||||
| pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co, | mvert[mloop[lt->tri[1]].v].co, | ||||
| pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co); | mvert[mloop[lt->tri[2]].v].co); | ||||
| } | } | ||||
| return mikk::float3(normal); | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(r_no, pMesh->vert_normals[pMesh->mloop[loop_index].v]); | return mikk::float3(vert_normals[mloop[loop_index].v]); | ||||
| } | } | ||||
| } | } | ||||
| static void dm_ts_SetTSpace(const SMikkTSpaceContext *pContext, | void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation) | ||||
| 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; | const MLoopTri *lt; | ||||
| uint loop_index; | uint loop_index = GetLoop(face_num, vert_num, lt); | ||||
| #ifdef USE_LOOPTRI_DETECT_QUADS | copy_v4_fl4(tangent[loop_index], T.x, T.y, T.z, orientation ? 1.0f : -1.0f); | ||||
| 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]; | |||||
| } | |||||
| #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: | #ifdef USE_LOOPTRI_DETECT_QUADS | ||||
| pRes = pMesh->tangent[loop_index]; | /* 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 DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata) | static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata) | ||||
| { | { | ||||
| SGLSLMeshToTangent *mesh2tangent = static_cast<SGLSLMeshToTangent *>(taskdata); | SGLSLMeshToTangent *mesh_data = 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 */ | mikk::Mikktspace<SGLSLMeshToTangent> mikk(*mesh_data); | ||||
| genTangSpaceDefault(&sContext); | mikk.genTangSpace(); | ||||
| } | |||||
| } | } | ||||
| void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data, | void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data, | ||||
| CustomData *tan_data, | CustomData *tan_data, | ||||
| int numLoopData, | int numLoopData, | ||||
| const char *layer_name) | const char *layer_name) | ||||
| { | { | ||||
| if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && | if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && | ||||
| ▲ Show 20 Lines • Show All 291 Lines • Show Last 20 Lines | |||||
The style guide mentions that member variables should be declared before functions.
Also, I'm not sure if there's a reason you used uint, but the style guide mentions to use signed integers and just use assertions to check for non-negative values if necessary.