From c1088e5f70e8ce1ca7fe5099e3f04bfdb4ddc2ab Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 8 Dec 2023 00:19:14 +0300 Subject: [PATCH] Streamline passing influence data to skinning --- components/nifosg/nifloader.cpp | 56 ++++++++++++++-------------- components/sceneutil/riggeometry.cpp | 37 +++++++++++++----- components/sceneutil/riggeometry.hpp | 32 +++++++--------- 3 files changed, 69 insertions(+), 56 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 436f2e1d34..a08231809b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1515,24 +1515,24 @@ namespace NifOsg osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geom); - // Assign bone weights - osg::ref_ptr map(new SceneUtil::RigGeometry::InfluenceMap); - const Nif::NiSkinInstance* skin = niGeometry->mSkin.getPtr(); const Nif::NiSkinData* data = skin->mData.getPtr(); const Nif::NiAVObjectList& bones = skin->mBones; + + // Assign bone weights + std::vector boneInfo; + std::vector influences; + boneInfo.resize(bones.size()); + influences.resize(bones.size()); for (std::size_t i = 0; i < bones.size(); ++i) { - std::string boneName = Misc::StringUtils::lowerCase(bones[i].getPtr()->mName); - - SceneUtil::RigGeometry::BoneInfluence influence; - influence.mWeights = data->mBones[i].mWeights; - influence.mInvBindMatrix = data->mBones[i].mTransform.toMatrix(); - influence.mBoundSphere = data->mBones[i].mBoundSphere; - - map->mData.emplace_back(boneName, influence); + boneInfo[i].mName = Misc::StringUtils::lowerCase(bones[i].getPtr()->mName); + boneInfo[i].mInvBindMatrix = data->mBones[i].mTransform.toMatrix(); + boneInfo[i].mBoundSphere = data->mBones[i].mBoundSphere; + influences[i] = data->mBones[i].mWeights; } - rig->setInfluenceMap(map); + rig->setBoneInfo(std::move(boneInfo)); + rig->setInfluences(influences); drawable = rig; } @@ -1671,29 +1671,29 @@ namespace NifOsg osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); - osg::ref_ptr map(new SceneUtil::RigGeometry::InfluenceMap); - - auto skin = static_cast(bsTriShape->mSkin.getPtr()); + const Nif::BSSkinInstance* skin = static_cast(bsTriShape->mSkin.getPtr()); const Nif::BSSkinBoneData* data = skin->mData.getPtr(); const Nif::NiAVObjectList& bones = skin->mBones; - std::vector> vertWeights(data->mBones.size()); - for (size_t i = 0; i < vertices.size(); i++) - for (int j = 0; j < 4; j++) - vertWeights[bsTriShape->mVertData[i].mBoneIndices[j]].emplace_back( - i, halfToFloat(bsTriShape->mVertData[i].mBoneWeights[j])); + std::vector boneInfo; + std::vector influences; + boneInfo.resize(bones.size()); + influences.resize(vertices.size()); for (std::size_t i = 0; i < bones.size(); ++i) { - std::string boneName = Misc::StringUtils::lowerCase(bones[i].getPtr()->mName); - - SceneUtil::RigGeometry::BoneInfluence influence; - influence.mWeights = vertWeights[i]; - influence.mInvBindMatrix = data->mBones[i].mTransform.toMatrix(); - influence.mBoundSphere = data->mBones[i].mBoundSphere; + boneInfo[i].mName = Misc::StringUtils::lowerCase(bones[i].getPtr()->mName); + boneInfo[i].mInvBindMatrix = data->mBones[i].mTransform.toMatrix(); + boneInfo[i].mBoundSphere = data->mBones[i].mBoundSphere; + } - map->mData.emplace_back(boneName, influence); + for (size_t i = 0; i < vertices.size(); i++) + { + const Nif::BSVertexData& vertData = bsTriShape->mVertData[i]; + for (int j = 0; j < 4; j++) + influences[i].emplace_back(vertData.mBoneIndices[j], halfToFloat(vertData.mBoneWeights[j])); } - rig->setInfluenceMap(map); + rig->setBoneInfo(std::move(boneInfo)); + rig->setInfluences(influences); drawable = rig; } diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 1572fab338..92e316d412 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -301,23 +301,29 @@ namespace SceneUtil } } - void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) + void RigGeometry::setBoneInfo(std::vector&& bones) { - mData = new InfluenceData; - mData->mBones.reserve(influenceMap->mData.size()); + if (!mData) + mData = new InfluenceData; + + mData->mBones = std::move(bones); + } + + void RigGeometry::setInfluences(const std::vector& influences) + { + if (!mData) + mData = new InfluenceData; - std::unordered_map> vertexToInfluences; + std::unordered_map vertexToInfluences; size_t index = 0; - for (const auto& [boneName, bi] : influenceMap->mData) + for (const auto& influence : influences) { - mData->mBones.push_back({ boneName, bi.mBoundSphere, bi.mInvBindMatrix }); - - for (const auto& [vertex, weight] : bi.mWeights) + for (const auto& [vertex, weight] : influence) vertexToInfluences[vertex].emplace_back(index, weight); index++; } - std::map, VertexList> influencesToVertices; + std::map influencesToVertices; for (const auto& [vertex, weights] : vertexToInfluences) influencesToVertices[weights].emplace_back(vertex); @@ -325,6 +331,19 @@ namespace SceneUtil mData->mInfluences.assign(influencesToVertices.begin(), influencesToVertices.end()); } + void RigGeometry::setInfluences(const std::vector& influences) + { + if (!mData) + mData = new InfluenceData; + + std::map influencesToVertices; + for (size_t i = 0; i < influences.size(); i++) + influencesToVertices[influences[i]].emplace_back(i); + + mData->mInfluences.reserve(influencesToVertices.size()); + mData->mInfluences.assign(influencesToVertices.begin(), influencesToVertices.end()); + } + void RigGeometry::accept(osg::NodeVisitor& nv) { if (!nv.validNodeMask(*this)) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index d1c077288d..64ea1e2519 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -36,21 +36,23 @@ namespace SceneUtil // static parts of the model. void compileGLObjects(osg::RenderInfo& renderInfo) const override {} - // TODO: Make InfluenceMap more similar to InfluenceData - struct BoneInfluence + struct BoneInfo { - osg::Matrixf mInvBindMatrix; + std::string mName; osg::BoundingSpheref mBoundSphere; - // - std::vector> mWeights; + osg::Matrixf mInvBindMatrix; }; - struct InfluenceMap : public osg::Referenced - { - std::vector> mData; - }; + using VertexWeight = std::pair; + using VertexWeights = std::vector; + using BoneWeight = std::pair; + using BoneWeights = std::vector; - void setInfluenceMap(osg::ref_ptr influenceMap); + void setBoneInfo(std::vector&& bones); + // Convert influences in vertex and weight list per bone format + void setInfluences(const std::vector& influences); + // Convert influences in bone and weight list per vertex format + void setInfluences(const std::vector& influences); /// Initialize this geometry from the source geometry. /// @note The source geometry will not be modified. @@ -89,19 +91,11 @@ namespace SceneUtil osg::ref_ptr mGeomToSkelMatrix; - struct BoneInfo - { - std::string mName; - osg::BoundingSpheref mBoundSphere; - osg::Matrixf mInvBindMatrix; - }; - - using BoneWeight = std::pair; using VertexList = std::vector; struct InfluenceData : public osg::Referenced { std::vector mBones; - std::vector, VertexList>> mInfluences; + std::vector> mInfluences; }; osg::ref_ptr mData; std::vector mNodes;