mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 21:35:24 +00:00
Merge branch 'riggeometry' into 'master'
Refurbish SceneUtil::RigGeometry See merge request OpenMW/openmw!3472
This commit is contained in:
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;
|
||||
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)
|
||||
std::unordered_map<unsigned short, std::vector<BoneWeight>> vertexToInfluences;
|
||||
size_t index = 0;
|
||||
for (const auto& [boneName, bi] : influenceMap->mData)
|
||||
{
|
||||
const std::string& boneName = influencePair.first;
|
||||
const BoneInfluence& bi = influencePair.second;
|
||||
mBoneSphereVector->mData.emplace_back(boneName, bi.mBoundSphere);
|
||||
mData->mBones.push_back({ boneName, bi.mBoundSphere, bi.mInvBindMatrix });
|
||||
|
||||
for (auto& weightPair : bi.mWeights)
|
||||
{
|
||||
std::vector<BoneWeight>& vec = vertex2BoneMap[weightPair.first];
|
||||
|
||||
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…
x
Reference in New Issue
Block a user