From 5081d263dbf966e584e53bf4e538215a856c682a Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 17 Jul 2025 15:46:54 +0200 Subject: [PATCH] Integrate MikkTSpace calculation for tangents --- code/PostProcessing/CalcTangentsProcess.cpp | 12 ++- code/PostProcessing/CalcTangentsProcess.h | 1 + .../GenerateMikkTSpaceTangents.cpp | 89 ++++++++++++++++++- .../GenerateMikkTSpaceTangents.h | 10 ++- include/assimp/config.h.in | 5 +- include/assimp/mesh.h | 1 - 6 files changed, 108 insertions(+), 10 deletions(-) diff --git a/code/PostProcessing/CalcTangentsProcess.cpp b/code/PostProcessing/CalcTangentsProcess.cpp index a23ac856b..2276f94df 100644 --- a/code/PostProcessing/CalcTangentsProcess.cpp +++ b/code/PostProcessing/CalcTangentsProcess.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team - - +Copyright (c) 2006-2025, assimp team All rights reserved. @@ -63,7 +61,11 @@ CalcTangentsProcess::CalcTangentsProcess() : // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool CalcTangentsProcess::IsActive(unsigned int pFlags) const { - return (pFlags & aiProcess_CalcTangentSpace) != 0; + const bool active = ((pFlags & aiProcess_CalcTangentSpace) != 0); + if (mActive) { + return active; + } + return false; } // ------------------------------------------------------------------------------------------------ @@ -71,6 +73,8 @@ bool CalcTangentsProcess::IsActive(unsigned int pFlags) const { void CalcTangentsProcess::SetupProperties(const Importer *pImp) { ai_assert(nullptr != pImp); + mActive = pImp->GetPropertyBool(AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS, false); + // get the current value of the property configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 45.f); configMaxAngle = std::max(std::min(configMaxAngle, 45.0f), 0.0f); diff --git a/code/PostProcessing/CalcTangentsProcess.h b/code/PostProcessing/CalcTangentsProcess.h index aaccb5307..bae82422e 100644 --- a/code/PostProcessing/CalcTangentsProcess.h +++ b/code/PostProcessing/CalcTangentsProcess.h @@ -103,6 +103,7 @@ private: /** Configuration option: maximum smoothing angle, in radians*/ float configMaxAngle; unsigned int configSourceUV; + bool mActive = true; }; } // end of namespace Assimp diff --git a/code/PostProcessing/GenerateMikkTSpaceTangents.cpp b/code/PostProcessing/GenerateMikkTSpaceTangents.cpp index 7a6bda867..37f2cad50 100644 --- a/code/PostProcessing/GenerateMikkTSpaceTangents.cpp +++ b/code/PostProcessing/GenerateMikkTSpaceTangents.cpp @@ -1,13 +1,100 @@ #include "GenerateMikkTSpaceTangents.h" +#include +#include namespace Assimp { -bool GenerateMikkTSpaceTangents::IsActive(unsigned int pFlags) const { +static int get_vertex_index(const SMikkTSpaceContext *context, int iFace, int iVert); +static int get_num_faces(const SMikkTSpaceContext *context); +static int get_num_vertices_of_face(const SMikkTSpaceContext *context, int iFace); +static void get_position(const SMikkTSpaceContext *context, float outpos[], int iFace, int iVert); +static void get_normal(const SMikkTSpaceContext *context, float outnormal[], int iFace, int iVert); +static void get_tex_coords(const SMikkTSpaceContext *context, float outuv[], int iFace, int iVert); +static void set_tspace_basic(const SMikkTSpaceContext *context, const float tangentu[], float fSign, int iFace, int iVert); +static int get_num_faces(const SMikkTSpaceContext *context) { + aiMesh *currentMesh = static_cast(context->m_pUserData); + const int numFaces = static_cast(currentMesh->mNumFaces); + + return numFaces; +} + +static int get_num_vertices_of_face(const SMikkTSpaceContext *context, int iFace) { + aiMesh *currentMesh = static_cast(context->m_pUserData); + const aiFace &face = currentMesh->mFaces[iFace]; + return face.mNumIndices; +} + +static void get_position(const SMikkTSpaceContext *context, float outpos[], int iFace, int iVert) { + aiMesh *currentMesh = static_cast(context->m_pUserData); + const aiVector3D &v = currentMesh->mVertices[static_cast(iVert)]; + outpos[0] = v.x; + outpos[1] = v.y; + outpos[2] = v.z; +} + +static void get_normal(const SMikkTSpaceContext *context, float outnormal[], int iFace, int iVert) { + aiMesh *currentMesh = static_cast(context->m_pUserData); + const aiVector3D &n = currentMesh->mNormals[static_cast(iVert)]; + outnormal[0] = n.x; + outnormal[0] = n.y; + outnormal[0] = n.z; +} + +static void get_tex_coords(const SMikkTSpaceContext *context, float outuv[], int iFace, int iVert) { + aiMesh *currentMesh = static_cast(context->m_pUserData); + aiVector3D &t = currentMesh->mTextureCoords[static_cast(iVert)][0]; + if (currentMesh->mNumUVComponents[iVert] == 2) { + outuv[0] = t.x; + outuv[1] = t.y; + } else if (currentMesh->mNumUVComponents[iVert] == 3){ + outuv[0] = t.x; + outuv[1] = t.y; + outuv[2] = t.z; + } +} + +static void set_tspace_basic(const SMikkTSpaceContext *context, const float tangentu[], float fSign, int iFace, int iVert) { + aiMesh *currentMesh = static_cast(context->m_pUserData); + currentMesh->mTangents[iVert].x = tangentu[0]; + currentMesh->mTangents[iVert].y = tangentu[1]; + currentMesh->mTangents[iVert].z = tangentu[1]; +} + +bool GenerateMikkTSpaceTangents::IsActive(unsigned int pFlags) const { + const bool active = ((pFlags & aiProcess_CalcTangentSpace) != 0); + if (mActive) { + return active; + } + return false; } void GenerateMikkTSpaceTangents::Execute(aiScene* pScene) { + mIface.m_getNumFaces = get_num_faces; + mIface.m_getNumVerticesOfFace = get_num_vertices_of_face; + mIface.m_getNormal = get_normal; + mIface.m_getPosition = get_position; + mIface.m_getTexCoord = get_tex_coords; + mIface.m_setTSpaceBasic = set_tspace_basic; + mContext.m_pInterface = &mIface; + for (size_t i=0; imNumMeshes; ++i) { + aiMesh *mesh = pScene->mMeshes[i]; + ExecutePerMesh(mesh); + } } +void GenerateMikkTSpaceTangents::SetupProperties(const Importer *pImp) { + mActive = pImp->GetPropertyBool(AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS, false); } + +void GenerateMikkTSpaceTangents::ExecutePerMesh(aiMesh *mesh) { + if (mesh == nullptr) { + return; + } + + mContext.m_pUserData = mesh; + genTangSpaceDefault(&mContext); +} + +} // namespace Assimp diff --git a/code/PostProcessing/GenerateMikkTSpaceTangents.h b/code/PostProcessing/GenerateMikkTSpaceTangents.h index 95fb5d945..9ca21b718 100644 --- a/code/PostProcessing/GenerateMikkTSpaceTangents.h +++ b/code/PostProcessing/GenerateMikkTSpaceTangents.h @@ -1,17 +1,21 @@ #pragma once #include "Common/BaseProcess.h" +#include "contrib/MikkTSpace/mikktspace.h" namespace Assimp { -class GenerateMikkTSpaceTangents : public BaseProcess { +class GenerateMikkTSpaceTangents final : public BaseProcess { public: GenerateMikkTSpaceTangents() = default; ~GenerateMikkTSpaceTangents() override = default; bool IsActive(unsigned int pFlags) const override; void Execute(aiScene* pScene) override; + void ExecutePerMesh(aiMesh *mesh); +private: + SMikkTSpaceInterface mIface; + SMikkTSpaceContext mContext; }; -} - +} // namespace Assimp diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index cb46d8057..40abec490 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -1131,6 +1131,9 @@ enum aiComponent #endif // AI_CONFIG_APP_SCALE_KEY +#define AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS \ + "POSTPROCESS_USE_MIKKTSPACE_TANGENTS" + // ---------- All the Build/Compile-time defines ------------ /** @brief Specifies if double precision is supported inside assimp @@ -1138,6 +1141,6 @@ enum aiComponent * Property type: Bool. Default value: undefined. */ -#cmakedefine ASSIMP_DOUBLE_PRECISION 1 +#define ASSIMP_DOUBLE_PRECISION 1 #endif // !! AI_CONFIG_H_INC diff --git a/include/assimp/mesh.h b/include/assimp/mesh.h index 45f50d5a5..cca293a00 100644 --- a/include/assimp/mesh.h +++ b/include/assimp/mesh.h @@ -1171,4 +1171,3 @@ struct aiSkeleton { #endif //! extern "C" #endif // AI_MESH_H_INC -