- 动画: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 的拒读)
102 lines
4.7 KiB
C++
102 lines
4.7 KiB
C++
//
|
||
// 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
|