Files
HelloVulkan/Engine/include/Engine/Animation/AnimationEvaluator.h
T
atdunbg beba491bcb 阶段性合并:动画重定向、碎裂共享库、第三人称玩法、编辑器面板与 vendored ufbx
- 动画:HumanoidRig 三层架构(standard 标准槽 / dialects 方言映射 / mapper 配对),
  指/趾统一走世界增量两遍式烘焙;AnimationAttach 拆为纯算法 + facade;修正 HumanoidBasis
  行走基朝向与跨骨架去重、根运动通道
- 物理:CharacterController 角色互碰撞 / shapeOffset / 接触事件;PhysicsWorld 接触合成与
  字符冲量判定
- 渲染与材质:Model 多材质按材质拆子 mesh 与贴图路径解析、DDS 直传、GLB 内嵌纹理落盘、
  不透明通道 alpha 固定 1.0、glTF FlipUVs 对齐;SceneSerializer 支持 meshIndex 与材质覆盖
- 脚本:FractureLib 抽为共享库(HostView 桥接)、WallFracture 参数直绑、新增
  ThirdPersonCamera / Follower / WASDMove 玩法;移除 GameDirector / PlayerController / Target
- 编辑器:新增 GamepadPanel、LogPanel(LogRing),改进 Inspector / 材质 / 统计 / 视口面板
- 依赖:vendored ufbx(FBX 5.x/6.x/7.x 全版本解析,替代 assimp 对 FBX 6.1 的拒读)
2026-10-11 22:22:19 +08:00

102 lines
4.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// AnimationEvaluator:骨骼动画姿态求值器(UE FAnimInstance 单节点求值 /
// Unity PlayableGraph 求值语义的极简对应物)。
//
// 动画系统职责分层(2026-10-06 重构,对齐 UE/Unity):
// Model = 资产层:node/bone/clip 静态数据(assimp 解析产物)
// AnimationComponent = 状态层:播放头/播放设置/crossfade 计时(纯数据)
// AnimationEvaluator = 求值层:clip 时间 → 全节点 global 矩阵(本文件)
// AnimationSystem = 调度层:逐实体推进状态 + 调求值器 + 产 palette
// SceneRenderer = 消费层:只读 palette/entitySkinBases 填实例
//
// 求值器无调度、无渲染依赖:同一姿态可在任意时刻重复求值(渲染主循环
// 与编辑器骨骼可视化复用同一套数学,保证"所见即所渲")。
//
#ifndef HELLOVULKAN_ANIMATIONEVALUATOR_H
#define HELLOVULKAN_ANIMATIONEVALUATOR_H
#include <Engine/Core/Types.h>
#include <Engine/Renderer/Model.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <vector>
namespace Engine::Animation {
// 单层采样的全节点局部 TRS(Layer 语义)。
// touched = 被任意轨道触碰的节点标记(ComposeGlobals 决定重建或
// 原样——FBX PreRotation 折在 localTransform 里,拆 TRS 重建会丢,
// 未触碰节点必须保持原矩阵)。容量跨帧复用,稳态零堆分配
struct LocalPose {
std::vector<glm::vec3> pos;
std::vector<glm::quat> rot;
std::vector<glm::vec3> scl;
std::vector<u8> touched;
};
// crossfade 求值快照(纯数据):src = 淡出中的来源 clip
//(nullptr = 无过渡 / 过渡已结束),wCur = 当前 clip 权重 0..1
//(smoothstep 已算好)。计时推进与 fadeFrom 状态翻转归 AnimationSystem
struct CrossfadeState {
const AnimationClip* src = nullptr;
f32 srcTime = 0.0f;
f32 wCur = 1.0f;
};
// 单个混合层:一个 clip 采样实例 + 权重。权重语义 = 归一化前的
// 相对权重(求值器内部按有效层权重和归一化;全部为 0 = rest)
struct PoseLayer {
const AnimationClip* clip = nullptr; // nullptr = 该层跳过
f32 time = 0.0f;
f32 weight = 1.0f;
};
// 姿态求值器。内部持有 N 层 LocalPose scratch(跨帧复用容量),
// 单实例非线程安全——动画推进收敛在 AnimationSystem 单点调用
class AnimationEvaluator {
public:
// cur = 当前 clip,curTime = 当前播放头(秒)。
// xf.src 非空时双层局部 TRS 混合(位置/缩放 lerp、旋转 slerp,
// 权重 = xf.wCur)→ global 累乘。
// outGlobals 尺寸 = model.GetNodes().size(),父序 DFS 累乘。
// (crossfade 双层 = EvaluateLayers 的 count==2 特例,同一套
// 加权混合数学,消掉历史双份代码)
// inPlace = 丢弃动画子树根节点的位移(Unity in-place 语义:
// 根运动开关关闭,原地播放,旋转保留)
void Evaluate(const Model& model, const AnimationClip& cur,
f32 curTime, const CrossfadeState& xf,
std::vector<glm::mat4>& outGlobals,
bool inPlace = false);
// N 层加权混合(BlendTree / 状态机过渡的通用入口):
// 逐层采样局部 TRS → 权重归一化混合(pos/scl lerp、rot 渐进
// slerp)→ global 累乘。全空/全零权重 = rest 姿态
void EvaluateLayers(const Model& model, const PoseLayer* layers,
u32 count, std::vector<glm::mat4>& outGlobals,
bool inPlace = false);
// 绑定姿势:全节点 untouched = localTransform 原样累乘。
// 与渲染 identity palette 的表现一致(无动画/组件禁用实体的
// 姿态)——骨骼可视化对非动画实体用它,保证可视化 = 渲染
void ComputeRestPose(const Model& model,
std::vector<glm::mat4>& outGlobals);
private:
// 混合循环的(pose, weight)配对视图:m_Layers 是采样存储,
// m_Sampled 指向其中的有效层并携带原权重
struct SampledLayer {
const LocalPose* pose;
f32 weight;
};
LocalPose m_A; // 混合累积层(= 直接模式当前层)
std::vector<LocalPose> m_Layers; // N 层采样 scratch(容量跨帧复用)
std::vector<SampledLayer> m_Sampled; // 有效层配对 scratch
};
} // namespace Engine::Animation
#endif