Skip to content

Commit

Permalink
Merge branch 'skinning' into 'master'
Browse files Browse the repository at this point in the history
Streamline passing influence data to skinning

See merge request OpenMW/openmw!3641
  • Loading branch information
jvoisin committed Dec 10, 2023
2 parents 47b87f1 + c1088e5 commit e3e9b39
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 56 deletions.
56 changes: 28 additions & 28 deletions components/nifosg/nifloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
37 changes: 28 additions & 9 deletions components/sceneutil/riggeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,30 +301,49 @@ 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);

mData->mInfluences.reserve(influencesToVertices.size());
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))
Expand Down
32 changes: 13 additions & 19 deletions components/sceneutil/riggeometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit e3e9b39

Please sign in to comment.