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 <unordered_map>
#include <osg/MatrixTransform>
#include <osgUtil/CullVisitor>
@ -10,39 +12,10 @@
#include "skeleton.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
{
RigGeometry::RigGeometry()
: mSkeleton(nullptr)
, mLastFrameNumber(0)
, mBoundsFirstFrame(true)
{
setNumChildrenRequiringUpdateTraversal(1);
// update done in accept(NodeVisitor&)
@ -50,12 +23,7 @@ namespace SceneUtil
RigGeometry::RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop)
: Drawable(copy, copyop)
, mSkeleton(nullptr)
, mInfluenceMap(copy.mInfluenceMap)
, mBone2VertexVector(copy.mBone2VertexVector)
, mBoneSphereVector(copy.mBoneSphereVector)
, mLastFrameNumber(0)
, mBoundsFirstFrame(true)
, mData(copy.mData)
{
setSourceGeometry(copy.mSourceGeometry);
setNumChildrenRequiringUpdateTraversal(1);
@ -151,42 +119,18 @@ namespace SceneUtil
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;
}
mBoneNodesVector.clear();
for (auto& bonePair : mBoneSphereVector->mData)
mNodes.clear();
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;
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);
}
mNodes.push_back(mSkeleton->getBone(info.mName));
if (!mNodes.back())
Log(Debug::Error) << "Error: RigGeometry did not find bone " << info.mName;
}
return true;
@ -226,25 +170,28 @@ namespace SceneUtil
osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(geom.getNormalArray());
osg::Vec4Array* tangentDst = static_cast<osg::Vec4Array*>(geom.getTexCoordArray(7));
int index = mBoneSphereVector->mData.size();
for (auto& pair : mBone2VertexVector->mData)
for (const auto& [influences, vertices] : mData->mInfluences)
{
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)
continue;
accumulateMatrix(weight.first.second, bone->mMatrixInSkeletonSpace, weight.second, resultMat);
index++;
osg::Matrixf boneMat = mData->mBones[index].mInvBindMatrix * bone->mMatrixInSkeletonSpace;
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)
resultMat *= (*mGeomToSkelMatrix);
for (auto& vertex : pair.second)
for (unsigned short vertex : vertices)
{
(*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]);
if (normalDst)
@ -291,15 +238,14 @@ namespace SceneUtil
osg::BoundingBox box;
int index = 0;
for (auto& boundPair : mBoneSphereVector->mData)
size_t index = 0;
for (const BoneInfo& info : mData->mBones)
{
Bone* bone = mBoneNodesVector[index];
const Bone* bone = mNodes[index++];
if (bone == nullptr)
continue;
index++;
osg::BoundingSpheref bs = boundPair.second;
osg::BoundingSpheref bs = info.mBoundSphere;
if (mGeomToSkelMatrix)
transformBoundingSphere(bone->mMatrixInSkeletonSpace * (*mGeomToSkelMatrix), bs);
else
@ -357,35 +303,26 @@ namespace SceneUtil
void RigGeometry::setInfluenceMap(osg::ref_ptr<InfluenceMap> influenceMap)
{
mInfluenceMap = influenceMap;
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);
mData = new InfluenceData;
mData->mBones.reserve(influenceMap->mData.size());
for (auto& weightPair : bi.mWeights)
{
std::vector<BoneWeight>& vec = vertex2BoneMap[weightPair.first];
std::unordered_map<unsigned short, std::vector<BoneWeight>> vertexToInfluences;
size_t index = 0;
for (const auto& [boneName, bi] : influenceMap->mData)
{
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;
for (auto& vertexPair : vertex2BoneMap)
{
bone2VertexMap[vertexPair.second].emplace_back(vertexPair.first);
}
std::map<std::vector<BoneWeight>, VertexList> influencesToVertices;
for (const auto& [vertex, weights] : vertexToInfluences)
influencesToVertices[weights].emplace_back(vertex);
mBone2VertexVector->mData.reserve(bone2VertexMap.size());
mBone2VertexVector->mData.assign(bone2VertexMap.begin(), bone2VertexMap.end());
mData->mInfluences.reserve(influencesToVertices.size());
mData->mInfluences.assign(influencesToVertices.begin(), influencesToVertices.end());
}
void RigGeometry::accept(osg::NodeVisitor& nv)

@ -36,6 +36,7 @@ namespace SceneUtil
// static parts of the model.
void compileGLObjects(osg::RenderInfo& renderInfo) const override {}
// TODO: Make InfluenceMap more similar to InfluenceData
struct BoneInfluence
{
osg::Matrixf mInvBindMatrix;
@ -84,35 +85,29 @@ namespace SceneUtil
osg::ref_ptr<osg::Geometry> mSourceGeometry;
osg::ref_ptr<const osg::Vec4Array> mSourceTangents;
Skeleton* mSkeleton;
Skeleton* mSkeleton{ nullptr };
osg::ref_ptr<osg::RefMatrix> mGeomToSkelMatrix;
osg::ref_ptr<InfluenceMap> mInfluenceMap;
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
struct BoneInfo
{
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;
std::vector<Bone*> mBoneNodesVector;
osg::ref_ptr<InfluenceData> mData;
std::vector<Bone*> mNodes;
unsigned int mLastFrameNumber;
bool mBoundsFirstFrame;
unsigned int mLastFrameNumber{ 0 };
bool mBoundsFirstFrame{ true };
bool initFromParentSkeleton(osg::NodeVisitor* nv);

Loading…
Cancel
Save