Better narration processing

This commit is contained in:
2026-01-22 17:15:19 +03:00
parent 4b24d85123
commit cd91174f5d
23 changed files with 1301 additions and 367 deletions

View File

@@ -9,22 +9,16 @@
namespace ECS
{
class RootMotionListener : public Ogre::NodeAnimationTrack::Listener {
Ogre::Vector3 prevTranslation;
mutable Ogre::Vector3 deltaMotion;
flecs::entity e;
public:
RootMotionListener(flecs::entity e)
: Ogre::NodeAnimationTrack::Listener()
, e(e)
, prevTranslation(Ogre::Vector3::ZERO)
, deltaMotion(Ogre::Vector3::ZERO)
{
}
bool getInterpolatedKeyFrame(const Ogre::AnimationTrack *t,
const Ogre::TimeIndex &timeIndex,
Ogre::KeyFrame *kf) override
{
#if 0
Ogre::TransformKeyFrame *vkf =
static_cast<Ogre::TransformKeyFrame *>(kf);
Ogre::KeyFrame *kf1, *kf2;
@@ -36,14 +30,12 @@ public:
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
Ogre::Vector3 translation;
Ogre::Quaternion rotation;
if (tm == 0.0f) {
Ogre::Vector3 deltaMotion;
Ogre::Vector3 prevMotion;
if (tm == 0.0f) {
rotation = k1->getRotation();
translation = k1->getTranslate();
deltaMotion = translation;
// vkf->setRotation(k1->getRotation());
// vkf->setTranslate(k1->getTranslate());
// vkf->setScale(k1->getScale());
} else {
rotation = Ogre::Quaternion::nlerp(
tm, k1->getRotation(), k2->getRotation(), true);
@@ -55,14 +47,7 @@ public:
translation.squaredLength())
deltaMotion = translation;
}
#if 0
std::cout << "time: " << tm
<< " Position: " << deltaMotion;
std::cout << " Quaternion: " << rotation;
std::cout << std::endl;
#endif
vkf->setTranslate(deltaMotion);
// vkf->setTranslate(translation);
vkf->setRotation(rotation);
vkf->setScale(Ogre::Vector3(1, 1, 1));
prevTranslation = translation;
@@ -70,7 +55,9 @@ public:
e.get_mut<CharacterBase>().mBonePrevMotion = prevTranslation;
e.modified<CharacterBase>();
return true;
}
#endif
return false;
}
};
struct AnimationTrigger;
struct AnimationTriggerSubscriber {
@@ -126,46 +113,66 @@ struct AnimationTrigger {
{
}
};
struct SetupTracks {
Ogre::NodeAnimationTrack *mHipsTrack;
Ogre::NodeAnimationTrack *mRootTrack;
RootMotionListener *mListener;
Ogre::Vector3 mRootTranslation;
SetupTracks(flecs::entity e, Ogre::Skeleton *skeleton,
Ogre::Animation *animation)
: mListener(OGRE_NEW RootMotionListener(e))
{
mHipsTrack = nullptr;
mRootTrack = nullptr;
for (const auto &it : animation->_getNodeTrackList()) {
Ogre::NodeAnimationTrack *track = it.second;
Ogre::String trackName =
track->getAssociatedNode()->getName();
if (trackName == "mixamorig:Hips") {
mHipsTrack = track;
} else if (trackName == "Root") {
mRootTrack = track;
// mRootTracks[i]->removeAllKeyFrames();
}
}
if (!mRootTrack) {
Ogre::Bone *bone = skeleton->getBone("Root");
mRootTrack = animation->createNodeTrack(
bone->getHandle(), bone);
Ogre::TransformKeyFrame *kf =
mRootTrack->createNodeKeyFrame(0.0f);
kf->setTranslate(Ogre::Vector3::ZERO);
kf->setRotation(Ogre::Quaternion::IDENTITY);
}
// if (e.has<Player>()) // FIXME
// mRootTrack->setListener(mListener);
Ogre::TransformKeyFrame *tkfBeg =
(Ogre::TransformKeyFrame *)mRootTrack->getKeyFrame(0);
Ogre::TransformKeyFrame *tkfEnd =
(Ogre::TransformKeyFrame *)mRootTrack->getKeyFrame(
mRootTrack->getNumKeyFrames() - 1);
mRootTranslation =
tkfEnd->getTranslate() - tkfBeg->getTranslate();
}
};
struct Animation {
Ogre::AnimationState *mAnimationState;
Ogre::Animation *mSkelAnimation;
Ogre::NodeAnimationTrack *mHipsTrack;
Ogre::NodeAnimationTrack *mRootTrack;
RootMotionListener *mListener;
SetupTracks *mTracks;
float m_weight;
float m_accWeight;
flecs::entity e;
Ogre::Skeleton *mSkeleton;
Animation(Ogre::Skeleton *skeleton, Ogre::AnimationState *animState,
Ogre::Animation *skelAnimation, flecs::entity e)
: mAnimationState(animState)
: mTracks(OGRE_NEW SetupTracks(e, skeleton, skelAnimation))
, mAnimationState(animState)
, mSkelAnimation(skelAnimation)
, mListener(OGRE_NEW RootMotionListener(e))
, m_weight(0)
, m_accWeight(0)
, e(e)
, mSkeleton(skeleton)
{
int j;
mRootTrack = nullptr;
mHipsTrack = nullptr;
for (const auto &it : mSkelAnimation->_getNodeTrackList()) {
Ogre::NodeAnimationTrack *track = it.second;
Ogre::String trackName =
track->getAssociatedNode()->getName();
if (trackName == "mixamorig:Hips") {
mHipsTrack = track;
} else if (trackName == "Root") {
mRootTrack = track;
// mRootTracks[i]->removeAllKeyFrames();
}
}
if (!mRootTrack) {
Ogre::Bone *bone = skeleton->getBone("Root");
mRootTrack = mSkelAnimation->createNodeTrack(
bone->getHandle(), bone);
Ogre::TransformKeyFrame *kf =
mRootTrack->createNodeKeyFrame(0.0f);
kf->setTranslate(Ogre::Vector3::ZERO);
kf->setRotation(Ogre::Quaternion::IDENTITY);
}
mRootTrack->setListener(mListener);
}
Ogre::String getName()
{
@@ -198,22 +205,134 @@ struct Animation {
{
return m_weight;
}
bool addTime(float time)
Ogre::Vector3 rootMotion;
Ogre::Vector3 getRootMotionDelta()
{
#if 0
Ogre::KeyFrame *kf1, *kf2;
Ogre::TransformKeyFrame *k1, *k2;
unsigned short firstKeyIndex;
Ogre::Real timePos = mAnimationState->getTimePosition();
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(timePos);
float tm = mTracks->mRootTrack->getKeyFramesAtTime(
index, &kf1, &kf2, &firstKeyIndex);
k1 = static_cast<Ogre::TransformKeyFrame *>(kf1);
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
Ogre::Vector3 translation;
Ogre::Quaternion rotation;
if (tm == 0.0f) {
rotation = k1->getRotation();
translation = k1->getTranslate();
} else {
rotation = Ogre::Quaternion::nlerp(
tm, k1->getRotation(),
k2->getRotation(), true);
translation = k1->getTranslate() +
(k2->getTranslate() -
k1->getTranslate()) *
tm;
}
return translation * mAnimationState->getWeight();
#endif
if (mAnimationState->getEnabled())
return rootMotion * mAnimationState->getWeight();
else
return Ogre::Vector3(0, 0, 0);
}
#if 0
void updateRootMotion(Ogre::Real timePos)
{
Ogre::KeyFrame *kf1, *kf2;
Ogre::TransformKeyFrame *k1, *k2;
unsigned short firstKeyIndex;
mSkeleton->getBone("Root")->setManuallyControlled(true);
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(timePos);
float tm = mTracks->mRootTrack->getKeyFramesAtTime(
index, &kf1, &kf2, &firstKeyIndex);
k1 = static_cast<Ogre::TransformKeyFrame *>(kf1);
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
Ogre::Vector3 translation;
Ogre::Quaternion rotation;
Ogre::Vector3 deltaMotion =
e.get_mut<CharacterBase>().mBoneMotion;
Ogre::Vector3 prevTranslation =
e.get_mut<CharacterBase>().mBonePrevMotion;
if (tm == 0.0f) {
rotation = k1->getRotation() * m_weight;
translation = k1->getTranslate() * m_weight;
deltaMotion = translation;
} else {
rotation = Ogre::Quaternion::nlerp(
tm, k1->getRotation() * m_weight,
k2->getRotation() * m_weight, true);
translation = k1->getTranslate() * m_weight +
(k2->getTranslate() * m_weight -
k1->getTranslate() * m_weight) *
tm;
deltaMotion = translation - prevTranslation;
if (deltaMotion.squaredLength() >
translation.squaredLength())
deltaMotion = translation;
}
e.get_mut<CharacterBase>().mBoneMotion = deltaMotion;
e.get_mut<CharacterBase>().mBonePrevMotion = prevTranslation;
e.modified<CharacterBase>();
#if 1
if (timePos > 0.5f && m_weight > 0.2 && translation.squaredLength() > 0.0f) {
std::cout << timePos << " " << m_weight << " "
<< e.get<CharacterBase>()
.mBodyEnt->getMesh()
->getName()
<< " " << deltaMotion << " "
<< prevTranslation << std::endl;
std::cout << translation << " " << rotation << std::endl;
// OgreAssert(false, "updateRootMotion");
}
#endif
mTracks->mRootTrack->getAssociatedNode()->setPosition(
Ogre::Vector3());
mSkeleton->getBone("Root")->reset();
}
#endif
void getKeyframeIndices(Ogre::Real timePos, unsigned short *pindex)
{
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(timePos);
Ogre::KeyFrame *kf1, *kf2;
mTracks->mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2, pindex);
}
bool addTime(float time)
{
bool result = mAnimationState->getEnabled();
if (!result)
return result;
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(
mAnimationState->getTimePosition());
Ogre::KeyFrame *kf1, *kf2;
unsigned short prev_index, next_index;
mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2, &prev_index);
unsigned short prev_index, next_index;
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(mAnimationState->getTimePosition());
getKeyframeIndices(mAnimationState->getTimePosition(), &prev_index);
unsigned int previous_frame = index.getKeyIndex();
float lastTime = mAnimationState->getTimePosition();
mAnimationState->addTime(time);
index = mSkelAnimation->_getTimeIndex(
mAnimationState->getTimePosition());
mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2, &next_index);
return prev_index != next_index;
float thisTime = mAnimationState->getTimePosition();
float length = mAnimationState->getLength();
bool loop = mAnimationState->getLoop();
int loops = loop ? (int)std::round((lastTime + time - thisTime) / length) : 0;
Ogre::TransformKeyFrame tkf(0, 0);
mTracks->mRootTrack->getInterpolatedKeyFrame(lastTime, &tkf);
Ogre::Vector3 lastRootPos = tkf.getTranslate();
mTracks->mRootTrack->getInterpolatedKeyFrame(thisTime, &tkf);
Ogre::Vector3 thisRootPos = tkf.getTranslate();
#if 0
if (thisTime > lastTime)
rootMotion = thisRootPos - lastRootPos;
else
rootMotion = mTracks->mRootTranslation + thisRootPos - lastRootPos;
#else
rootMotion = (thisRootPos - lastRootPos) + (loops * mTracks->mRootTranslation);
#endif
getKeyframeIndices(mAnimationState->getTimePosition(), &next_index);
// updateRootMotion(mAnimationState->getTimePosition());
return prev_index != next_index;
}
void reset()
{
@@ -827,6 +946,14 @@ struct AnimationSystem : AnimationNode {
}
};
AnimationSystemBuilder m_builder;
Ogre::Vector3 getRootMotionDelta()
{
Ogre::Vector3 motionDelta(0, 0, 0);
int i;
for (i = 0; i < vanimation_list.size(); i++)
motionDelta += vanimation_list[i]->getRootMotionDelta();
return motionDelta;
}
bool addTime(float time)
{
int i;