Bugfix/sparky kitty studios (#6623)

* Fixed regression that scrambled FBX blendshape order.

* Merge master to this branch

---------

Co-authored-by: Lux <lxw404@gmail.com>
Co-authored-by: Lux <52231149+lxw404@users.noreply.github.com>
Co-authored-by: Kim Kulling <kim.kulling@draeger.com>
This commit is contained in:
Kim Kulling
2026-04-30 11:15:09 +02:00
committed by GitHub
parent 11a5d1b8ef
commit 392a658f9c
5 changed files with 68 additions and 60 deletions

View File

@@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
#include <algorithm>
#include "FBXParser.h"
#include "FBXDocument.h"
#include "FBXMeshGeometry.h"
@@ -144,8 +146,10 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc,
for (const Connection* con : conns) {
const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
if (bspc) {
auto pr = blendShapeChannels.insert(bspc);
if (!pr.second) {
// Only add a channel if it doesn't exist already
if (std::find(blendShapeChannels.begin(), blendShapeChannels.end(), bspc) == blendShapeChannels.end()) {
blendShapeChannels.push_back(bspc);
} else {
FBXImporter::LogWarn("there is the same blendShapeChannel id ", bspc->ID());
}
}
@@ -170,8 +174,10 @@ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const
for (const Connection* con : conns) {
const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
if (sg) {
auto pr = shapeGeometries.insert(sg);
if (!pr.second) {
// Only add a geometry if it doesn't exist already
if (std::find(shapeGeometries.begin(), shapeGeometries.end(), sg) == shapeGeometries.end()) {
shapeGeometries.push_back(sg);
} else {
FBXImporter::LogWarn("there is the same shapeGeometrie id ", sg->ID());
}
}

View File

@@ -865,14 +865,14 @@ public:
return fullWeights;
}
const std::unordered_set<const ShapeGeometry*>& GetShapeGeometries() const {
const std::vector<const ShapeGeometry*>& GetShapeGeometries() const {
return shapeGeometries;
}
private:
float percent;
WeightArray fullWeights;
std::unordered_set<const ShapeGeometry*> shapeGeometries;
std::vector<const ShapeGeometry*> shapeGeometries;
};
/** DOM class for BlendShape deformers */
@@ -882,12 +882,12 @@ public:
virtual ~BlendShape() = default;
const std::unordered_set<const BlendShapeChannel*>& BlendShapeChannels() const {
const std::vector<const BlendShapeChannel*>& BlendShapeChannels() const {
return blendShapeChannels;
}
private:
std::unordered_set<const BlendShapeChannel*> blendShapeChannels;
std::vector<const BlendShapeChannel*> blendShapeChannels;
};
/** DOM class for skin deformer clusters (aka sub-deformers) */

View File

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
#include <algorithm>
#include <functional>
#include "FBXMeshGeometry.h"
@@ -69,8 +70,10 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
}
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
if (bsp) {
auto pr = blendShapes.insert(bsp);
if (!pr.second) {
// Only add a blendshape if it doesn't exist already
if (std::find(blendShapes.begin(), blendShapes.end(), bsp) == blendShapes.end()) {
blendShapes.push_back(bsp);
} else {
FBXImporter::LogWarn("there is the same blendShape id ", bsp->ID());
}
}
@@ -78,7 +81,7 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
}
// ------------------------------------------------------------------------------------------------
const std::unordered_set<const BlendShape*>& Geometry::GetBlendShapes() const {
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
return blendShapes;
}

View File

@@ -72,11 +72,11 @@ public:
/// @brief Get the BlendShape attached to this geometry or nullptr
/// @return The blendshape arrays.
const std::unordered_set<const BlendShape*>& GetBlendShapes() const;
const std::vector<const BlendShape*>& GetBlendShapes() const;
private:
const Skin* skin;
std::unordered_set<const BlendShape*> blendShapes;
std::vector<const BlendShape*> blendShapes;
};

View File

@@ -58,11 +58,55 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stack>
namespace Assimp {
namespace {
ai_real calculateInputACMR(aiMesh *pMesh, const aiFace *const pcEnd,
unsigned int configCacheDepth, unsigned int meshNum) {
ai_real fACMR = 0.0f;
unsigned int *piFIFOStack = new unsigned int[configCacheDepth];
memset(piFIFOStack, 0xff, configCacheDepth * sizeof(unsigned int));
unsigned int *piCur = piFIFOStack;
const unsigned int *const piCurEnd = piFIFOStack + configCacheDepth;
// count the number of cache misses
unsigned int iCacheMisses = 0;
for (const aiFace *pcFace = pMesh->mFaces; pcFace != pcEnd; ++pcFace) {
for (unsigned int qq = 0; qq < 3; ++qq) {
bool bInCache = false;
for (unsigned int *pp = piFIFOStack; pp < piCurEnd; ++pp) {
if (*pp == pcFace->mIndices[qq]) {
// the vertex is in cache
bInCache = true;
break;
}
}
if (!bInCache) {
++iCacheMisses;
if (piCurEnd == piCur) {
piCur = piFIFOStack;
}
*piCur++ = pcFace->mIndices[qq];
}
}
}
delete[] piFIFOStack;
fACMR = (ai_real)iCacheMisses / pMesh->mNumFaces;
if (3.0 == fACMR) {
char szBuff[128]; // should be sufficiently large in every case
// the JoinIdenticalVertices process has not been executed on this
// mesh, otherwise this value would normally be at least minimally
// smaller than 3.0 ...
ai_snprintf(szBuff, 128, "Mesh %u: Not suitable for vcache optimization", meshNum);
ASSIMP_LOG_WARN(szBuff);
return static_cast<ai_real>(0.f);
}
return fACMR;
}
}
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() :
mConfigCacheDepth(PP_ICL_PTCACHE_SIZE) {
ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() : mConfigCacheDepth(PP_ICL_PTCACHE_SIZE) {
// empty
}
@@ -107,51 +151,6 @@ void ImproveCacheLocalityProcess::Execute(aiScene *pScene) {
}
}
// ------------------------------------------------------------------------------------------------
static ai_real calculateInputACMR(aiMesh *pMesh, const aiFace *const pcEnd,
unsigned int configCacheDepth, unsigned int meshNum) {
ai_real fACMR = 0.0f;
unsigned int *piFIFOStack = new unsigned int[configCacheDepth];
memset(piFIFOStack, 0xff, configCacheDepth * sizeof(unsigned int));
unsigned int *piCur = piFIFOStack;
const unsigned int *const piCurEnd = piFIFOStack + configCacheDepth;
// count the number of cache misses
unsigned int iCacheMisses = 0;
for (const aiFace *pcFace = pMesh->mFaces; pcFace != pcEnd; ++pcFace) {
for (unsigned int qq = 0; qq < 3; ++qq) {
bool bInCache = false;
for (unsigned int *pp = piFIFOStack; pp < piCurEnd; ++pp) {
if (*pp == pcFace->mIndices[qq]) {
// the vertex is in cache
bInCache = true;
break;
}
}
if (!bInCache) {
++iCacheMisses;
if (piCurEnd == piCur) {
piCur = piFIFOStack;
}
*piCur++ = pcFace->mIndices[qq];
}
}
}
delete[] piFIFOStack;
fACMR = (ai_real)iCacheMisses / pMesh->mNumFaces;
if (3.0 == fACMR) {
char szBuff[128]; // should be sufficiently large in every case
// the JoinIdenticalVertices process has not been executed on this
// mesh, otherwise this value would normally be at least minimally
// smaller than 3.0 ...
ai_snprintf(szBuff, 128, "Mesh %u: Not suitable for vcache optimization", meshNum);
ASSIMP_LOG_WARN(szBuff);
return static_cast<ai_real>(0.f);
}
return fACMR;
}
// ------------------------------------------------------------------------------------------------
// Improves the cache coherency of a specific mesh
ai_real ImproveCacheLocalityProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshNum) {