1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-21 18:40:01 +00:00

Refactor AnimBlendControllers

This commit is contained in:
Sam Hellawell 2024-04-27 23:31:28 +01:00
parent 4040bd9231
commit eb290bebbb
6 changed files with 132 additions and 105 deletions

View File

@ -27,7 +27,7 @@ add_openmw_dir (mwrender
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover
postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass precipitationocclusion ripples postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass precipitationocclusion ripples
actorutil distortion animationpriority bonegroup blendmask actorutil distortion animationpriority bonegroup blendmask animblendcontroller
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput

View File

@ -60,7 +60,6 @@
#include "../mwmechanics/weapontype.hpp" #include "../mwmechanics/weapontype.hpp"
#include "actorutil.hpp" #include "actorutil.hpp"
#include "animblendcontroller.cpp"
#include "rotatecontroller.hpp" #include "rotatecontroller.hpp"
#include "util.hpp" #include "util.hpp"
#include "vismask.hpp" #include "vismask.hpp"
@ -402,8 +401,7 @@ namespace
return lightModel; return lightModel;
} }
void assignBoneBlendCallbackRecursive(MWRender::BoneAnimBlendController* controller, void assignBoneBlendCallbackRecursive(MWRender::BoneAnimBlendController* controller, osg::Node* parent, bool isRoot)
MWRender::ActiveControllersVector& activeControllers, osg::Node* parent, bool isRoot)
{ {
// Attempt to cast node to an osgAnimation::Bone // Attempt to cast node to an osgAnimation::Bone
if (!isRoot && dynamic_cast<osgAnimation::Bone*>(parent)) if (!isRoot && dynamic_cast<osgAnimation::Bone*>(parent))
@ -454,7 +452,7 @@ namespace
osg::Group* group = parent->asGroup(); osg::Group* group = parent->asGroup();
if (group) if (group)
for (unsigned int i = 0; i < group->getNumChildren(); ++i) for (unsigned int i = 0; i < group->getNumChildren(); ++i)
assignBoneBlendCallbackRecursive(controller, activeControllers, group->getChild(i), false); assignBoneBlendCallbackRecursive(controller, group->getChild(i), false);
} }
} }
@ -1085,31 +1083,31 @@ namespace MWRender
return mNodeMap; return mNodeMap;
} }
template <typename ControllerType, typename NodeType> template <typename ControllerType>
inline osg::Callback* Animation::handleBlendTransform(osg::ref_ptr<osg::Node> node, inline osg::Callback* Animation::handleBlendTransform(const osg::ref_ptr<osg::Node>& node,
osg::ref_ptr<SceneUtil::KeyframeController> keyframeController, osg::ref_ptr<SceneUtil::KeyframeController> keyframeController,
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<AnimBlendController<NodeType>>>& blendControllers, std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<ControllerType>>& blendControllers,
const AnimBlendStateData& stateData, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules, const AnimBlendStateData& stateData, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules,
const AnimState& active) const AnimState& active)
{ {
osg::ref_ptr<ControllerType> animController; osg::ref_ptr<ControllerType> animController;
if (blendControllers.contains(node)) if (blendControllers.contains(node))
{ {
animController = blendControllers[node]; animController = blendControllers.at(node);
animController->setKeyframeTrack(keyframeController, stateData, blendRules); animController->setKeyframeTrack(keyframeController, stateData, blendRules);
} }
else else
{ {
animController = new ControllerType(keyframeController, stateData, blendRules); animController = new ControllerType(keyframeController, stateData, blendRules);
blendControllers[node] = animController; blendControllers.emplace(node, animController);
if constexpr (std::is_same_v<ControllerType, BoneAnimBlendController>) if constexpr (std::is_same_v<ControllerType, BoneAnimBlendController>)
assignBoneBlendCallbackRecursive(animController, mActiveControllers, node, true); assignBoneBlendCallbackRecursive(animController, node, true);
} }
keyframeController->mTime = active.mTime; keyframeController->mTime = active.mTime;
osg::Callback* asCallback = animController->getAsCallback();
if constexpr (std::is_same_v<ControllerType, BoneAnimBlendController>) if constexpr (std::is_same_v<ControllerType, BoneAnimBlendController>)
{ {
// IMPORTANT: we must gather all transforms at point of change before next update // IMPORTANT: we must gather all transforms at point of change before next update
@ -1118,13 +1116,13 @@ namespace MWRender
animController->gatherRecursiveBoneTransforms(static_cast<osgAnimation::Bone*>(node.get())); animController->gatherRecursiveBoneTransforms(static_cast<osgAnimation::Bone*>(node.get()));
// Register blend callback after the initial animation callback // Register blend callback after the initial animation callback
node->addUpdateCallback(animController->getAsCallback()); node->addUpdateCallback(asCallback);
mActiveControllers.emplace_back(node, animController->getAsCallback()); mActiveControllers.emplace_back(node, asCallback);
return keyframeController->getAsCallback(); return keyframeController->getAsCallback();
} }
return animController->getAsCallback(); return asCallback;
} }
void Animation::resetActiveGroups() void Animation::resetActiveGroups()
@ -1181,14 +1179,13 @@ namespace MWRender
{ {
if (dynamic_cast<NifOsg::MatrixTransform*>(node.get())) if (dynamic_cast<NifOsg::MatrixTransform*>(node.get()))
{ {
callback = handleBlendTransform<NifAnimBlendController, NifOsg::MatrixTransform>(node, callback = handleBlendTransform<NifAnimBlendController>(node, it->second,
it->second, mAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second); mAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second);
} }
else if (dynamic_cast<osgAnimation::Bone*>(node.get())) else if (dynamic_cast<osgAnimation::Bone*>(node.get()))
{ {
callback callback = handleBlendTransform<BoneAnimBlendController>(node, it->second,
= handleBlendTransform<BoneAnimBlendController, osgAnimation::Bone>(node, it->second, mBoneAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second);
mBoneAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second);
} }
} }

View File

@ -306,10 +306,10 @@ namespace MWRender
void removeFromSceneImpl(); void removeFromSceneImpl();
template <typename ControllerType, typename NodeType> template <typename ControllerType>
inline osg::Callback* handleBlendTransform(osg::ref_ptr<osg::Node> node, inline osg::Callback* handleBlendTransform(const osg::ref_ptr<osg::Node>& node,
osg::ref_ptr<SceneUtil::KeyframeController> keyframeController, osg::ref_ptr<SceneUtil::KeyframeController> keyframeController,
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<AnimBlendController<NodeType>>>& blendControllers, std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<ControllerType>>& blendControllers,
const AnimBlendStateData& stateData, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules, const AnimBlendStateData& stateData, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules,
const AnimState& active); const AnimState& active);

View File

@ -4,6 +4,7 @@
#include <osgAnimation/Bone> #include <osgAnimation/Bone>
#include <cassert>
#include <string> #include <string>
#include <vector> #include <vector>
@ -90,18 +91,26 @@ namespace MWRender
} }
} }
template <typename NodeClass> AnimBlendController::AnimBlendController(const osg::ref_ptr<SceneUtil::KeyframeController>& keyframeTrack,
AnimBlendController<NodeClass>::AnimBlendController(osg::ref_ptr<SceneUtil::KeyframeController> keyframeTrack, const AnimBlendStateData& newState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules)
const AnimBlendStateData& newState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules)
: mTimeFactor(0.0f)
, mInterpFactor(0.0f)
{ {
setKeyframeTrack(keyframeTrack, newState, blendRules); setKeyframeTrack(keyframeTrack, newState, blendRules);
} }
template <typename NodeClass> NifAnimBlendController::NifAnimBlendController(const osg::ref_ptr<SceneUtil::KeyframeController>& keyframeTrack,
void AnimBlendController<NodeClass>::setKeyframeTrack(osg::ref_ptr<SceneUtil::KeyframeController> kft, const AnimBlendStateData& newState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules)
const AnimBlendStateData& newState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules) : AnimBlendController(keyframeTrack, newState, blendRules)
{
}
BoneAnimBlendController::BoneAnimBlendController(const osg::ref_ptr<SceneUtil::KeyframeController>& keyframeTrack,
const AnimBlendStateData& newState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules)
: AnimBlendController(keyframeTrack, newState, blendRules)
{
}
void AnimBlendController::setKeyframeTrack(const osg::ref_ptr<SceneUtil::KeyframeController>& kft,
const AnimBlendStateData& newState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules)
{ {
// If animation has changed then start blending // If animation has changed then start blending
if (newState.mGroupname != mAnimState.mGroupname || newState.mStartKey != mAnimState.mStartKey if (newState.mGroupname != mAnimState.mGroupname || newState.mStartKey != mAnimState.mStartKey
@ -139,8 +148,22 @@ namespace MWRender
} }
} }
template <typename NodeClass> void AnimBlendController::calculateInterpFactor(float time)
void AnimBlendController<NodeClass>::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot) {
if (mBlendDuration != 0)
mTimeFactor = std::min((time - mBlendStartTime) / mBlendDuration, 1.0f);
else
mTimeFactor = 1;
mInterpActive = mTimeFactor < 1.0;
if (mInterpActive)
mInterpFactor = mEasingFn(mTimeFactor);
else
mInterpFactor = 1.0f;
}
void BoneAnimBlendController::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot)
{ {
// Incase group traversal encountered something that isnt a bone // Incase group traversal encountered something that isnt a bone
if (!bone) if (!bone)
@ -156,8 +179,7 @@ namespace MWRender
} }
} }
template <typename NodeClass> void BoneAnimBlendController::applyBoneBlend(osgAnimation::Bone* bone)
void AnimBlendController<NodeClass>::applyBoneBlend(osgAnimation::Bone* bone)
{ {
// If we are done with interpolation then we can safely skip this as the bones are correct // If we are done with interpolation then we can safely skip this as the bones are correct
if (!mInterpActive) if (!mInterpActive)
@ -200,24 +222,7 @@ namespace MWRender
bone->setMatrixInSkeletonSpace(lerpedMatrix); bone->setMatrixInSkeletonSpace(lerpedMatrix);
} }
template <typename NodeClass> void BoneAnimBlendController::operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv)
void AnimBlendController<NodeClass>::calculateInterpFactor(float time)
{
if (mBlendDuration != 0)
mTimeFactor = std::min((time - mBlendStartTime) / mBlendDuration, 1.0f);
else
mTimeFactor = 1;
mInterpActive = mTimeFactor < 1.0;
if (mInterpActive)
mInterpFactor = mEasingFn(mTimeFactor);
else
mInterpFactor = 1.0f;
}
template <typename NodeClass>
void AnimBlendController<NodeClass>::operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv)
{ {
// HOW THIS WORKS: This callback method is called only for bones with attached keyframe controllers // HOW THIS WORKS: This callback method is called only for bones with attached keyframe controllers
// such as bip01, bip01 spine1 etc. The child bones of these controllers have their own callback wrapper // such as bip01, bip01 spine1 etc. The child bones of these controllers have their own callback wrapper
@ -237,11 +242,10 @@ namespace MWRender
if (mInterpActive) if (mInterpActive)
applyBoneBlend(node); applyBoneBlend(node);
SceneUtil::NodeCallback<AnimBlendController<NodeClass>, osgAnimation::Bone*>::traverse(node, nv); SceneUtil::NodeCallback<BoneAnimBlendController, osgAnimation::Bone*>::traverse(node, nv);
} }
template <typename NodeClass> void NifAnimBlendController::operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv)
void AnimBlendController<NodeClass>::operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv)
{ {
// HOW THIS WORKS: The actual retrieval of the bone transformation based on animation is done by the // HOW THIS WORKS: The actual retrieval of the bone transformation based on animation is done by the
// KeyframeController (mKeyframeTrack). The KeyframeController retreives time data (playback position) every // KeyframeController (mKeyframeTrack). The KeyframeController retreives time data (playback position) every
@ -303,6 +307,6 @@ namespace MWRender
// instantly hide/show objects in which case the scale interpolation is undesirable. // instantly hide/show objects in which case the scale interpolation is undesirable.
node->setScale(*scale); node->setScale(*scale);
SceneUtil::NodeCallback<AnimBlendController<NodeClass>, NifOsg::MatrixTransform*>::traverse(node, nv); SceneUtil::NodeCallback<NifAnimBlendController, NifOsg::MatrixTransform*>::traverse(node, nv);
} }
} }

View File

@ -27,49 +27,28 @@ namespace MWRender
std::string mStartKey; std::string mStartKey;
}; };
template <typename NodeClass> class AnimBlendController : public SceneUtil::Controller
class AnimBlendController : public SceneUtil::NodeCallback<AnimBlendController<NodeClass>, NodeClass*>,
public SceneUtil::Controller
{ {
public: public:
AnimBlendController(osg::ref_ptr<SceneUtil::KeyframeController> keyframeTrack, AnimBlendController(const osg::ref_ptr<SceneUtil::KeyframeController>& keyframeTrack,
const AnimBlendStateData& animState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules); const AnimBlendStateData& animState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules);
AnimBlendController() {} AnimBlendController() {}
AnimBlendController(const AnimBlendController& other, const osg::CopyOp&) void setKeyframeTrack(const osg::ref_ptr<SceneUtil::KeyframeController>& kft,
: AnimBlendController(other.mKeyframeTrack, other.mAnimState, other.mAnimBlendRules) const AnimBlendStateData& animState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules);
{
}
META_Object(MWRender, AnimBlendController<NodeClass>)
void operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv);
void operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv);
void setKeyframeTrack(osg::ref_ptr<SceneUtil::KeyframeController> kft, const AnimBlendStateData& animState,
osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules);
osg::Callback* getAsCallback() { return this; }
bool getBlendTrigger() const { return mBlendTrigger; } bool getBlendTrigger() const { return mBlendTrigger; }
void gatherRecursiveBoneTransforms(osgAnimation::Bone* parent, bool isRoot = true); protected:
void applyBoneBlend(osgAnimation::Bone* parent);
private:
Easings::EasingFn mEasingFn; Easings::EasingFn mEasingFn;
float mBlendDuration; float mBlendDuration = 0.0f;
float mBlendStartTime = 0.0f;
float mTimeFactor = 0.0f;
float mInterpFactor = 0.0f;
bool mBlendTrigger = false; bool mBlendTrigger = false;
float mBlendStartTime; bool mInterpActive = false;
osg::Quat mBlendStartRot;
osg::Vec3f mBlendStartTrans;
float mBlendStartScale;
float mTimeFactor;
float mInterpFactor;
bool mInterpActive;
AnimBlendStateData mAnimState; AnimBlendStateData mAnimState;
osg::ref_ptr<const SceneUtil::AnimBlendRules> mAnimBlendRules; osg::ref_ptr<const SceneUtil::AnimBlendRules> mAnimBlendRules;
@ -80,8 +59,55 @@ namespace MWRender
inline void calculateInterpFactor(float time); inline void calculateInterpFactor(float time);
}; };
using NifAnimBlendController = AnimBlendController<NifOsg::MatrixTransform>; class NifAnimBlendController : public SceneUtil::NodeCallback<NifAnimBlendController, NifOsg::MatrixTransform*>,
using BoneAnimBlendController = AnimBlendController<osgAnimation::Bone>; public AnimBlendController
{
public:
NifAnimBlendController(const osg::ref_ptr<SceneUtil::KeyframeController>& keyframeTrack,
const AnimBlendStateData& animState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules);
NifAnimBlendController() {}
NifAnimBlendController(const NifAnimBlendController& other, const osg::CopyOp&)
: NifAnimBlendController(other.mKeyframeTrack, other.mAnimState, other.mAnimBlendRules)
{
}
META_Object(MWRender, NifAnimBlendController)
void operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv);
osg::Callback* getAsCallback() { return this; }
private:
osg::Quat mBlendStartRot;
osg::Vec3f mBlendStartTrans;
float mBlendStartScale = 0.0f;
};
class BoneAnimBlendController : public SceneUtil::NodeCallback<BoneAnimBlendController, osgAnimation::Bone*>,
public AnimBlendController
{
public:
BoneAnimBlendController(const osg::ref_ptr<SceneUtil::KeyframeController>& keyframeTrack,
const AnimBlendStateData& animState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules);
BoneAnimBlendController() {}
BoneAnimBlendController(const BoneAnimBlendController& other, const osg::CopyOp&)
: BoneAnimBlendController(other.mKeyframeTrack, other.mAnimState, other.mAnimBlendRules)
{
}
void gatherRecursiveBoneTransforms(osgAnimation::Bone* parent, bool isRoot = true);
void applyBoneBlend(osgAnimation::Bone* parent);
META_Object(MWRender, BoneAnimBlendController)
void operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv);
osg::Callback* getAsCallback() { return this; }
};
// Assigned to child bones with an instance of AnimBlendController // Assigned to child bones with an instance of AnimBlendController
class BoneAnimBlendControllerWrapper : public osg::Callback class BoneAnimBlendControllerWrapper : public osg::Callback

View File

@ -187,20 +187,20 @@ namespace SceneUtil
mgr->addWrapper(new GeometrySerializer); mgr->addWrapper(new GeometrySerializer);
// ignore the below for now to avoid warning spam // ignore the below for now to avoid warning spam
const char* ignore[] = { "Debug::DebugDrawer", "MWRender::AnimBlendController<NifOsg::MatrixTransform>", const char* ignore[] = { "Debug::DebugDrawer", "MWRender::NifAnimBlendController",
"MWRender::AnimBlendController<osgAnimation::Bone>", "MWRender::BoneAnimBlendControllerWrapper", "MWRender::BoneAnimBlendController", "MWRender::BoneAnimBlendControllerWrapper", "MWRender::PtrHolder",
"MWRender::PtrHolder", "Resource::TemplateRef", "Resource::TemplateMultiRef", "Resource::TemplateRef", "Resource::TemplateMultiRef", "SceneUtil::CompositeStateSetUpdater",
"SceneUtil::CompositeStateSetUpdater", "SceneUtil::UBOManager", "SceneUtil::LightListCallback", "SceneUtil::UBOManager", "SceneUtil::LightListCallback", "SceneUtil::LightManagerUpdateCallback",
"SceneUtil::LightManagerUpdateCallback", "SceneUtil::FFPLightStateAttribute", "SceneUtil::FFPLightStateAttribute", "SceneUtil::UpdateRigBounds", "SceneUtil::UpdateRigGeometry",
"SceneUtil::UpdateRigBounds", "SceneUtil::UpdateRigGeometry", "SceneUtil::LightSource", "SceneUtil::LightSource", "SceneUtil::DisableLight", "SceneUtil::MWShadowTechnique",
"SceneUtil::DisableLight", "SceneUtil::MWShadowTechnique", "SceneUtil::TextKeyMapHolder", "SceneUtil::TextKeyMapHolder", "Shader::AddedState", "Shader::RemovedAlphaFunc",
"Shader::AddedState", "Shader::RemovedAlphaFunc", "NifOsg::FlipController", "NifOsg::FlipController", "NifOsg::KeyframeController", "NifOsg::Emitter",
"NifOsg::KeyframeController", "NifOsg::Emitter", "NifOsg::ParticleColorAffector", "NifOsg::ParticleColorAffector", "NifOsg::ParticleSystem", "NifOsg::GravityAffector",
"NifOsg::ParticleSystem", "NifOsg::GravityAffector", "NifOsg::ParticleBomb", "NifOsg::GrowFadeAffector", "NifOsg::ParticleBomb", "NifOsg::GrowFadeAffector", "NifOsg::InverseWorldMatrix",
"NifOsg::InverseWorldMatrix", "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController", "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController", "NifOsg::UpdateMorphGeometry",
"NifOsg::UpdateMorphGeometry", "NifOsg::UVController", "NifOsg::VisController", "osgMyGUI::Drawable", "NifOsg::UVController", "NifOsg::VisController", "osgMyGUI::Drawable", "osg::DrawCallback",
"osg::DrawCallback", "osg::UniformBufferObject", "osgOQ::ClearQueriesCallback", "osg::UniformBufferObject", "osgOQ::ClearQueriesCallback", "osgOQ::RetrieveQueriesCallback",
"osgOQ::RetrieveQueriesCallback", "osg::DummyObject" }; "osg::DummyObject" };
for (size_t i = 0; i < sizeof(ignore) / sizeof(ignore[0]); ++i) for (size_t i = 0; i < sizeof(ignore) / sizeof(ignore[0]); ++i)
{ {
mgr->addWrapper(makeDummySerializer(ignore[i])); mgr->addWrapper(makeDummySerializer(ignore[i]));