Refactor AnimBlendControllers

pull/3236/head
Sam Hellawell 8 months ago
parent 4040bd9231
commit eb290bebbb

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

@ -60,7 +60,6 @@
#include "../mwmechanics/weapontype.hpp"
#include "actorutil.hpp"
#include "animblendcontroller.cpp"
#include "rotatecontroller.hpp"
#include "util.hpp"
#include "vismask.hpp"
@ -402,8 +401,7 @@ namespace
return lightModel;
}
void assignBoneBlendCallbackRecursive(MWRender::BoneAnimBlendController* controller,
MWRender::ActiveControllersVector& activeControllers, osg::Node* parent, bool isRoot)
void assignBoneBlendCallbackRecursive(MWRender::BoneAnimBlendController* controller, osg::Node* parent, bool isRoot)
{
// Attempt to cast node to an osgAnimation::Bone
if (!isRoot && dynamic_cast<osgAnimation::Bone*>(parent))
@ -454,7 +452,7 @@ namespace
osg::Group* group = parent->asGroup();
if (group)
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;
}
template <typename ControllerType, typename NodeType>
inline osg::Callback* Animation::handleBlendTransform(osg::ref_ptr<osg::Node> node,
template <typename ControllerType>
inline osg::Callback* Animation::handleBlendTransform(const osg::ref_ptr<osg::Node>& node,
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 AnimState& active)
{
osg::ref_ptr<ControllerType> animController;
if (blendControllers.contains(node))
{
animController = blendControllers[node];
animController = blendControllers.at(node);
animController->setKeyframeTrack(keyframeController, stateData, blendRules);
}
else
{
animController = new ControllerType(keyframeController, stateData, blendRules);
blendControllers[node] = animController;
blendControllers.emplace(node, animController);
if constexpr (std::is_same_v<ControllerType, BoneAnimBlendController>)
assignBoneBlendCallbackRecursive(animController, mActiveControllers, node, true);
assignBoneBlendCallbackRecursive(animController, node, true);
}
keyframeController->mTime = active.mTime;
osg::Callback* asCallback = animController->getAsCallback();
if constexpr (std::is_same_v<ControllerType, BoneAnimBlendController>)
{
// 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()));
// Register blend callback after the initial animation callback
node->addUpdateCallback(animController->getAsCallback());
mActiveControllers.emplace_back(node, animController->getAsCallback());
node->addUpdateCallback(asCallback);
mActiveControllers.emplace_back(node, asCallback);
return keyframeController->getAsCallback();
}
return animController->getAsCallback();
return asCallback;
}
void Animation::resetActiveGroups()
@ -1181,14 +1179,13 @@ namespace MWRender
{
if (dynamic_cast<NifOsg::MatrixTransform*>(node.get()))
{
callback = handleBlendTransform<NifAnimBlendController, NifOsg::MatrixTransform>(node,
it->second, mAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second);
callback = handleBlendTransform<NifAnimBlendController>(node, it->second,
mAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second);
}
else if (dynamic_cast<osgAnimation::Bone*>(node.get()))
{
callback
= handleBlendTransform<BoneAnimBlendController, osgAnimation::Bone>(node, it->second,
mBoneAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second);
callback = handleBlendTransform<BoneAnimBlendController>(node, it->second,
mBoneAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second);
}
}

@ -306,10 +306,10 @@ namespace MWRender
void removeFromSceneImpl();
template <typename ControllerType, typename NodeType>
inline osg::Callback* handleBlendTransform(osg::ref_ptr<osg::Node> node,
template <typename ControllerType>
inline osg::Callback* handleBlendTransform(const osg::ref_ptr<osg::Node>& node,
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 AnimState& active);

@ -4,6 +4,7 @@
#include <osgAnimation/Bone>
#include <cassert>
#include <string>
#include <vector>
@ -90,18 +91,26 @@ namespace MWRender
}
}
template <typename NodeClass>
AnimBlendController<NodeClass>::AnimBlendController(osg::ref_ptr<SceneUtil::KeyframeController> keyframeTrack,
const AnimBlendStateData& newState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules)
: mTimeFactor(0.0f)
, mInterpFactor(0.0f)
AnimBlendController::AnimBlendController(const osg::ref_ptr<SceneUtil::KeyframeController>& keyframeTrack,
const AnimBlendStateData& newState, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules)
{
setKeyframeTrack(keyframeTrack, newState, blendRules);
}
template <typename NodeClass>
void AnimBlendController<NodeClass>::setKeyframeTrack(osg::ref_ptr<SceneUtil::KeyframeController> kft,
const AnimBlendStateData& newState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules)
NifAnimBlendController::NifAnimBlendController(const osg::ref_ptr<SceneUtil::KeyframeController>& keyframeTrack,
const AnimBlendStateData& newState, const 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 (newState.mGroupname != mAnimState.mGroupname || newState.mStartKey != mAnimState.mStartKey
@ -139,8 +148,22 @@ namespace MWRender
}
}
template <typename NodeClass>
void AnimBlendController<NodeClass>::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot)
void AnimBlendController::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;
}
void BoneAnimBlendController::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot)
{
// Incase group traversal encountered something that isnt a bone
if (!bone)
@ -156,8 +179,7 @@ namespace MWRender
}
}
template <typename NodeClass>
void AnimBlendController<NodeClass>::applyBoneBlend(osgAnimation::Bone* bone)
void BoneAnimBlendController::applyBoneBlend(osgAnimation::Bone* bone)
{
// If we are done with interpolation then we can safely skip this as the bones are correct
if (!mInterpActive)
@ -200,24 +222,7 @@ namespace MWRender
bone->setMatrixInSkeletonSpace(lerpedMatrix);
}
template <typename NodeClass>
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)
void BoneAnimBlendController::operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv)
{
// 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
@ -237,11 +242,10 @@ namespace MWRender
if (mInterpActive)
applyBoneBlend(node);
SceneUtil::NodeCallback<AnimBlendController<NodeClass>, osgAnimation::Bone*>::traverse(node, nv);
SceneUtil::NodeCallback<BoneAnimBlendController, osgAnimation::Bone*>::traverse(node, nv);
}
template <typename NodeClass>
void AnimBlendController<NodeClass>::operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv)
void NifAnimBlendController::operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv)
{
// 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
@ -303,6 +307,6 @@ namespace MWRender
// instantly hide/show objects in which case the scale interpolation is undesirable.
node->setScale(*scale);
SceneUtil::NodeCallback<AnimBlendController<NodeClass>, NifOsg::MatrixTransform*>::traverse(node, nv);
SceneUtil::NodeCallback<NifAnimBlendController, NifOsg::MatrixTransform*>::traverse(node, nv);
}
}

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

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

Loading…
Cancel
Save