1
1
forked from 0ad/0ad

Fix bounding boxes after f73fa05542

Skinning calculations must happen in bone-space.

Fixes f73fa05542

Reported by: langbart
Fixes #6168

Differential Revision: https://code.wildfiregames.com/D3927
This was SVN commit r25387.
This commit is contained in:
wraitii 2021-05-05 16:20:33 +00:00
parent 781afea4b1
commit 100159548c
3 changed files with 25 additions and 12 deletions

View File

@ -33,7 +33,9 @@
void CModelDef::GetMaxBounds(CSkeletonAnimDef* anim, bool loop, CBoundingBoxAligned& result)
{
std::unordered_map<u32, CBoundingBoxAligned>::const_iterator it = m_MaxBoundsPerAnimDef.find(anim ? anim->m_UID : 0);
const u32 animIndex = anim ? anim->m_UID : 0;
std::unordered_map<u32, CBoundingBoxAligned>::const_iterator it = m_MaxBoundsPerAnimDef.find(animIndex);
if (it != m_MaxBoundsPerAnimDef.end())
{
result = it->second;
@ -47,19 +49,28 @@ void CModelDef::GetMaxBounds(CSkeletonAnimDef* anim, bool loop, CBoundingBoxAlig
{
for (size_t i = 0; i < numverts; ++i)
result += verts[i].m_Coords;
m_MaxBoundsPerAnimDef[0] = result;
m_MaxBoundsPerAnimDef[animIndex] = result;
return;
}
ENSURE(anim->m_UID != 0);
ENSURE(animIndex != 0);
CMatrix3D* inverseBindBoneMatrix = GetInverseBindBoneMatrices();
std::vector<CMatrix3D> boneMatrix(anim->GetNumKeys());
// NB: by using frames, the bounds are technically pessimistic (since interpolation could end up outside of them).
for (size_t j = 0; j < anim->GetNumFrames(); ++j)
const size_t numFrames = anim->GetNumFrames();
const float frameTime = anim->GetFrameTime();
const size_t numBones = GetNumBones();
// NB: by using frames, the bounds are technically pessimistic,
// since interpolation between frames can put vertices farther.
for (size_t j = 0; j < numFrames; ++j)
{
anim->BuildBoneMatrices(j*anim->GetFrameTime(), boneMatrix.data(), loop);
anim->BuildBoneMatrices(j * frameTime, boneMatrix.data(), loop);
for (size_t i = 0; i < numBones; ++i)
boneMatrix[i] *= inverseBindBoneMatrix[i];
for (size_t i = 0; i < numverts; ++i)
result += SkinPoint(verts[i], boneMatrix.data());
}
m_MaxBoundsPerAnimDef[anim->m_UID] = result;
m_MaxBoundsPerAnimDef[animIndex] = result;
}
CVector3D CModelDef::SkinPoint(const SModelVertex& vtx,

View File

@ -28,19 +28,22 @@
#include "ps/CLogger.h"
#include "ps/FileIo.h"
namespace
{
// Start IDs at 1 to leave 0 as a special value.
u32 CSkeletonAnimDef::nextUID = 1;
u32 g_NextSkeletonDefUID = 1;
}
///////////////////////////////////////////////////////////////////////////////////////////
// CSkeletonAnimDef constructor
CSkeletonAnimDef::CSkeletonAnimDef() : m_FrameTime(0), m_NumKeys(0), m_NumFrames(0)
{
m_UID = nextUID++;
m_UID = g_NextSkeletonDefUID++;
// Log a warning if we ever overflow. Should that not result from a bug, bumping to u64 ought to suffice.
if (nextUID == 0)
if (g_NextSkeletonDefUID == 0)
{
// Reset to 1.
nextUID++;
g_NextSkeletonDefUID++;
LOGWARNING("CSkeletonAnimDef unique ID overflowed to 0 - model-animation bounds may be incorrect.");
}
}

View File

@ -96,7 +96,6 @@ public:
// Unique identifier - used by CModelDef to cache bounds per-animDef.
// (hopefully we won't run into the u32 limit too soon).
u32 m_UID;
static u32 nextUID;
};
#endif