Fix T51561: Normal maps fail w/ quad + eevee
Generalize derived-mesh tangent calculation so it can be used by Batch cache creation too.
This commit is contained in:
parent
a6c60affff
commit
429f6bee28
Notes:
blender-bot
2023-02-14 08:45:09 +01:00
Referenced by issue #91171, Blender crashes if simplify is turned on while baking multires Referenced by issue #57664, Crash generating material preview icons with a Normal Map node that uses Tangent Space and specific UV Referenced by issue #51561, Normal maps not working in quad meshes in Eevee
|
@ -785,17 +785,11 @@ void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs);
|
|||
void DM_calc_tangents_names_from_gpu(
|
||||
const struct GPUVertexAttribs *gattribs,
|
||||
char (*tangent_names)[MAX_NAME], int *tangent_names_count);
|
||||
void DM_add_named_tangent_layer_for_uv(
|
||||
CustomData *uv_data, CustomData *tan_data, int numLoopData,
|
||||
const char *layer_name);
|
||||
void DM_calc_loop_tangents_step_0(
|
||||
const CustomData *loopData, bool calc_active_tangent,
|
||||
const char (*tangent_names)[MAX_NAME], int tangent_names_count,
|
||||
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
|
||||
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask);
|
||||
|
||||
void DM_calc_loop_tangents(
|
||||
DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME],
|
||||
int tangent_names_count);
|
||||
|
||||
void DM_calc_auto_bump_scale(DerivedMesh *dm);
|
||||
|
||||
/** Set object's bounding box based on DerivedMesh min/max data */
|
||||
|
|
|
@ -186,13 +186,6 @@ void BKE_mesh_calc_normals_looptri(
|
|||
const struct MLoop *mloop,
|
||||
const struct MLoopTri *looptri, int looptri_num,
|
||||
float (*r_tri_nors)[3]);
|
||||
void BKE_mesh_loop_tangents_ex(
|
||||
const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
|
||||
float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
|
||||
const int numLoops, const struct MPoly *mpolys, const int numPolys,
|
||||
struct ReportList *reports);
|
||||
void BKE_mesh_loop_tangents(
|
||||
struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
|
||||
|
||||
/**
|
||||
* References a contiguous loop-fan with normal offset vars.
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* ***** 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 *****
|
||||
*/
|
||||
#ifndef __BKE_MESH_TANGENT_H__
|
||||
#define __BKE_MESH_TANGENT_H__
|
||||
|
||||
void BKE_mesh_calc_loop_tangent_single_ex(
|
||||
const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
|
||||
float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
|
||||
const int numLoops, const struct MPoly *mpolys, const int numPolys,
|
||||
struct ReportList *reports);
|
||||
void BKE_mesh_calc_loop_tangent_single(
|
||||
struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
|
||||
|
||||
void BKE_mesh_calc_loop_tangent_ex(
|
||||
const struct MVert *mvert,
|
||||
const struct MPoly *mpoly, const uint mpoly_len,
|
||||
const struct MLoop *mloop,
|
||||
const struct MLoopTri *looptri, const uint looptri_len,
|
||||
|
||||
struct CustomData *loopdata,
|
||||
bool calc_active_tangent,
|
||||
const char (*tangent_names)[64], int tangent_names_len,
|
||||
const float (*poly_normals)[3],
|
||||
const float (*loop_normals)[3],
|
||||
const float (*vert_orco)[3],
|
||||
/* result */
|
||||
struct CustomData *loopdata_out,
|
||||
const uint loopdata_out_len,
|
||||
char *tangent_mask_curr_p);
|
||||
|
||||
/* Helpers */
|
||||
void BKE_mesh_add_loop_tangent_named_layer_for_uv(
|
||||
struct CustomData *uv_data, struct CustomData *tan_data, int numLoopData,
|
||||
const char *layer_name);
|
||||
void BKE_mesh_calc_loop_tangent_step_0(
|
||||
const struct CustomData *loopData, bool calc_active_tangent,
|
||||
const char (*tangent_names)[64], int tangent_names_count,
|
||||
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
|
||||
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask);
|
||||
|
||||
#endif /* __BKE_MESH_TANGENT_H__ */
|
||||
|
|
@ -136,6 +136,7 @@ set(SRC
|
|||
intern/mesh_evaluate.c
|
||||
intern/mesh_mapping.c
|
||||
intern/mesh_remap.c
|
||||
intern/mesh_tangent.c
|
||||
intern/mesh_validate.c
|
||||
intern/modifier.c
|
||||
intern/modifiers_bmesh.c
|
||||
|
@ -263,6 +264,7 @@ set(SRC
|
|||
BKE_mesh.h
|
||||
BKE_mesh_mapping.h
|
||||
BKE_mesh_remap.h
|
||||
BKE_mesh_tangent.h
|
||||
BKE_modifier.h
|
||||
BKE_movieclip.h
|
||||
BKE_multires.h
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#include "BKE_modifier.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "BKE_mesh_tangent.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_object_deform.h"
|
||||
#include "BKE_paint.h"
|
||||
|
@ -3038,234 +3039,6 @@ void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int
|
|||
|
||||
/* ******************* GLSL ******************** */
|
||||
|
||||
/** \name Tangent Space Calculation
|
||||
* \{ */
|
||||
|
||||
/* Necessary complexity to handle looptri's as quads for correct tangents */
|
||||
#define USE_LOOPTRI_DETECT_QUADS
|
||||
|
||||
typedef struct {
|
||||
float (*precomputedFaceNormals)[3];
|
||||
float (*precomputedLoopNormals)[3];
|
||||
const MLoopTri *looptri;
|
||||
MLoopUV *mloopuv; /* texture coordinates */
|
||||
MPoly *mpoly; /* indices */
|
||||
MLoop *mloop; /* indices */
|
||||
MVert *mvert; /* vertices & normals */
|
||||
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
|
||||
|
||||
} SGLSLMeshToTangent;
|
||||
|
||||
/* interface */
|
||||
#include "mikktspace.h"
|
||||
|
||||
static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
|
||||
{
|
||||
SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
|
||||
|
||||
#ifdef USE_LOOPTRI_DETECT_QUADS
|
||||
return pMesh->num_face_as_quad_map;
|
||||
#else
|
||||
return pMesh->numTessFaces;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
|
||||
{
|
||||
#ifdef USE_LOOPTRI_DETECT_QUADS
|
||||
SGLSLMeshToTangent *pMesh = 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 = pContext->m_pUserData;
|
||||
const MLoopTri *lt;
|
||||
int loop_index;
|
||||
const float *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 = 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:
|
||||
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 = pContext->m_pUserData;
|
||||
const MLoopTri *lt;
|
||||
int loop_index;
|
||||
|
||||
#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 = 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:
|
||||
if (pMesh->mloopuv != NULL) {
|
||||
const float *uv = pMesh->mloopuv[loop_index].uv;
|
||||
copy_v2_v2(r_uv, uv);
|
||||
}
|
||||
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 = (SGLSLMeshToTangent *) pContext->m_pUserData;
|
||||
const MLoopTri *lt;
|
||||
int loop_index;
|
||||
|
||||
#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 = 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:
|
||||
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 {
|
||||
#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
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
|
||||
normal_short_to_float_v3(r_no, no);
|
||||
}
|
||||
}
|
||||
|
||||
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 = (SGLSLMeshToTangent *) pContext->m_pUserData;
|
||||
const MLoopTri *lt;
|
||||
int loop_index;
|
||||
|
||||
#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 = 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;
|
||||
|
||||
finally:
|
||||
pRes = pMesh->tangent[loop_index];
|
||||
copy_v3_v3(pRes, fvTangent);
|
||||
pRes[3] = fSign;
|
||||
}
|
||||
|
||||
void DM_calc_tangents_names_from_gpu(
|
||||
const GPUVertexAttribs *gattribs,
|
||||
char (*tangent_names)[MAX_NAME], int *r_tangent_names_count)
|
||||
|
@ -3279,241 +3052,30 @@ void DM_calc_tangents_names_from_gpu(
|
|||
*r_tangent_names_count = count;
|
||||
}
|
||||
|
||||
static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
|
||||
{
|
||||
struct SGLSLMeshToTangent *mesh2tangent = taskdata;
|
||||
/* new computation method */
|
||||
{
|
||||
SMikkTSpaceContext sContext = {NULL};
|
||||
SMikkTSpaceInterface sInterface = {NULL};
|
||||
|
||||
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;
|
||||
|
||||
/* 0 if failed */
|
||||
genTangSpaceDefault(&sContext);
|
||||
}
|
||||
}
|
||||
|
||||
void DM_add_named_tangent_layer_for_uv(
|
||||
CustomData *uv_data, CustomData *tan_data, int numLoopData,
|
||||
const char *layer_name)
|
||||
{
|
||||
if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
|
||||
CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
|
||||
{
|
||||
CustomData_add_layer_named(
|
||||
tan_data, CD_TANGENT, CD_CALLOC, NULL,
|
||||
numLoopData, layer_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
|
||||
* Also, we calculate tangent_mask that works as a descriptor of tangents state.
|
||||
* If tangent_mask has changed, then recalculate tangents.
|
||||
*/
|
||||
void DM_calc_loop_tangents_step_0(
|
||||
const CustomData *loopData, bool calc_active_tangent,
|
||||
const char (*tangent_names)[MAX_NAME], int tangent_names_count,
|
||||
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
|
||||
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
|
||||
/* Active uv in viewport */
|
||||
int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
|
||||
*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
|
||||
ract_uv_name[0] = 0;
|
||||
if (*ract_uv_n != -1) {
|
||||
strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
|
||||
}
|
||||
|
||||
/* Active tangent in render */
|
||||
*rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
|
||||
rren_uv_name[0] = 0;
|
||||
if (*rren_uv_n != -1) {
|
||||
strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
|
||||
}
|
||||
|
||||
/* If active tangent not in tangent_names we take it into account */
|
||||
*rcalc_act = false;
|
||||
*rcalc_ren = false;
|
||||
for (int i = 0; i < tangent_names_count; i++) {
|
||||
if (tangent_names[i][0] == 0) {
|
||||
calc_active_tangent = true;
|
||||
}
|
||||
}
|
||||
if (calc_active_tangent) {
|
||||
*rcalc_act = true;
|
||||
*rcalc_ren = true;
|
||||
for (int i = 0; i < tangent_names_count; i++) {
|
||||
if (STREQ(ract_uv_name, tangent_names[i]))
|
||||
*rcalc_act = false;
|
||||
if (STREQ(rren_uv_name, tangent_names[i]))
|
||||
*rcalc_ren = false;
|
||||
}
|
||||
}
|
||||
*rtangent_mask = 0;
|
||||
|
||||
const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
|
||||
for (int n = 0; n < uv_layer_num; n++) {
|
||||
const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
|
||||
bool add = false;
|
||||
for (int i = 0; i < tangent_names_count; i++) {
|
||||
if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
|
||||
add = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
|
||||
(*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
|
||||
{
|
||||
add = true;
|
||||
}
|
||||
if (add)
|
||||
*rtangent_mask |= 1 << n;
|
||||
}
|
||||
}
|
||||
|
||||
void DM_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)
|
||||
{
|
||||
if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0)
|
||||
if (CustomData_number_of_layers(&dm->loopData, 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(
|
||||
&dm->loopData, 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) {
|
||||
/* Check we have all the needed layers */
|
||||
MPoly *mpoly = dm->getPolyArray(dm);
|
||||
const MLoopTri *looptri = dm->getLoopTriArray(dm);
|
||||
int totface = dm->getNumLoopTri(dm);
|
||||
/* Allocate needed tangent layers */
|
||||
for (int i = 0; i < tangent_names_count; i++)
|
||||
if (tangent_names[i][0])
|
||||
DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
|
||||
if (calc_act && act_uv_name[0])
|
||||
DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
|
||||
if (calc_ren && ren_uv_name[0])
|
||||
DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name);
|
||||
|
||||
#ifdef USE_LOOPTRI_DETECT_QUADS
|
||||
int num_face_as_quad_map;
|
||||
int *face_as_quad_map = NULL;
|
||||
|
||||
/* map faces to quads */
|
||||
if (totface != dm->getNumPolys(dm)) {
|
||||
/* 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 k, j;
|
||||
for (k = 0, j = 0; j < totface; k++, j++) {
|
||||
face_as_quad_map[k] = j;
|
||||
/* step over all quads */
|
||||
if (mpoly[looptri[j].poly].totloop == 4) {
|
||||
j++; /* skips the nest looptri */
|
||||
}
|
||||
}
|
||||
num_face_as_quad_map = k;
|
||||
}
|
||||
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 */
|
||||
SGLSLMeshToTangent data_array[MAX_MTFACE];
|
||||
const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
|
||||
for (int n = 0; n < tangent_layer_num; n++) {
|
||||
int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
|
||||
BLI_assert(n < MAX_MTFACE);
|
||||
SGLSLMeshToTangent *mesh2tangent = &data_array[n];
|
||||
mesh2tangent->numTessFaces = totface;
|
||||
#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->mvert = dm->getVertArray(dm);
|
||||
mesh2tangent->mpoly = dm->getPolyArray(dm);
|
||||
mesh2tangent->mloop = dm->getLoopArray(dm);
|
||||
mesh2tangent->looptri = dm->getLoopTriArray(dm);
|
||||
/* 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 = dm->getLoopDataArray(dm, CD_NORMAL);
|
||||
mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->polyData, CD_NORMAL);
|
||||
|
||||
mesh2tangent->orco = NULL;
|
||||
mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
|
||||
if (!mesh2tangent->mloopuv) {
|
||||
mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
|
||||
if (!mesh2tangent->orco)
|
||||
continue;
|
||||
}
|
||||
mesh2tangent->tangent = dm->loopData.layers[index].data;
|
||||
|
||||
/* Fill the resulting tangent_mask */
|
||||
int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
|
||||
int uv_start = CustomData_get_layer_index(&dm->loopData, 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, DM_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
|
||||
|
||||
int uv_index, tan_index;
|
||||
|
||||
/* Update active layer index */
|
||||
uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
|
||||
if (uv_index != -1) {
|
||||
tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.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(&dm->loopData, CD_MLOOPUV, ren_uv_n);
|
||||
if (uv_index != -1) {
|
||||
tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
|
||||
CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_mesh_calc_loop_tangent_ex(
|
||||
dm->getVertArray(dm),
|
||||
dm->getPolyArray(dm), dm->getNumPolys(dm),
|
||||
dm->getLoopArray(dm),
|
||||
dm->getLoopTriArray(dm), dm->getNumLoopTri(dm),
|
||||
&dm->loopData,
|
||||
calc_active_tangent,
|
||||
tangent_names, tangent_names_len,
|
||||
CustomData_get_layer(&dm->polyData, CD_NORMAL),
|
||||
dm->getLoopDataArray(dm, CD_NORMAL),
|
||||
dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */
|
||||
/* result */
|
||||
&dm->loopData, dm->getNumLoops(dm),
|
||||
&dm->tangent_mask);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
void DM_calc_auto_bump_scale(DerivedMesh *dm)
|
||||
{
|
||||
/* int totvert = dm->getNumVerts(dm); */ /* UNUSED */
|
||||
|
|
|
@ -245,6 +245,11 @@ static void emDM_calc_loop_tangents(
|
|||
{
|
||||
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
|
||||
BMEditMesh *em = bmdm->em;
|
||||
|
||||
if (CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "BKE_DerivedMesh.h"
|
||||
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_tangent.h" /* for utility functions */
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_editmesh_tangent.h"
|
||||
|
||||
|
@ -268,7 +269,7 @@ static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), v
|
|||
}
|
||||
|
||||
/**
|
||||
* \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
|
||||
* \see #BKE_mesh_calc_loop_tangent, 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.
|
||||
|
@ -285,8 +286,8 @@ void BKE_editmesh_loop_tangent_calc(
|
|||
char *tangent_mask_curr_p)
|
||||
{
|
||||
BMesh *bm = em->bm;
|
||||
if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0)
|
||||
return;
|
||||
|
||||
BLI_assert(CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) != 0);
|
||||
|
||||
int act_uv_n = -1;
|
||||
int ren_uv_n = -1;
|
||||
|
@ -297,18 +298,18 @@ void BKE_editmesh_loop_tangent_calc(
|
|||
char tangent_mask = 0;
|
||||
char tangent_mask_curr = *tangent_mask_curr_p;
|
||||
|
||||
DM_calc_loop_tangents_step_0(
|
||||
BKE_mesh_calc_loop_tangent_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]);
|
||||
BKE_mesh_add_loop_tangent_named_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);
|
||||
BKE_mesh_add_loop_tangent_named_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);
|
||||
BKE_mesh_add_loop_tangent_named_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;
|
||||
|
|
|
@ -1663,152 +1663,6 @@ void BKE_mesh_normals_loop_to_vertex(
|
|||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Mesh Tangent Calculations
|
||||
* \{ */
|
||||
|
||||
/* Tangent space utils. */
|
||||
|
||||
/* User data. */
|
||||
typedef struct {
|
||||
const MPoly *mpolys; /* faces */
|
||||
const MLoop *mloops; /* faces's vertices */
|
||||
const MVert *mverts; /* vertices */
|
||||
const MLoopUV *luvs; /* texture coordinates */
|
||||
float (*lnors)[3]; /* loops' normals */
|
||||
float (*tangents)[4]; /* output tangents */
|
||||
int num_polys; /* number of polygons */
|
||||
} BKEMeshToTangent;
|
||||
|
||||
/* Mikktspace's API */
|
||||
static int get_num_faces(const SMikkTSpaceContext *pContext)
|
||||
{
|
||||
BKEMeshToTangent *p_mesh = (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 = (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 = (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 = (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 = (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 = (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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
|
||||
* split normals can be used to recreate the full tangent space.
|
||||
* Note: * The mesh should be made of only tris and quads!
|
||||
*/
|
||||
void BKE_mesh_loop_tangents_ex(
|
||||
const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
|
||||
float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
|
||||
const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
|
||||
ReportList *reports)
|
||||
{
|
||||
BKEMeshToTangent mesh_to_tangent = {NULL};
|
||||
SMikkTSpaceContext s_context = {NULL};
|
||||
SMikkTSpaceInterface s_interface = {NULL};
|
||||
|
||||
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. */
|
||||
mesh_to_tangent.mpolys = mpolys;
|
||||
mesh_to_tangent.mloops = mloops;
|
||||
mesh_to_tangent.mverts = mverts;
|
||||
mesh_to_tangent.luvs = loopuvs;
|
||||
mesh_to_tangent.lnors = loopnors;
|
||||
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;
|
||||
|
||||
/* 0 if failed */
|
||||
if (genTangSpaceDefault(&s_context) == false) {
|
||||
BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around BKE_mesh_loop_tangents_ex, which takes care of most boiling code.
|
||||
* \note
|
||||
* - There must be a valid loop's CD_NORMALS available.
|
||||
* - The mesh should be made of only tris and quads!
|
||||
*/
|
||||
void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
|
||||
{
|
||||
MLoopUV *loopuvs;
|
||||
float (*loopnors)[3];
|
||||
|
||||
/* Check we have valid texture coordinates first! */
|
||||
if (uvmap) {
|
||||
loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
|
||||
}
|
||||
else {
|
||||
loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
|
||||
}
|
||||
if (!loopuvs) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
|
||||
return;
|
||||
}
|
||||
|
||||
loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
|
||||
if (!loopnors) {
|
||||
BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_mesh_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
|
||||
loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Polygon Calculations
|
||||
|
|
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/blenkernel/intern/mesh_tangent.c
|
||||
* \ingroup bke
|
||||
*
|
||||
* Functions to evaluate mesh tangents.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_stack.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_tangent.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_strict_flags.h"
|
||||
|
||||
#include "atomic_ops.h"
|
||||
#include "mikktspace.h"
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Mesh Tangent Calculations (Single Layer)
|
||||
* \{ */
|
||||
|
||||
/* Tangent space utils. */
|
||||
|
||||
/* User data. */
|
||||
typedef struct {
|
||||
const MPoly *mpolys; /* faces */
|
||||
const MLoop *mloops; /* faces's vertices */
|
||||
const MVert *mverts; /* vertices */
|
||||
const MLoopUV *luvs; /* texture coordinates */
|
||||
float (*lnors)[3]; /* loops' normals */
|
||||
float (*tangents)[4]; /* output tangents */
|
||||
int num_polys; /* number of polygons */
|
||||
} BKEMeshToTangent;
|
||||
|
||||
/* Mikktspace's API */
|
||||
static int get_num_faces(const SMikkTSpaceContext *pContext)
|
||||
{
|
||||
BKEMeshToTangent *p_mesh = (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 = (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 = (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 = (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 = (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 = (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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
|
||||
* split normals can be used to recreate the full tangent space.
|
||||
* Note: * The mesh should be made of only tris and quads!
|
||||
*/
|
||||
void BKE_mesh_calc_loop_tangent_single_ex(
|
||||
const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
|
||||
float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
|
||||
const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
|
||||
ReportList *reports)
|
||||
{
|
||||
BKEMeshToTangent mesh_to_tangent = {NULL};
|
||||
SMikkTSpaceContext s_context = {NULL};
|
||||
SMikkTSpaceInterface s_interface = {NULL};
|
||||
|
||||
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. */
|
||||
mesh_to_tangent.mpolys = mpolys;
|
||||
mesh_to_tangent.mloops = mloops;
|
||||
mesh_to_tangent.mverts = mverts;
|
||||
mesh_to_tangent.luvs = loopuvs;
|
||||
mesh_to_tangent.lnors = loopnors;
|
||||
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;
|
||||
|
||||
/* 0 if failed */
|
||||
if (genTangSpaceDefault(&s_context) == false) {
|
||||
BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
|
||||
* \note
|
||||
* - There must be a valid loop's CD_NORMALS available.
|
||||
* - The mesh should be made of only tris and quads!
|
||||
*/
|
||||
void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
|
||||
{
|
||||
MLoopUV *loopuvs;
|
||||
float (*loopnors)[3];
|
||||
|
||||
/* Check we have valid texture coordinates first! */
|
||||
if (uvmap) {
|
||||
loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
|
||||
}
|
||||
else {
|
||||
loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
|
||||
}
|
||||
if (!loopuvs) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
|
||||
return;
|
||||
}
|
||||
|
||||
loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
|
||||
if (!loopnors) {
|
||||
BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_mesh_calc_loop_tangent_single_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
|
||||
loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Mesh Tangent Calculations (All Layers)
|
||||
* \{ */
|
||||
|
||||
|
||||
/* 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 MLoopTri *looptri;
|
||||
MLoopUV *mloopuv; /* texture coordinates */
|
||||
const MPoly *mpoly; /* indices */
|
||||
const MLoop *mloop; /* indices */
|
||||
const MVert *mvert; /* vertices & normals */
|
||||
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
|
||||
|
||||
} SGLSLMeshToTangent;
|
||||
|
||||
/* interface */
|
||||
#include "mikktspace.h"
|
||||
|
||||
static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
|
||||
{
|
||||
SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
|
||||
|
||||
#ifdef USE_LOOPTRI_DETECT_QUADS
|
||||
return pMesh->num_face_as_quad_map;
|
||||
#else
|
||||
return pMesh->numTessFaces;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
|
||||
{
|
||||
#ifdef USE_LOOPTRI_DETECT_QUADS
|
||||
SGLSLMeshToTangent *pMesh = 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 = pContext->m_pUserData;
|
||||
const MLoopTri *lt;
|
||||
uint loop_index;
|
||||
const float *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:
|
||||
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 = pContext->m_pUserData;
|
||||
const MLoopTri *lt;
|
||||
uint loop_index;
|
||||
|
||||
#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:
|
||||
if (pMesh->mloopuv != NULL) {
|
||||
const float *uv = pMesh->mloopuv[loop_index].uv;
|
||||
copy_v2_v2(r_uv, uv);
|
||||
}
|
||||
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 = (SGLSLMeshToTangent *) pContext->m_pUserData;
|
||||
const MLoopTri *lt;
|
||||
uint loop_index;
|
||||
|
||||
#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:
|
||||
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 {
|
||||
#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
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
|
||||
normal_short_to_float_v3(r_no, no);
|
||||
}
|
||||
}
|
||||
|
||||
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 = (SGLSLMeshToTangent *) pContext->m_pUserData;
|
||||
const MLoopTri *lt;
|
||||
uint loop_index;
|
||||
|
||||
#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];
|
||||
|
||||
float *pRes;
|
||||
|
||||
finally:
|
||||
pRes = pMesh->tangent[loop_index];
|
||||
copy_v3_v3(pRes, fvTangent);
|
||||
pRes[3] = fSign;
|
||||
}
|
||||
|
||||
static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
|
||||
{
|
||||
struct SGLSLMeshToTangent *mesh2tangent = taskdata;
|
||||
/* new computation method */
|
||||
{
|
||||
SMikkTSpaceContext sContext = {NULL};
|
||||
SMikkTSpaceInterface sInterface = {NULL};
|
||||
|
||||
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;
|
||||
|
||||
/* 0 if failed */
|
||||
genTangSpaceDefault(&sContext);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_mesh_add_loop_tangent_named_layer_for_uv(
|
||||
CustomData *uv_data, CustomData *tan_data, int numLoopData,
|
||||
const char *layer_name)
|
||||
{
|
||||
if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
|
||||
CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
|
||||
{
|
||||
CustomData_add_layer_named(
|
||||
tan_data, CD_TANGENT, CD_CALLOC, NULL,
|
||||
numLoopData, layer_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
|
||||
* Also, we calculate tangent_mask that works as a descriptor of tangents state.
|
||||
* If tangent_mask has changed, then recalculate tangents.
|
||||
*/
|
||||
void BKE_mesh_calc_loop_tangent_step_0(
|
||||
const CustomData *loopData, bool calc_active_tangent,
|
||||
const char (*tangent_names)[MAX_NAME], int tangent_names_count,
|
||||
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
|
||||
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
|
||||
/* Active uv in viewport */
|
||||
int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
|
||||
*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
|
||||
ract_uv_name[0] = 0;
|
||||
if (*ract_uv_n != -1) {
|
||||
strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
|
||||
}
|
||||
|
||||
/* Active tangent in render */
|
||||
*rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
|
||||
rren_uv_name[0] = 0;
|
||||
if (*rren_uv_n != -1) {
|
||||
strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
|
||||
}
|
||||
|
||||
/* If active tangent not in tangent_names we take it into account */
|
||||
*rcalc_act = false;
|
||||
*rcalc_ren = false;
|
||||
for (int i = 0; i < tangent_names_count; i++) {
|
||||
if (tangent_names[i][0] == 0) {
|
||||
calc_active_tangent = true;
|
||||
}
|
||||
}
|
||||
if (calc_active_tangent) {
|
||||
*rcalc_act = true;
|
||||
*rcalc_ren = true;
|
||||
for (int i = 0; i < tangent_names_count; i++) {
|
||||
if (STREQ(ract_uv_name, tangent_names[i]))
|
||||
*rcalc_act = false;
|
||||
if (STREQ(rren_uv_name, tangent_names[i]))
|
||||
*rcalc_ren = false;
|
||||
}
|
||||
}
|
||||
*rtangent_mask = 0;
|
||||
|
||||
const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
|
||||
for (int n = 0; n < uv_layer_num; n++) {
|
||||
const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
|
||||
bool add = false;
|
||||
for (int i = 0; i < tangent_names_count; i++) {
|
||||
if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
|
||||
add = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
|
||||
(*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
|
||||
{
|
||||
add = true;
|
||||
}
|
||||
if (add)
|
||||
*rtangent_mask |= (char)(1 << n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See: #BKE_editmesh_loop_tangent_calc (matching logic).
|
||||
*/
|
||||
void BKE_mesh_calc_loop_tangent_ex(
|
||||
const MVert *mvert,
|
||||
const MPoly *mpoly, const uint mpoly_len,
|
||||
const MLoop *mloop,
|
||||
const MLoopTri *looptri,
|
||||
const uint looptri_len,
|
||||
|
||||
CustomData *loopdata,
|
||||
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)
|
||||
{
|
||||
BLI_assert(CustomData_number_of_layers(loopdata, CD_MLOOPUV) != 0);
|
||||
|
||||
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;
|
||||
|
||||
BKE_mesh_calc_loop_tangent_step_0(
|
||||
loopdata, 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) {
|
||||
/* Check we have all the needed layers */
|
||||
/* Allocate needed tangent layers */
|
||||
for (int i = 0; i < tangent_names_len; i++)
|
||||
if (tangent_names[i][0])
|
||||
BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
|
||||
if (calc_act && act_uv_name[0])
|
||||
BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name);
|
||||
if (calc_ren && ren_uv_name[0])
|
||||
BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
|
||||
|
||||
#ifdef USE_LOOPTRI_DETECT_QUADS
|
||||
int num_face_as_quad_map;
|
||||
int *face_as_quad_map = NULL;
|
||||
|
||||
/* map faces to quads */
|
||||
if (looptri_len != mpoly_len) {
|
||||
/* 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) * looptri_len, __func__);
|
||||
int k, j;
|
||||
for (k = 0, j = 0; j < (int)looptri_len; k++, j++) {
|
||||
face_as_quad_map[k] = j;
|
||||
/* step over all quads */
|
||||
if (mpoly[looptri[j].poly].totloop == 4) {
|
||||
j++; /* skips the nest looptri */
|
||||
}
|
||||
}
|
||||
num_face_as_quad_map = k;
|
||||
}
|
||||
else {
|
||||
num_face_as_quad_map = (int)looptri_len;
|
||||
}
|
||||
#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 */
|
||||
SGLSLMeshToTangent data_array[MAX_MTFACE];
|
||||
const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
|
||||
for (int n = 0; n < tangent_layer_num; n++) {
|
||||
int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
|
||||
BLI_assert(n < MAX_MTFACE);
|
||||
SGLSLMeshToTangent *mesh2tangent = &data_array[n];
|
||||
mesh2tangent->numTessFaces = (int)looptri_len;
|
||||
#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->mvert = mvert;
|
||||
mesh2tangent->mpoly = mpoly;
|
||||
mesh2tangent->mloop = mloop;
|
||||
mesh2tangent->looptri = looptri;
|
||||
/* 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->precomputedFaceNormals = poly_normals;
|
||||
|
||||
mesh2tangent->orco = NULL;
|
||||
mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata->layers[index].name);
|
||||
if (!mesh2tangent->mloopuv) {
|
||||
mesh2tangent->orco = vert_orco;
|
||||
if (!mesh2tangent->orco)
|
||||
continue;
|
||||
}
|
||||
mesh2tangent->tangent = loopdata_out->layers[index].data;
|
||||
|
||||
/* Fill the resulting tangent_mask */
|
||||
int uv_ind = CustomData_get_named_layer_index(
|
||||
loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
|
||||
int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV);
|
||||
BLI_assert(uv_ind != -1 && uv_start != -1);
|
||||
BLI_assert(uv_ind - uv_start < MAX_MTFACE);
|
||||
tangent_mask_curr |= (char)(1 << (uv_ind - uv_start));
|
||||
BLI_task_pool_push(task_pool, DM_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;
|
||||
|
||||
int uv_index, tan_index;
|
||||
|
||||
/* Update active layer index */
|
||||
uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n);
|
||||
if (uv_index != -1) {
|
||||
tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, loopdata->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(loopdata, CD_MLOOPUV, ren_uv_n);
|
||||
if (uv_index != -1) {
|
||||
tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, loopdata->layers[uv_index].name);
|
||||
CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -45,6 +45,7 @@
|
|||
#include "BKE_editmesh.h"
|
||||
#include "BKE_editmesh_tangent.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_tangent.h"
|
||||
#include "BKE_texture.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
@ -497,18 +498,45 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
|
|||
}
|
||||
else {
|
||||
#undef me
|
||||
if (!CustomData_has_layer(cd_ldata, CD_NORMAL)) {
|
||||
BKE_mesh_calc_normals_split(me);
|
||||
|
||||
if (!CustomData_has_layer(&rdata->cd.output.ldata, CD_MLOOPTANGENT)) {
|
||||
if (!CustomData_has_layer(cd_ldata, CD_NORMAL)) {
|
||||
BKE_mesh_calc_normals_split(me);
|
||||
}
|
||||
|
||||
bool calc_active_tangent = false;
|
||||
const float (*poly_normals)[3] = rdata->poly_normals;
|
||||
const 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->cd.layers.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);
|
||||
}
|
||||
|
||||
BKE_mesh_calc_loop_tangent_ex(
|
||||
me->mvert,
|
||||
me->mpoly, me->totpoly,
|
||||
me->mloop,
|
||||
rdata->mlooptri, rdata->tri_len,
|
||||
cd_ldata,
|
||||
calc_active_tangent,
|
||||
tangent_names, tangent_names_len,
|
||||
poly_normals, loop_normals,
|
||||
rdata->orco,
|
||||
&rdata->cd.output.ldata, me->totloop,
|
||||
&rdata->cd.output.tangent_mask);
|
||||
|
||||
/* If we store tangents in the mesh, set temporary. */
|
||||
#if 0
|
||||
CustomData_set_layer_flag(cd_ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
|
||||
#endif
|
||||
}
|
||||
|
||||
float (*loopnors)[3] = CustomData_get_layer(cd_ldata, CD_NORMAL);
|
||||
rdata->cd.layers.tangent[i] = CustomData_get_layer_n(&rdata->cd.output.ldata, CD_TANGENT, i);
|
||||
BLI_assert(rdata->cd.layers.tangent[i] != NULL);
|
||||
|
||||
rdata->cd.layers.tangent[i] = CustomData_add_layer(
|
||||
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->cd.layers.tangent[i],
|
||||
loopnors, rdata->cd.layers.uv[i], me->totloop, me->mpoly, me->totpoly, NULL);
|
||||
#define me DONT_USE_THIS
|
||||
#ifdef me /* quiet warning */
|
||||
#endif
|
||||
|
@ -526,7 +554,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
|
|||
#undef me
|
||||
}
|
||||
|
||||
return rdata;
|
||||
return rdata;
|
||||
}
|
||||
|
||||
static void mesh_render_data_free(MeshRenderData *rdata)
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_tangent.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "ED_mesh.h"
|
||||
|
||||
|
@ -92,7 +93,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *
|
|||
BKE_mesh_calc_normals_split(mesh);
|
||||
}
|
||||
|
||||
BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
|
||||
BKE_mesh_calc_loop_tangent_single(mesh, uvmap, r_looptangents, reports);
|
||||
}
|
||||
|
||||
static void rna_Mesh_free_tangents(Mesh *mesh)
|
||||
|
|
Loading…
Reference in New Issue