mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-14 01:19:59 +00:00
Merge branch 'smolpiranha' into 'master'
Take skin transform and skeleton root into account Closes #4437 See merge request OpenMW/openmw!4471
This commit is contained in:
commit
0e97af6638
@ -1567,6 +1567,9 @@ namespace NifOsg
|
||||
}
|
||||
rig->setBoneInfo(std::move(boneInfo));
|
||||
rig->setInfluences(influences);
|
||||
rig->setTransform(data->mTransform.toMatrix());
|
||||
if (const Nif::NiAVObject* rootBone = skin->mRoot.getPtr())
|
||||
rig->setRootBone(rootBone->mName);
|
||||
|
||||
drawable = rig;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <osgUtil/CullVisitor>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include "skeleton.hpp"
|
||||
@ -181,6 +182,12 @@ namespace SceneUtil
|
||||
++boneInfo;
|
||||
}
|
||||
|
||||
osg::Matrixf transform;
|
||||
if (mSkinToSkelMatrix)
|
||||
transform = (*mSkinToSkelMatrix) * mData->mTransform;
|
||||
else
|
||||
transform = mData->mTransform;
|
||||
|
||||
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);
|
||||
@ -196,8 +203,7 @@ namespace SceneUtil
|
||||
*resultMatPtr += *boneMatPtr * weight;
|
||||
}
|
||||
|
||||
if (mGeomToSkelMatrix)
|
||||
resultMat *= (*mGeomToSkelMatrix);
|
||||
resultMat *= transform;
|
||||
|
||||
for (unsigned short vertex : vertices)
|
||||
{
|
||||
@ -242,9 +248,14 @@ namespace SceneUtil
|
||||
|
||||
mSkeleton->updateBoneMatrices(nv->getTraversalNumber());
|
||||
|
||||
updateGeomToSkelMatrix(nv->getNodePath());
|
||||
updateSkinToSkelMatrix(nv->getNodePath());
|
||||
|
||||
osg::BoundingBox box;
|
||||
osg::Matrixf transform;
|
||||
if (mSkinToSkelMatrix)
|
||||
transform = (*mSkinToSkelMatrix) * mData->mTransform;
|
||||
else
|
||||
transform = mData->mTransform;
|
||||
|
||||
size_t index = 0;
|
||||
for (const BoneInfo& info : mData->mBones)
|
||||
@ -254,10 +265,7 @@ namespace SceneUtil
|
||||
continue;
|
||||
|
||||
osg::BoundingSpheref bs = info.mBoundSphere;
|
||||
if (mGeomToSkelMatrix)
|
||||
transformBoundingSphere(bone->mMatrixInSkeletonSpace * (*mGeomToSkelMatrix), bs);
|
||||
else
|
||||
transformBoundingSphere(bone->mMatrixInSkeletonSpace, bs);
|
||||
transformBoundingSphere(bone->mMatrixInSkeletonSpace * transform, bs);
|
||||
box.expandBy(bs);
|
||||
}
|
||||
|
||||
@ -280,31 +288,39 @@ namespace SceneUtil
|
||||
}
|
||||
}
|
||||
|
||||
void RigGeometry::updateGeomToSkelMatrix(const osg::NodePath& nodePath)
|
||||
void RigGeometry::updateSkinToSkelMatrix(const osg::NodePath& nodePath)
|
||||
{
|
||||
bool foundSkel = false;
|
||||
osg::RefMatrix* geomToSkelMatrix = mGeomToSkelMatrix;
|
||||
if (geomToSkelMatrix)
|
||||
geomToSkelMatrix->makeIdentity();
|
||||
for (osg::NodePath::const_iterator it = nodePath.begin(); it != nodePath.end() - 1; ++it)
|
||||
if (mSkinToSkelMatrix)
|
||||
mSkinToSkelMatrix->makeIdentity();
|
||||
auto skeletonRoot = std::find(nodePath.begin(), nodePath.end(), mSkeleton);
|
||||
if (skeletonRoot == nodePath.end())
|
||||
return;
|
||||
skeletonRoot++;
|
||||
auto skinRoot = nodePath.end();
|
||||
if (!mData->mRootBone.empty())
|
||||
skinRoot = std::find_if(skeletonRoot, nodePath.end(),
|
||||
[&](const osg::Node* node) { return Misc::StringUtils::ciEqual(node->getName(), mData->mRootBone); });
|
||||
if (skinRoot == nodePath.end())
|
||||
{
|
||||
osg::Node* node = *it;
|
||||
if (!foundSkel)
|
||||
// Failed to find skin root, cancel out everything up till the trishape.
|
||||
// Our parent node is the trishape's transform
|
||||
skinRoot = nodePath.end() - 2;
|
||||
if ((*skinRoot)->getName() != getName()) // but maybe it can get optimized out
|
||||
skinRoot++;
|
||||
}
|
||||
else
|
||||
skinRoot++;
|
||||
for (auto it = skeletonRoot; it != skinRoot; ++it)
|
||||
{
|
||||
const osg::Node* node = *it;
|
||||
if (const osg::Transform* trans = node->asTransform())
|
||||
{
|
||||
if (node == mSkeleton)
|
||||
foundSkel = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (osg::Transform* trans = node->asTransform())
|
||||
{
|
||||
osg::MatrixTransform* matrixTrans = trans->asMatrixTransform();
|
||||
if (matrixTrans && matrixTrans->getMatrix().isIdentity())
|
||||
continue;
|
||||
if (!geomToSkelMatrix)
|
||||
geomToSkelMatrix = mGeomToSkelMatrix = new osg::RefMatrix;
|
||||
trans->computeWorldToLocalMatrix(*geomToSkelMatrix, nullptr);
|
||||
}
|
||||
const osg::MatrixTransform* matrixTrans = trans->asMatrixTransform();
|
||||
if (matrixTrans && matrixTrans->getMatrix().isIdentity())
|
||||
continue;
|
||||
if (!mSkinToSkelMatrix)
|
||||
mSkinToSkelMatrix = new osg::RefMatrix;
|
||||
trans->computeWorldToLocalMatrix(*mSkinToSkelMatrix, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -352,6 +368,20 @@ namespace SceneUtil
|
||||
mData->mInfluences.assign(influencesToVertices.begin(), influencesToVertices.end());
|
||||
}
|
||||
|
||||
void RigGeometry::setTransform(osg::Matrixf&& transform)
|
||||
{
|
||||
if (!mData)
|
||||
mData = new InfluenceData;
|
||||
mData->mTransform = transform;
|
||||
}
|
||||
|
||||
void RigGeometry::setRootBone(std::string_view name)
|
||||
{
|
||||
if (!mData)
|
||||
mData = new InfluenceData;
|
||||
mData->mRootBone = name;
|
||||
}
|
||||
|
||||
void RigGeometry::accept(osg::NodeVisitor& nv)
|
||||
{
|
||||
if (!nv.validNodeMask(*this))
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Matrixf>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
class Skeleton;
|
||||
@ -58,6 +60,10 @@ namespace SceneUtil
|
||||
/// @note The source geometry will not be modified.
|
||||
void setSourceGeometry(osg::ref_ptr<osg::Geometry> sourceGeom);
|
||||
|
||||
void setTransform(osg::Matrixf&& transform);
|
||||
|
||||
void setRootBone(std::string_view name);
|
||||
|
||||
osg::ref_ptr<osg::Geometry> getSourceGeometry() const;
|
||||
|
||||
void accept(osg::NodeVisitor& nv) override;
|
||||
@ -89,13 +95,15 @@ namespace SceneUtil
|
||||
osg::ref_ptr<const osg::Vec4Array> mSourceTangents;
|
||||
Skeleton* mSkeleton{ nullptr };
|
||||
|
||||
osg::ref_ptr<osg::RefMatrix> mGeomToSkelMatrix;
|
||||
osg::ref_ptr<osg::RefMatrix> mSkinToSkelMatrix;
|
||||
|
||||
using VertexList = std::vector<unsigned short>;
|
||||
struct InfluenceData : public osg::Referenced
|
||||
{
|
||||
std::vector<BoneInfo> mBones;
|
||||
std::vector<std::pair<BoneWeights, VertexList>> mInfluences;
|
||||
osg::Matrixf mTransform;
|
||||
std::string mRootBone;
|
||||
};
|
||||
osg::ref_ptr<InfluenceData> mData;
|
||||
std::vector<Bone*> mNodes;
|
||||
@ -105,7 +113,7 @@ namespace SceneUtil
|
||||
|
||||
bool initFromParentSkeleton(osg::NodeVisitor* nv);
|
||||
|
||||
void updateGeomToSkelMatrix(const osg::NodePath& nodePath);
|
||||
void updateSkinToSkelMatrix(const osg::NodePath& nodePath);
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user