diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index b940fb60ec..1572fab338 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -1,5 +1,7 @@ #include "riggeometry.hpp" +#include + #include #include @@ -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(geom.getNormalArray()); osg::Vec4Array* tangentDst = static_cast(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) { - mInfluenceMap = influenceMap; - - typedef std::map> 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& vec = vertex2BoneMap[weightPair.first]; + std::unordered_map> 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, 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) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 72e8fcd032..d1c077288d 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -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 mSourceGeometry; osg::ref_ptr mSourceTangents; - Skeleton* mSkeleton; + Skeleton* mSkeleton{ nullptr }; osg::ref_ptr mGeomToSkelMatrix; - osg::ref_ptr mInfluenceMap; - - typedef std::pair BoneBindMatrixPair; - - typedef std::pair BoneWeight; - - typedef std::vector VertexList; - - typedef std::map, VertexList> Bone2VertexMap; - - struct Bone2VertexVector : public osg::Referenced + struct BoneInfo { - std::vector, VertexList>> mData; + std::string mName; + osg::BoundingSpheref mBoundSphere; + osg::Matrixf mInvBindMatrix; }; - osg::ref_ptr mBone2VertexVector; - struct BoneSphereVector : public osg::Referenced + using BoneWeight = std::pair; + using VertexList = std::vector; + struct InfluenceData : public osg::Referenced { - std::vector> mData; + std::vector mBones; + std::vector, VertexList>> mInfluences; }; - osg::ref_ptr mBoneSphereVector; - std::vector mBoneNodesVector; + osg::ref_ptr mData; + std::vector mNodes; - unsigned int mLastFrameNumber; - bool mBoundsFirstFrame; + unsigned int mLastFrameNumber{ 0 }; + bool mBoundsFirstFrame{ true }; bool initFromParentSkeleton(osg::NodeVisitor* nv);