diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-05-09 01:50:45 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-05-09 03:26:36 +0300 |
commit | faba1e7d6e3fb510adf3c5507049598141d6e730 (patch) | |
tree | 581acdd8a0bcac498cbcee21cd045b4017a84602 /source | |
parent | 54af61440eb1eeb2ab30edb71c351fa9182395c4 (diff) |
DWM: Tangent support for editmesh
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_editmesh_tangent.h | 40 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/editderivedmesh.c | 382 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/editmesh_tangent.c | 419 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_mesh.c | 164 |
5 files changed, 573 insertions, 434 deletions
diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h new file mode 100644 index 00000000000..7d6839a4e6a --- /dev/null +++ b/source/blender/blenkernel/BKE_editmesh_tangent.h @@ -0,0 +1,40 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Joseph Eagar. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_EDITMESH_TANGENT_H__ +#define __BKE_EDITMESH_TANGENT_H__ + +/** \file BKE_editmesh_tangent.h + * \ingroup bke + */ + +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 *dm_loopdata_out, + const uint dm_loopdata_out_len, + char *tangent_mask_curr_p); + +#endif /* __BKE_EDITMESH_TANGENT_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 9fa6b7cc3cf..1acc45c9f00 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -103,6 +103,7 @@ set(SRC intern/editderivedmesh.c intern/editmesh.c intern/editmesh_bvh.c + intern/editmesh_tangent.c intern/effect.c intern/fcurve.c intern/fluidsim.c @@ -232,6 +233,7 @@ set(SRC BKE_dynamicpaint.h BKE_editmesh.h BKE_editmesh_bvh.h + BKE_editmesh_tangent.h BKE_effect.h BKE_fcurve.h BKE_fluidsim.h diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 19a27499ff0..320299d1933 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -50,6 +50,7 @@ #include "BKE_mesh.h" #include "BKE_editmesh.h" #include "BKE_editmesh_bvh.h" +#include "BKE_editmesh_tangent.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -238,383 +239,24 @@ static void emDM_calcLoopNormalsSpaceArray( #endif } - -/** \name Tangent Space Calculation - * \{ */ - -/* Necessary complexity to handle looptri's as quads for correct tangents */ -#define USE_LOOPTRI_DETECT_QUADS - -typedef struct { - 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 - -} SGLSLEditMeshToTangent; - -#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 - -/* interface */ -#include "mikktspace.h" - -static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) -{ - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - -#ifdef USE_LOOPTRI_DETECT_QUADS - return pMesh->num_face_as_quad_map; -#else - return pMesh->numTessFaces; -#endif -} - -static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) -{ -#ifdef USE_LOOPTRI_DETECT_QUADS - SGLSLEditMeshToTangent *pMesh = 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) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - 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]; - - 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) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - 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: - if (pMesh->cd_loop_uv_offset != -1) { - const float *uv = BM_ELEM_CD_GET_VOID_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]); - } -} - -static void emdm_ts_GetNormal( - const SMikkTSpaceContext *pContext, float r_no[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - 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: - 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)]); - } - else { - copy_v3_v3(r_no, l->f->no); - } - } - else { - copy_v3_v3(r_no, l->v->no); - } -} - -static void emdm_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); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - 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]; - - 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, int UNUSED(threadid)) -{ - struct SGLSLEditMeshToTangent *mesh2tangent = taskdata; - /* new computation method */ - { - SMikkTSpaceContext sContext = {NULL}; - SMikkTSpaceInterface sInterface = {NULL}; - 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; - /* 0 if failed */ - genTangSpaceDefault(&sContext); - } -} - -/** - * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data. - * - * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`. - * This is done because #CD_TANGENT is cache data used only for drawing. - */ - static void emDM_calc_loop_tangents( DerivedMesh *dm, bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], int tangent_names_count) + const char (*tangent_names)[MAX_NAME], int tangent_names_len) { EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; BMEditMesh *em = bmdm->em; - BMesh *bm = bmdm->em->bm; - if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0) - return; - - int act_uv_n = -1; - int ren_uv_n = -1; - bool calc_act = false; - bool calc_ren = false; - char act_uv_name[MAX_NAME]; - char ren_uv_name[MAX_NAME]; - char tangent_mask = 0; - - DM_calc_loop_tangents_step_0( - &bm->ldata, calc_active_tangent, tangent_names, tangent_names_count, - &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); - - if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) { - for (int i = 0; i < tangent_names_count; i++) - if (tangent_names[i][0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]); - if (calc_act && act_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name); - if (calc_ren && ren_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name); - int totface = em->tottri; -#ifdef USE_LOOPTRI_DETECT_QUADS - int num_face_as_quad_map; - int *face_as_quad_map = NULL; - - /* map faces to quads */ - if (bmdm->em->tottri != bm->totface) { - /* over alloc, since we dont know how many ngon or quads we have */ - - /* map fake face index to looptri */ - face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__); - int i, j; - for (i = 0, j = 0; j < totface; i++, j++) { - face_as_quad_map[i] = j; - /* step over all quads */ - if (em->looptris[j][0]->f->len == 4) { - j++; /* skips the nest looptri */ - } - } - num_face_as_quad_map = i; - } - else { - num_face_as_quad_map = totface; - } -#endif - /* Calculation */ - { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL); - - dm->tangent_mask = 0; - /* Calculate tangent layers */ - SGLSLEditMeshToTangent data_array[MAX_MTFACE]; - int index = 0; - int n = 0; - CustomData_update_typemap(&dm->loopData); - const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT); - for (n = 0; n < tangent_layer_num; n++) { - index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n); - BLI_assert(n < MAX_MTFACE); - SGLSLEditMeshToTangent *mesh2tangent = &data_array[n]; - mesh2tangent->numTessFaces = em->tottri; -#ifdef USE_LOOPTRI_DETECT_QUADS - mesh2tangent->face_as_quad_map = face_as_quad_map; - mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; -#endif - mesh2tangent->precomputedFaceNormals = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */ - /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), - * have to check this is valid... - */ - mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL); - mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n); - - /* needed for indexing loop-tangents */ - int htype_index = BM_LOOP; - if (mesh2tangent->cd_loop_uv_offset == -1) { - mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO); - if (!mesh2tangent->orco) - continue; - /* needed for orco lookups */ - htype_index |= BM_VERT; - } - if (mesh2tangent->precomputedFaceNormals) { - /* needed for face normal lookups */ - htype_index |= BM_FACE; - } - BM_mesh_elem_index_ensure(bm, htype_index); - - mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris; - mesh2tangent->tangent = dm->loopData.layers[index].data; - - /* Fill the resulting tangent_mask */ - int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name); - int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV); - BLI_assert(uv_ind != -1 && uv_start != -1); - BLI_assert(uv_ind - uv_start < MAX_MTFACE); - dm->tangent_mask |= 1 << (uv_ind - uv_start); - BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); - } - - BLI_assert(dm->tangent_mask == tangent_mask); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - } -#ifdef USE_LOOPTRI_DETECT_QUADS - if (face_as_quad_map) { - MEM_freeN(face_as_quad_map); - } -#undef USE_LOOPTRI_DETECT_QUADS -#endif - } - /* Update active layer index */ - int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n); - int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name); - CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index); - - /* Update render layer index */ - uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n); - tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name); - CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index); + const float (*poly_normals)[3] = bmdm->polyNos; + const float (*loop_normals)[3] = CustomData_get_layer(&dm->loopData, CD_NORMAL); + const float (*vert_orco)[3] = dm->getVertDataArray(dm, CD_ORCO); /* can be NULL */ + BKE_editmesh_loop_tangent_calc( + em, calc_active_tangent, + tangent_names, tangent_names_len, + poly_normals, loop_normals, + vert_orco, + &dm->loopData, dm->numLoopData, + &dm->tangent_mask); } -/** \} */ - static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm)) { diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c new file mode 100644 index 00000000000..501ddb10d4f --- /dev/null +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -0,0 +1,419 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/editmesh_tangent.c + * \ingroup bke + */ + +#include "BLI_math.h" +#include "BLI_task.h" + +#include "BKE_DerivedMesh.h" + +#include "BKE_mesh.h" +#include "BKE_editmesh.h" +#include "BKE_editmesh_tangent.h" + +#include "MEM_guardedalloc.h" + +/* interface */ +#include "mikktspace.h" + +/** \name Tangent Space Calculation + * \{ */ + +/* Necessary complexity to handle looptri's as quads for correct tangents */ +#define USE_LOOPTRI_DETECT_QUADS + +typedef struct { + 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 + +} SGLSLEditMeshToTangent; + +#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 = pContext->m_pUserData; + +#ifdef USE_LOOPTRI_DETECT_QUADS + return pMesh->num_face_as_quad_map; +#else + return pMesh->numTessFaces; +#endif +} + +static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ +#ifdef USE_LOOPTRI_DETECT_QUADS + SGLSLEditMeshToTangent *pMesh = 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) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + 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]; + + 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) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + 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: + if (pMesh->cd_loop_uv_offset != -1) { + const float *uv = BM_ELEM_CD_GET_VOID_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]); + } +} + +static void emdm_ts_GetNormal( + const SMikkTSpaceContext *pContext, float r_no[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + 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: + 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)]); + } + else { + copy_v3_v3(r_no, l->f->no); + } + } + else { + copy_v3_v3(r_no, l->v->no); + } +} + +static void emdm_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); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + 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]; + + 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, int UNUSED(threadid)) +{ + struct SGLSLEditMeshToTangent *mesh2tangent = taskdata; + /* new computation method */ + { + SMikkTSpaceContext sContext = {NULL}; + SMikkTSpaceInterface sInterface = {NULL}; + 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; + /* 0 if failed */ + genTangSpaceDefault(&sContext); + } +} + +/** + * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data. + * + * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`. + * This is done because #CD_TANGENT is cache data used only for drawing. + */ +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], + /* result */ + CustomData *loopdata_out, + const uint loopdata_out_len, + char *tangent_mask_curr_p) +{ + BMesh *bm = em->bm; + if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0) + return; + + int act_uv_n = -1; + int ren_uv_n = -1; + bool calc_act = false; + bool calc_ren = false; + char act_uv_name[MAX_NAME]; + char ren_uv_name[MAX_NAME]; + char tangent_mask = 0; + char tangent_mask_curr = *tangent_mask_curr_p; + + DM_calc_loop_tangents_step_0( + &bm->ldata, calc_active_tangent, tangent_names, tangent_names_len, + &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); + + if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) { + for (int i = 0; i < tangent_names_len; i++) + if (tangent_names[i][0]) + DM_add_named_tangent_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, tangent_names[i]); + if (calc_act && act_uv_name[0]) + DM_add_named_tangent_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, act_uv_name); + if (calc_ren && ren_uv_name[0]) + DM_add_named_tangent_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, ren_uv_name); + int totface = em->tottri; +#ifdef USE_LOOPTRI_DETECT_QUADS + int num_face_as_quad_map; + int *face_as_quad_map = NULL; + + /* map faces to quads */ + if (em->tottri != bm->totface) { + /* over alloc, since we dont know how many ngon or quads we have */ + + /* map fake face index to looptri */ + face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__); + int i, j; + for (i = 0, j = 0; j < totface; i++, j++) { + face_as_quad_map[i] = j; + /* step over all quads */ + if (em->looptris[j][0]->f->len == 4) { + j++; /* skips the nest looptri */ + } + } + num_face_as_quad_map = i; + } + else { + num_face_as_quad_map = totface; + } +#endif + /* Calculation */ + { + TaskScheduler *scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool; + task_pool = BLI_task_pool_create(scheduler, NULL); + + tangent_mask_curr = 0; + /* Calculate tangent layers */ + SGLSLEditMeshToTangent data_array[MAX_MTFACE]; + int index = 0; + int n = 0; + CustomData_update_typemap(loopdata_out); + const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT); + for (n = 0; n < tangent_layer_num; n++) { + index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n); + BLI_assert(n < MAX_MTFACE); + SGLSLEditMeshToTangent *mesh2tangent = &data_array[n]; + mesh2tangent->numTessFaces = em->tottri; +#ifdef USE_LOOPTRI_DETECT_QUADS + mesh2tangent->face_as_quad_map = face_as_quad_map; + mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; +#endif + mesh2tangent->precomputedFaceNormals = poly_normals; /* dm->getPolyDataArray(dm, CD_NORMAL) */ + /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), + * have to check this is valid... + */ + mesh2tangent->precomputedLoopNormals = loop_normals; + mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n); + + /* needed for indexing loop-tangents */ + int htype_index = BM_LOOP; + if (mesh2tangent->cd_loop_uv_offset == -1) { + mesh2tangent->orco = vert_orco; + if (!mesh2tangent->orco) + continue; + /* needed for orco lookups */ + htype_index |= BM_VERT; + } + if (mesh2tangent->precomputedFaceNormals) { + /* needed for face normal lookups */ + htype_index |= BM_FACE; + } + BM_mesh_elem_index_ensure(bm, htype_index); + + mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris; + mesh2tangent->tangent = loopdata_out->layers[index].data; + + /* Fill the resulting tangent_mask */ + int uv_ind = CustomData_get_named_layer_index( + &bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name); + int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV); + BLI_assert(uv_ind != -1 && uv_start != -1); + BLI_assert(uv_ind - uv_start < MAX_MTFACE); + tangent_mask_curr |= 1 << (uv_ind - uv_start); + BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); + } + + BLI_assert(tangent_mask_curr == tangent_mask); + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); + } +#ifdef USE_LOOPTRI_DETECT_QUADS + if (face_as_quad_map) { + MEM_freeN(face_as_quad_map); + } +#undef USE_LOOPTRI_DETECT_QUADS +#endif + } + + *tangent_mask_curr_p = tangent_mask_curr; + + /* Update active layer index */ + int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n); + int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[uv_index].name); + CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index); + + /* Update render layer index */ + uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n); + tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[uv_index].name); + CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index); +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index a9d54da9d08..fabb0a3f3a0 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -43,6 +43,7 @@ #include "BKE_deform.h" #include "BKE_DerivedMesh.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_tangent.h" #include "BKE_mesh.h" #include "BKE_texture.h" @@ -153,9 +154,16 @@ typedef struct MeshRenderData { int bweight; int *uv; int *vcol; - int *tangent; +// int *tangent; } cd_offset; + /* for certain cases we need an output loop-data storage (bmesh tangents) */ + struct { + CustomData ldata; + /* grr, special case variable (use in place of 'dm->tangent_mask') */ + char tangent_mask; + } cd_output; + char (*auto_names)[32]; char (*uv_names)[32]; char (*vcol_names)[32]; @@ -223,6 +231,8 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) rdata->types = types; rdata->mat_len = mesh_render_mat_len_get(me); + CustomData_reset(&rdata->cd_output.ldata); + if (me->edit_btmesh) { BMEditMesh *embm = me->edit_btmesh; BMesh *bm = embm->bm; @@ -334,8 +344,46 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) } if (types & MR_DATATYPE_SHADING) { - rdata->uv_len = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); - rdata->vcol_len = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); + CustomData *cd_vdata, *cd_ldata; + + if (me->edit_btmesh) { + BMesh *bm = me->edit_btmesh->bm; + cd_vdata = &bm->vdata; + cd_ldata = &bm->ldata; + } + else { + cd_vdata = &me->vdata; + cd_ldata = &me->ldata; + } + + rdata->orco = CustomData_get_layer(cd_vdata, CD_ORCO); + /* If orco is not available compute it ourselves */ + if (!rdata->orco) { + if (me->edit_btmesh) { + BMesh *bm = me->edit_btmesh->bm; + rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh"); + BLI_assert((bm->elem_table_dirty & BM_VERT) == 0); + BMVert **vtable = bm->vtable; + for (int i = 0; i < bm->totvert; i++) { + copy_v3_v3(rdata->orco[i], vtable[i]->co); + } + BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0); + } + else { + rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh"); + MVert *mvert = rdata->mvert; + for (int a = 0; a < rdata->vert_len; a++, mvert++) { + copy_v3_v3(rdata->orco[a], mvert->co); + } + BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0); + } + } + + /* don't access mesh directly, instead use vars taken from BMesh or Mesh */ +#define me DONT_USE_THIS + + rdata->uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV); + rdata->vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL); rdata->mloopuv = MEM_mallocN(sizeof(*rdata->mloopuv) * rdata->uv_len, "rdata->mloopuv"); rdata->mloopcol = MEM_mallocN(sizeof(*rdata->mloopcol) * rdata->vcol_len, "rdata->mloopcol"); @@ -347,7 +395,6 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) rdata->cd_offset.uv = MEM_mallocN(sizeof(*rdata->cd_offset.uv) * rdata->uv_len, "rdata->uv_ofs"); rdata->cd_offset.vcol = MEM_mallocN(sizeof(*rdata->cd_offset.vcol) * rdata->vcol_len, "rdata->vcol_ofs"); - rdata->cd_offset.tangent = MEM_mallocN(sizeof(*rdata->cd_offset.tangent) * rdata->uv_len, "rdata->tangent_ofs"); /* Allocate max */ rdata->auto_vcol = MEM_callocN( @@ -363,32 +410,32 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) * to a safe glsl var name, but without name clash. * NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */ for (int i = 0; i < rdata->vcol_len; ++i) { - const char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, i); + const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i); unsigned int hash = BLI_ghashutil_strhash_p(name); BLI_snprintf(rdata->vcol_names[i], sizeof(*rdata->vcol_names), "c%u", hash); - rdata->mloopcol[i] = CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, i); + rdata->mloopcol[i] = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); if (rdata->edit_bmesh) { rdata->cd_offset.vcol[i] = CustomData_get_n_offset(&rdata->edit_bmesh->bm->ldata, CD_MLOOPCOL, i); } /* Gather number of auto layers. */ /* We only do vcols that are not overridden by uvs */ - if (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPUV, name) == -1) { + if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) { BLI_snprintf(rdata->auto_names[rdata->uv_len + i], sizeof(*rdata->auto_names), "a%u", hash); rdata->auto_vcol[i] = true; } } /* Start Fresh */ - CustomData_free_layers(&me->ldata, CD_MLOOPTANGENT, me->totloop); + CustomData_free_layers(cd_ldata, CD_MLOOPTANGENT, rdata->loop_len); for (int i = 0; i < rdata->uv_len; ++i) { - const char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, i); + const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i); unsigned int hash = BLI_ghashutil_strhash_p(name); { /* UVs */ BLI_snprintf(rdata->uv_names[i], sizeof(*rdata->uv_names), "u%u", hash); - rdata->mloopuv[i] = CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, i); + rdata->mloopuv[i] = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i); if (rdata->edit_bmesh) { rdata->cd_offset.uv[i] = CustomData_get_n_offset(&rdata->edit_bmesh->bm->ldata, CD_MLOOPUV, i); } @@ -400,70 +447,64 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) BLI_snprintf(rdata->tangent_names[i], sizeof(*rdata->tangent_names), "t%u", hash); if (rdata->edit_bmesh) { -#if 0 /* TODO Waiting for the port of emDM_calc_loop_tangents */ - BMesh *bm = rdata->edit_bmesh->bm; - - float (*loopnors)[3] = CustomData_get_layer(&bm->ldata, CD_NORMAL); + BMEditMesh *em = rdata->edit_bmesh; + BMesh *bm = em->bm; + + if (!CustomData_has_layer(&rdata->cd_output.ldata, CD_MLOOPTANGENT)) { + bool calc_active_tangent = false; + float (*poly_normals)[3] = rdata->poly_normals; + float (*loop_normals)[3] = CustomData_get_layer(cd_ldata, CD_NORMAL); + char tangent_names[MAX_MTFACE][MAX_NAME]; + int tangent_names_len = 0; + for (tangent_names_len = 0; tangent_names_len < rdata->uv_len; tangent_names_len++) { + BLI_strncpy( + tangent_names[tangent_names_len], + CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, tangent_names_len), MAX_NAME); + } - rdata->mtangent[i] = CustomData_add_layer( - &bm->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, bm->totloop); - CustomData_set_layer_flag(&bm->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY); + BKE_editmesh_loop_tangent_calc( + em, calc_active_tangent, + tangent_names, tangent_names_len, + poly_normals, loop_normals, + rdata->orco, + &rdata->cd_output.ldata, bm->totloop, + &rdata->cd_output.tangent_mask); + } - BKE_mesh_loop_tangents_ex(bm->mvert, bm->totvert, bm->mloop, rdata->mtangent[i], - loopnors, rdata->mloopuv[i], bm->totloop, bm->mpoly, bm->totpoly, NULL); + /* note: BKE_editmesh_loop_tangent_calc calculates 'CD_TANGENT', + * not 'CD_MLOOPTANGENT' (as done below). It's OK, they're compatible. */ + rdata->mtangent[i] = CustomData_get_layer_n(&rdata->cd_output.ldata, CD_TANGENT, i); + BLI_assert(rdata->mtangent[i] != NULL); - rdata->tangent_ofs[i] = CustomData_get_n_offset(&bm->ldata, CD_MLOOPTANGENT, i); -#else - rdata->cd_offset.tangent[i] = -1; -#endif + /* special case, we don't use offsets here */ } else { - if (!CustomData_has_layer(&me->ldata, CD_NORMAL)) { +#undef me + if (!CustomData_has_layer(cd_ldata, CD_NORMAL)) { BKE_mesh_calc_normals_split(me); } - float (*loopnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL); + float (*loopnors)[3] = CustomData_get_layer(cd_ldata, CD_NORMAL); rdata->mtangent[i] = CustomData_add_layer( - &me->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, me->totloop); - CustomData_set_layer_flag(&me->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY); + cd_ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, me->totloop); + CustomData_set_layer_flag(cd_ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY); BKE_mesh_loop_tangents_ex(me->mvert, me->totvert, me->mloop, rdata->mtangent[i], loopnors, rdata->mloopuv[i], me->totloop, me->mpoly, me->totpoly, NULL); +#define me DONT_USE_THIS } } } rdata->uv_active = CustomData_get_active_layer_index( - &me->ldata, CD_MLOOPUV) - CustomData_get_layer_index(&me->ldata, CD_MLOOPUV); + cd_ldata, CD_MLOOPUV) - CustomData_get_layer_index(cd_ldata, CD_MLOOPUV); rdata->vcol_active = CustomData_get_active_layer_index( - &me->ldata, CD_MLOOPCOL) - CustomData_get_layer_index(&me->ldata, CD_MLOOPCOL); + cd_ldata, CD_MLOOPCOL) - CustomData_get_layer_index(cd_ldata, CD_MLOOPCOL); rdata->tangent_active = CustomData_get_active_layer_index( - &me->ldata, CD_MLOOPTANGENT) - CustomData_get_layer_index(&me->ldata, CD_MLOOPTANGENT); - - rdata->orco = CustomData_get_layer(&me->vdata, CD_ORCO); + cd_ldata, CD_MLOOPTANGENT) - CustomData_get_layer_index(cd_ldata, CD_MLOOPTANGENT); - /* If orco is not available compute it ourselves */ - if (!rdata->orco) { - if (me->edit_btmesh) { - BMesh *bm = me->edit_btmesh->bm; - rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh"); - BLI_assert((bm->elem_table_dirty & BM_VERT) == 0); - BMVert **vtable = bm->vtable; - for (int i = 0; i < bm->totvert; i++) { - copy_v3_v3(rdata->orco[i], vtable[i]->co); - } - BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0); - } - else { - rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh"); - MVert *mvert = rdata->mvert; - for (int a = 0; a < rdata->vert_len; a++, mvert++) { - copy_v3_v3(rdata->orco[a], mvert->co); - } - BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0); - } - } +#undef me } return rdata; @@ -475,7 +516,6 @@ static void mesh_render_data_free(MeshRenderData *rdata) MEM_SAFE_FREE(rdata->auto_names); MEM_SAFE_FREE(rdata->cd_offset.uv); MEM_SAFE_FREE(rdata->cd_offset.vcol); - MEM_SAFE_FREE(rdata->cd_offset.tangent); MEM_SAFE_FREE(rdata->orco); MEM_SAFE_FREE(rdata->mloopuv); MEM_SAFE_FREE(rdata->mloopcol); @@ -493,6 +533,9 @@ static void mesh_render_data_free(MeshRenderData *rdata) MEM_SAFE_FREE(rdata->vert_weight_color); MEM_SAFE_FREE(rdata->edge_selection); MEM_SAFE_FREE(rdata->vert_color); + + CustomData_free(&rdata->cd_output.ldata, rdata->loop_len); + MEM_freeN(rdata); } @@ -1108,17 +1151,10 @@ static void mesh_render_data_looptri_tans_get( float *(*r_vert_tans)[3]) { if (rdata->edit_bmesh) { -#if 0 /* waiting for edit mesh tangent calculation */ const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx]; - (*r_vert_tans)[0] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[0], rdata->cd_offset.tangent[tangent_layer])); - (*r_vert_tans)[1] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[1], rdata->cd_offset.tangent[tangent_layer])); - (*r_vert_tans)[2] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[2], rdata->cd_offset.tangent[tangent_layer])); -#else - static float tan[4] = {0.0f}; - (*r_vert_tans)[0] = tan; - (*r_vert_tans)[1] = tan; - (*r_vert_tans)[2] = tan; -#endif + (*r_vert_tans)[0] = rdata->mtangent[tangent_layer][BM_elem_index_get(bm_looptri[0])]; + (*r_vert_tans)[1] = rdata->mtangent[tangent_layer][BM_elem_index_get(bm_looptri[1])]; + (*r_vert_tans)[2] = rdata->mtangent[tangent_layer][BM_elem_index_get(bm_looptri[2])]; } else { const MLoopTri *mlt = &rdata->mlooptri[tri_idx]; |