Merge branch 'riggeometry' into 'master'

Refurbish SceneUtil::RigGeometry

See merge request OpenMW/openmw!3472
macos_ci_fix
psi29a 1 year ago
commit c058b30322

@ -1,5 +1,7 @@
#include "riggeometry.hpp" #include "riggeometry.hpp"
#include <unordered_map>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <osgUtil/CullVisitor> #include <osgUtil/CullVisitor>
@ -10,39 +12,10 @@
#include "skeleton.hpp" #include "skeleton.hpp"
#include "util.hpp" #include "util.hpp"
namespace
{
inline void accumulateMatrix(
const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, const float weight, osg::Matrixf& result)
{
osg::Matrixf m = invBindMatrix * matrix;
float* ptr = m.ptr();
float* ptrresult = result.ptr();
ptrresult[0] += ptr[0] * weight;
ptrresult[1] += ptr[1] * weight;
ptrresult[2] += ptr[2] * weight;
ptrresult[4] += ptr[4] * weight;
ptrresult[5] += ptr[5] * weight;
ptrresult[6] += ptr[6] * weight;
ptrresult[8] += ptr[8] * weight;
ptrresult[9] += ptr[9] * weight;
ptrresult[10] += ptr[10] * weight;
ptrresult[12] += ptr[12] * weight;
ptrresult[13] += ptr[13] * weight;
ptrresult[14] += ptr[14] * weight;
}
}
namespace SceneUtil namespace SceneUtil
{ {
RigGeometry::RigGeometry() RigGeometry::RigGeometry()
: mSkeleton(nullptr)
, mLastFrameNumber(0)
, mBoundsFirstFrame(true)
{ {
setNumChildrenRequiringUpdateTraversal(1); setNumChildrenRequiringUpdateTraversal(1);
// update done in accept(NodeVisitor&) // update done in accept(NodeVisitor&)
@ -50,12 +23,7 @@ namespace SceneUtil
RigGeometry::RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop) RigGeometry::RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop)
: Drawable(copy, copyop) : Drawable(copy, copyop)
, mSkeleton(nullptr) , mData(copy.mData)
, mInfluenceMap(copy.mInfluenceMap)
, mBone2VertexVector(copy.mBone2VertexVector)
, mBoneSphereVector(copy.mBoneSphereVector)
, mLastFrameNumber(0)
, mBoundsFirstFrame(true)
{ {
setSourceGeometry(copy.mSourceGeometry); setSourceGeometry(copy.mSourceGeometry);
setNumChildrenRequiringUpdateTraversal(1); setNumChildrenRequiringUpdateTraversal(1);
@ -151,42 +119,18 @@ namespace SceneUtil
return false; return false;
} }
if (!mInfluenceMap) if (!mData)
{ {
Log(Debug::Error) << "Error: No InfluenceMap set on RigGeometry"; Log(Debug::Error) << "Error: No influence data set on RigGeometry";
return false; return false;
} }
mBoneNodesVector.clear(); mNodes.clear();
for (auto& bonePair : mBoneSphereVector->mData) for (const BoneInfo& info : mData->mBones)
{
const std::string& boneName = bonePair.first;
Bone* bone = mSkeleton->getBone(boneName);
if (!bone)
{
mBoneNodesVector.push_back(nullptr);
Log(Debug::Error) << "Error: RigGeometry did not find bone " << boneName;
continue;
}
mBoneNodesVector.push_back(bone);
}
for (auto& pair : mBone2VertexVector->mData)
{
for (auto& weight : pair.first)
{ {
const std::string& boneName = weight.first.first; mNodes.push_back(mSkeleton->getBone(info.mName));
Bone* bone = mSkeleton->getBone(boneName); if (!mNodes.back())
if (!bone) Log(Debug::Error) << "Error: RigGeometry did not find bone " << info.mName;
{
mBoneNodesVector.push_back(nullptr);
Log(Debug::Error) << "Error: RigGeometry did not find bone " << boneName;
continue;
}
mBoneNodesVector.push_back(bone);
}
} }
return true; return true;
@ -226,25 +170,28 @@ namespace SceneUtil
osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(geom.getNormalArray()); osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(geom.getNormalArray());
osg::Vec4Array* tangentDst = static_cast<osg::Vec4Array*>(geom.getTexCoordArray(7)); osg::Vec4Array* tangentDst = static_cast<osg::Vec4Array*>(geom.getTexCoordArray(7));
int index = mBoneSphereVector->mData.size(); for (const auto& [influences, vertices] : mData->mInfluences)
for (auto& pair : mBone2VertexVector->mData)
{ {
osg::Matrixf resultMat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); osg::Matrixf resultMat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
for (auto& weight : pair.first) for (const auto& [index, weight] : influences)
{ {
Bone* bone = mBoneNodesVector[index]; const Bone* bone = mNodes[index];
if (bone == nullptr) if (bone == nullptr)
continue; continue;
accumulateMatrix(weight.first.second, bone->mMatrixInSkeletonSpace, weight.second, resultMat); osg::Matrixf boneMat = mData->mBones[index].mInvBindMatrix * bone->mMatrixInSkeletonSpace;
index++; float* boneMatPtr = boneMat.ptr();
float* resultMatPtr = resultMat.ptr();
for (int i = 0; i < 16; ++i, ++resultMatPtr, ++boneMatPtr)
if (i % 4 != 3)
*resultMatPtr += *boneMatPtr * weight;
} }
if (mGeomToSkelMatrix) if (mGeomToSkelMatrix)
resultMat *= (*mGeomToSkelMatrix); resultMat *= (*mGeomToSkelMatrix);
for (auto& vertex : pair.second) for (unsigned short vertex : vertices)
{ {
(*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]); (*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]);
if (normalDst) if (normalDst)
@ -291,15 +238,14 @@ namespace SceneUtil
osg::BoundingBox box; osg::BoundingBox box;
int index = 0; size_t index = 0;
for (auto& boundPair : mBoneSphereVector->mData) for (const BoneInfo& info : mData->mBones)
{ {
Bone* bone = mBoneNodesVector[index]; const Bone* bone = mNodes[index++];
if (bone == nullptr) if (bone == nullptr)
continue; continue;
index++; osg::BoundingSpheref bs = info.mBoundSphere;
osg::BoundingSpheref bs = boundPair.second;
if (mGeomToSkelMatrix) if (mGeomToSkelMatrix)
transformBoundingSphere(bone->mMatrixInSkeletonSpace * (*mGeomToSkelMatrix), bs); transformBoundingSphere(bone->mMatrixInSkeletonSpace * (*mGeomToSkelMatrix), bs);
else else
@ -357,35 +303,26 @@ namespace SceneUtil
void RigGeometry::setInfluenceMap(osg::ref_ptr<InfluenceMap> influenceMap) void RigGeometry::setInfluenceMap(osg::ref_ptr<InfluenceMap> influenceMap)
{ {
mInfluenceMap = influenceMap; mData = new InfluenceData;
mData->mBones.reserve(influenceMap->mData.size());
typedef std::map<unsigned short, std::vector<BoneWeight>> Vertex2BoneMap;
Vertex2BoneMap vertex2BoneMap;
mBoneSphereVector = new BoneSphereVector;
mBoneSphereVector->mData.reserve(mInfluenceMap->mData.size());
mBone2VertexVector = new Bone2VertexVector;
for (auto& influencePair : mInfluenceMap->mData)
{
const std::string& boneName = influencePair.first;
const BoneInfluence& bi = influencePair.second;
mBoneSphereVector->mData.emplace_back(boneName, bi.mBoundSphere);
for (auto& weightPair : bi.mWeights) std::unordered_map<unsigned short, std::vector<BoneWeight>> vertexToInfluences;
size_t index = 0;
for (const auto& [boneName, bi] : influenceMap->mData)
{ {
std::vector<BoneWeight>& vec = vertex2BoneMap[weightPair.first]; mData->mBones.push_back({ boneName, bi.mBoundSphere, bi.mInvBindMatrix });
vec.emplace_back(std::make_pair(boneName, bi.mInvBindMatrix), weightPair.second); for (const auto& [vertex, weight] : bi.mWeights)
} vertexToInfluences[vertex].emplace_back(index, weight);
index++;
} }
Bone2VertexMap bone2VertexMap; std::map<std::vector<BoneWeight>, VertexList> influencesToVertices;
for (auto& vertexPair : vertex2BoneMap) for (const auto& [vertex, weights] : vertexToInfluences)
{ influencesToVertices[weights].emplace_back(vertex);
bone2VertexMap[vertexPair.second].emplace_back(vertexPair.first);
}
mBone2VertexVector->mData.reserve(bone2VertexMap.size()); mData->mInfluences.reserve(influencesToVertices.size());
mBone2VertexVector->mData.assign(bone2VertexMap.begin(), bone2VertexMap.end()); mData->mInfluences.assign(influencesToVertices.begin(), influencesToVertices.end());
} }
void RigGeometry::accept(osg::NodeVisitor& nv) void RigGeometry::accept(osg::NodeVisitor& nv)

@ -36,6 +36,7 @@ namespace SceneUtil
// static parts of the model. // static parts of the model.
void compileGLObjects(osg::RenderInfo& renderInfo) const override {} void compileGLObjects(osg::RenderInfo& renderInfo) const override {}
// TODO: Make InfluenceMap more similar to InfluenceData
struct BoneInfluence struct BoneInfluence
{ {
osg::Matrixf mInvBindMatrix; osg::Matrixf mInvBindMatrix;
@ -84,35 +85,29 @@ namespace SceneUtil
osg::ref_ptr<osg::Geometry> mSourceGeometry; osg::ref_ptr<osg::Geometry> mSourceGeometry;
osg::ref_ptr<const osg::Vec4Array> mSourceTangents; osg::ref_ptr<const osg::Vec4Array> mSourceTangents;
Skeleton* mSkeleton; Skeleton* mSkeleton{ nullptr };
osg::ref_ptr<osg::RefMatrix> mGeomToSkelMatrix; osg::ref_ptr<osg::RefMatrix> mGeomToSkelMatrix;
osg::ref_ptr<InfluenceMap> mInfluenceMap; struct BoneInfo
typedef std::pair<std::string, osg::Matrixf> BoneBindMatrixPair;
typedef std::pair<BoneBindMatrixPair, float> BoneWeight;
typedef std::vector<unsigned short> VertexList;
typedef std::map<std::vector<BoneWeight>, VertexList> Bone2VertexMap;
struct Bone2VertexVector : public osg::Referenced
{ {
std::vector<std::pair<std::vector<BoneWeight>, VertexList>> mData; std::string mName;
osg::BoundingSpheref mBoundSphere;
osg::Matrixf mInvBindMatrix;
}; };
osg::ref_ptr<Bone2VertexVector> mBone2VertexVector;
struct BoneSphereVector : public osg::Referenced using BoneWeight = std::pair<size_t, float>;
using VertexList = std::vector<unsigned short>;
struct InfluenceData : public osg::Referenced
{ {
std::vector<std::pair<std::string, osg::BoundingSpheref>> mData; std::vector<BoneInfo> mBones;
std::vector<std::pair<std::vector<BoneWeight>, VertexList>> mInfluences;
}; };
osg::ref_ptr<BoneSphereVector> mBoneSphereVector; osg::ref_ptr<InfluenceData> mData;
std::vector<Bone*> mBoneNodesVector; std::vector<Bone*> mNodes;
unsigned int mLastFrameNumber; unsigned int mLastFrameNumber{ 0 };
bool mBoundsFirstFrame; bool mBoundsFirstFrame{ true };
bool initFromParentSkeleton(osg::NodeVisitor* nv); bool initFromParentSkeleton(osg::NodeVisitor* nv);

Loading…
Cancel
Save