Streamline passing influence data to skinning

macos_ci_fix
Alexei Kotov 1 year ago
parent b67d89f2e0
commit c1088e5f70

@ -1515,24 +1515,24 @@ namespace NifOsg
osg::ref_ptr<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry);
rig->setSourceGeometry(geom);
// Assign bone weights
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> 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<SceneUtil::RigGeometry::BoneInfo> boneInfo;
std::vector<SceneUtil::RigGeometry::VertexWeights> 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<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry);
rig->setSourceGeometry(geometry);
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map(new SceneUtil::RigGeometry::InfluenceMap);
auto skin = static_cast<const Nif::BSSkinInstance*>(bsTriShape->mSkin.getPtr());
const Nif::BSSkinInstance* skin = static_cast<const Nif::BSSkinInstance*>(bsTriShape->mSkin.getPtr());
const Nif::BSSkinBoneData* data = skin->mData.getPtr();
const Nif::NiAVObjectList& bones = skin->mBones;
std::vector<std::vector<Nif::NiSkinData::VertWeight>> 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<SceneUtil::RigGeometry::BoneInfo> boneInfo;
std::vector<SceneUtil::RigGeometry::BoneWeights> 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;
}

@ -301,23 +301,29 @@ namespace SceneUtil
}
}
void RigGeometry::setInfluenceMap(osg::ref_ptr<InfluenceMap> influenceMap)
void RigGeometry::setBoneInfo(std::vector<BoneInfo>&& 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<VertexWeights>& influences)
{
if (!mData)
mData = new InfluenceData;
std::unordered_map<unsigned short, std::vector<BoneWeight>> vertexToInfluences;
std::unordered_map<unsigned short, BoneWeights> 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<std::vector<BoneWeight>, VertexList> influencesToVertices;
std::map<BoneWeights, VertexList> 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<BoneWeights>& influences)
{
if (!mData)
mData = new InfluenceData;
std::map<BoneWeights, VertexList> 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))

@ -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;
// <vertex index, weight>
std::vector<std::pair<unsigned short, float>> mWeights;
osg::Matrixf mInvBindMatrix;
};
struct InfluenceMap : public osg::Referenced
{
std::vector<std::pair<std::string, BoneInfluence>> mData;
};
using VertexWeight = std::pair<unsigned short, float>;
using VertexWeights = std::vector<VertexWeight>;
using BoneWeight = std::pair<size_t, float>;
using BoneWeights = std::vector<BoneWeight>;
void setInfluenceMap(osg::ref_ptr<InfluenceMap> influenceMap);
void setBoneInfo(std::vector<BoneInfo>&& bones);
// Convert influences in vertex and weight list per bone format
void setInfluences(const std::vector<VertexWeights>& influences);
// Convert influences in bone and weight list per vertex format
void setInfluences(const std::vector<BoneWeights>& 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<osg::RefMatrix> mGeomToSkelMatrix;
struct BoneInfo
{
std::string mName;
osg::BoundingSpheref mBoundSphere;
osg::Matrixf mInvBindMatrix;
};
using BoneWeight = std::pair<size_t, float>;
using VertexList = std::vector<unsigned short>;
struct InfluenceData : public osg::Referenced
{
std::vector<BoneInfo> mBones;
std::vector<std::pair<std::vector<BoneWeight>, VertexList>> mInfluences;
std::vector<std::pair<BoneWeights, VertexList>> mInfluences;
};
osg::ref_ptr<InfluenceData> mData;
std::vector<Bone*> mNodes;

Loading…
Cancel
Save