深度解析 Cesium 测试资产 AnimatedMorphCube:glTF 2.0 Morph Targets 变形动画的完整技术拆解
2026/9/14 12:17:43 网站建设 项目流程

深度解析 Cesium 测试资产 AnimatedMorphCube:glTF 2.0 Morph Targets 变形动画的完整技术拆解

【免费下载链接】cesiumAn open-source JavaScript library for world-class 3D globes and maps :earth_americas:项目地址: https://gitcode.com/GitHub_Trending/ce/cesium

本篇文章以 Cesium 仓库内的 glTF 2.0 测试资产 Animated Morph Cube 为核心,逐层拆解其"薄片(thin)与斜坡(angle)两个 Morph Target 之间循环变形"的动画实现,并延伸到 Cesium 引擎对 Morph Targets 的加载、权重驱动与 GPU 顶点着色管线,帮助你同时掌握"模型资产结构"与"引擎底层原理"两个层面的完整知识。

一、模型资产概述:两个 Morph Target 的变形动画

AnimatedMorphCube 是 Cesium 仓库 Specs/Data/Models/glTF-2.0/AnimatedMorphCube 下的标准 glTF 2.0 测试模型。根据其 README 的描述,这个立方体模型内置了两个 Morph Target(形态目标):

  • thin(薄片):将立方体的顶点沿特定方向移动,使其在视觉上变成"超薄"的扁平形态;
  • angle(斜坡):将立方体的顶点移动,使其构成一个斜坡(ramp)形状。

模型的动画循环在这两种状态之间平滑地来回变形。它不依赖骨骼动画(Skinning),而是完全通过 Morph Target 权重(weights)驱动顶点位移实现,是验证 glTF 2.0 Morph Target 与权重动画支持的标准样本。

该模型资产在仓库中以两种变体存在:

变体目录生成工具二进制大小
标准版glTF/AnimatedMorphCube.gltf+AnimatedMorphCube.binglTF Tools for Unity4284 字节
量化版glTF-Quantized/AnimatedMorphCube.gltf+AnimatedMorphCube.bingltfpack 0.131700 字节

二、glTF 标准资产的结构拆解:从 Accessor 到 Animation

标准版 glTF/AnimatedMorphCube.gltf 是一个自包含引用外部.bin缓冲文件的 JSON 描述,我们可以按 glTF 2.0 的层级逐层分析。

2.1 顶点数据与 Accessor 布局

模型的基础网格(mesh,名为Cube)包含 24 个顶点(count: 24),三角形索引数量为 36(count: 36,类型SCALAR,componentType 5123 即UNSIGNED_SHORT)。primitive 的属性(attributes)引用了三个 Accessor:

语义Accessor 索引类型说明
POSITION2VEC3 / FLOAT基础位置,min/max 约为 ±0.01,即边长为 0.02 的单位立方体
NORMAL0VEC3 / FLOAT法线
TANGENT1VEC4 / FLOAT切线(含 W 分量)

关键的 Morph Target 数据位于 primitive 的targets数组中,glTF 2.0 规定 targets 中的每个对象是与基础属性同结构的增量数据——即每个 target 存储的是"顶点需要被偏移的量",而不是目标位置的绝对值:

"targets": [ { "NORMAL": 3, "POSITION": 4, "TANGENT": 5 }, { "NORMAL": 6, "POSITION": 7, "TANGENT": 8 } ]
  • 第一个 target(thin)的 POSITION 增量 Accessor(索引 4)的 min 为[0, 0, 0],max 为[0, 0.01893253, 0]——所有增量仅出现在Y 轴方向,说明"薄片"形态是沿 Y 轴方向压缩/拉伸顶点产生的;
  • 第二个 target(angle)的 POSITION 增量 Accessor(索引 7)的 min 为[0, 0, 0],max 为[0, 0.0198908355, 0]——同样只有 Y 轴增量,但各顶点的增量幅值分布不同,从而把顶面推成斜坡状。

每个 target 同时携带对应的NORMALTANGENT增量,保证变形过程中光照法线能够同步更新,这是高质量 Morph Target 资产的必要设计。

2.2 Mesh 默认权重与 Animation 动画

mesh 层级声明了默认权重:

"weights": [0.0, 0.0]

即模型初始状态完全处于基础形态。真正的变形由动画驱动,动画名为Square

  • channels:一个 channel,sampler: 0target.node: 0target.path: "weights"——即动画目标是对节点 0 的 Morph Target 权重属性进行关键帧驱动;
  • samplersinterpolation: "LINEAR"(线性插值),input为 accessor 10(127 个时间采样点,min 0.0,max 约 4.2 秒),output为 accessor 11(254 个值,即 127 帧 × 2 个权重,恰好与两个 Morph Target 一一对应)。

因此整个动画循环就是:thin权重从 0→1 拉出薄片形态,再切换到angle权重 0→1 拉出斜坡形态,再回到原点,如此循环。动画作用于节点 0(名为AnimatedMorphCube),该节点还携带了旋转四元数[0, 0.7071067, -0.7071068, 0](绕 X 轴旋转 90°)和 100 倍的等比缩放,使立方体在场景中以合适的朝向与尺寸展示。

2.3 材质与元信息

材质(Material)使用 PBR 金属粗糙度模型:baseColorFactor[0.6038274, 0.6038274, 0.6038274, 1.0](中性灰),metallicFactor: 0roughnessFactor: 0.5。资产头部标注generator: "glTF Tools for Unity"version: "2.0",说明这是由 Unity 的 glTF 导出工具生成的官方标准样本。

三、Morph Target 变形原理:权重加权求和

Morph Target 的核心数学原理非常简单——最终顶点位置等于基础位置加上每个 target 增量按权重加权求和的结果。这一点在 Cesium 引擎源码中体现得淋漓尽致。

在 MorphTargetsPipelineStage.js 中,引擎为每个 Morph Target 属性生成如下 GLSL 累加代码(见addMorphTargetAttributeDeclarationAndFunctionLine,第 179-189 行):

morphedPosition += u_morphWeights[i] * a_targetPosition_i;

其中:

  • a_targetPosition_i是第 i 个 Morph Target 的 POSITION 增量属性;
  • u_morphWeights[i]是第 i 个权重 uniform;
  • morphedPosition初始值为基础position

法线、切线同理分别累加a_targetNormal_ia_targetTangent_i。这一实现与 glTF 2.0 规范中"最终顶点 = 基础顶点 + Σ(权重 × target 增量)"的定义完全一致。

四、Cesium 渲染管线中的 Morph Target 处理

4.1 管线阶段:MorphTargetsPipelineStage

Cesium 采用管线(Pipeline Stage)方式组织模型加载与渲染资源构建。当 glTF 的 primitive 携带targets时,MorphTargetsPipelineStage.js 会执行如下工作(见process方法,第 45-103 行):

  1. 在顶点着色器中定义宏HAS_MORPH_TARGETS
  2. 遍历 primitive 的所有 Morph Target 及其属性,把每个增量属性注册为顶点属性(a_targetPosition_i等);
  3. 只支持 POSITION、NORMAL、TANGENT 三种语义,其余属性直接跳过(见第 65-72 行注释 "Cesium only supports morph targets for positions, normals, and tangents");
  4. 声明 uniformu_morphWeights[N](N 为 Morph Target 数量)并注册到 uniformMap;
  5. 注入MorphTargetsStageVS顶点着色器代码。

这些注入的 GLSL 函数(getMorphedPosition/getMorphedNormal/getMorphedTangent)被 MorphTargetsStageVS.glsl 中的morphTargetsStage函数调用,在顶点着色阶段替换positionMCnormalMCtangentMC,从而在 GPU 上完成变形计算:

void morphTargetsStage(inout ProcessedAttributes attributes) { vec3 positionMC = attributes.positionMC; attributes.positionMC = getMorphedPosition(positionMC); #ifdef HAS_NORMALS vec3 normalMC = attributes.normalMC; attributes.normalMC = getMorphedNormal(normalMC); #endif #ifdef HAS_TANGENTS vec3 tangentMC = attributes.tangentMC; attributes.tangentMC = getMorphedTangent(tangentMC); #endif }

4.2 运行时节点:ModelRuntimeNode

动画运行期间,权重值存储在运行时节点上。ModelRuntimeNode.js 中定义了morphWeights属性的 setter(第 445-462 行):它要求新数组长度与原始权重数组完全一致,否则抛出DeveloperError("value must have the same length as the original weights array."),随后逐元素拷贝。这一校验确保了动画采样器输出的权重数量与 Morph Target 数量严格匹配(AnimatedMorphCube 为 2 个),从机制上避免了越界访问。

在 glTF 加载时(ModelRuntimeNode.js第 514-516 行),若节点声明了morphWeights,则直接slice()拷贝为运行时初始权重,对应本资产 mesh 上的"weights": [0.0, 0.0]

五、测试用例:仓库如何验证 Morph Target 能力

AnimatedMorphCube 在 Cesium 仓库中承担着双重测试职责:

  1. GltfLoaderSpec.js 第 1044-1047 行:"loads AnimatedMorphCube" 测试用例通过loadGltf加载该资产并断言组件加载成功,验证了完整 glTF 结构(含 Morph Targets 与权重动画)的解析路径。

  2. MorphTargetsPipelineStageSpec.js 第 153 行起:"processes morph target with POSITION, NORMAL, and TANGENT" 测试用例直接加载AnimatedMorphCube/glTF/AnimatedMorphCube.gltf,并断言:

    • 顶点着色器生成了 3 个属性(POSITION、NORMAL、TANGENT 各一的 Morph Target 增量);
    • 生成了顶点函数getMorphedPosition,函数体内包含morphedPosition += u_morphWeights[0] * a_targetPosition_0;return morphedPosition;
    • 定义了宏HAS_MORPH_TARGETS
    • 声明了 uniformu_morphWeights[1](该用例只取第一个 primitive,因此为 1),且 uniformMap 能正确返回运行时权重。

    这正是验证本资产"两个 target 各带 POSITION/NORMAL/TANGENT"结构与 Cesium 管线输出对应关系的直接证据。

  3. PrimitiveStatisticsPipelineStageSpec.js也引用了该资产用于统计管线相关断言。

六、量化版本:KHR_mesh_quantization 与 gltfpack 优化

glTF-Quantized/AnimatedMorphCube.gltf 由 gltfpack 0.13 生成,声明了扩展KHR_mesh_quantization(同时列入extensionsUsedextensionsRequired),展示了真实的量化优化手法:

数据标准版量化版
POSITION / NORMAL 分量FLOAT(5126)5120(BYTEnormalized: true
Morph Target POSITION 增量FLOAT(5126)5122(SHORT,min/max 保留量化范围)
权重输出FLOAT(5126)5121(UNSIGNED_BYTEnormalized: true
索引5123(UNSIGNED_SHORT)5123(UNSIGNED_SHORT)
二进制体积4284 字节1700 字节(压缩约 60%)

量化版将浮点属性替换为整型 + 归一化(normalized)表示,并在 accessor 的 min/max 中保留量化前的取值范围(例如 Morph Target 增量 max 从[0, 0.0189, 0]变为[0, 5188, 0],配合节点 scale 与 min/max 完成反量化还原),将顶点数据从 12 字节/分量压缩到 1~2 字节/分量。同时量化版把节点的 100 倍缩放拆分为两层(父节点AnimatedMorphCube旋转 + 子节点携带微缩比例与平移),属于 gltfpack 的常见重组优化。由于KHR_mesh_quantization被声明为extensionsRequired,加载端(如 Cesium)必须支持该扩展才能正确渲染此变体。

七、在 Cesium 中实际使用 Morph Target 资产

在 Cesium 中加载 AnimatedMorphCube 这类模型,标准方式是通过Model.fromGltf或实体系统的model图形(如Cesium.ModelGraphics)指定 glTF/glb 资源路径。加载后:

  1. 动画自动播放:glTF 内嵌的权重动画(本资产中的Square动画)会随模型动画系统播放,即model.activeAnimations.add({ name: "Square" })一类接口即可驱动 thin/angle 之间的循环变形;
  2. 手动驱动权重:可以通过运行时节点接口直接设置morphWeights数组(如[1.0, 0.0]完全展示薄片形态、[0.0, 1.0]完全展示斜坡形态),注意新数组长度必须与 Morph Target 数量一致,否则ModelRuntimeNode会抛出 DeveloperError;
  3. 光照同步:由于资产为每个 target 提供了 NORMAL/TANGENT 增量,变形过程中法线与切线会同步更新,光照与法线贴图效果保持正确。

八、许可信息

根据模型目录内 README 的声明,该资产由 Microsoft 在知识共享 CC0(公有领域)许可下发布:在法律允许的最大范围内,Microsoft 放弃对该资产的所有版权及相关邻接权利,因此它可被自由用于测试、二次分发与商业项目,这也是它作为 Cesium 测试样本能够随仓库分发的许可基础。

总结

AnimatedMorphCube 虽然只是一个"立方体",却是理解 glTF 2.0 Morph Target 全链路的最佳样本:从资产侧看,它完整展示了targets增量数据结构、默认weightsweights路径动画与 LINEAR 插值;从引擎侧看,Cesium 通过MorphTargetsPipelineStage将其转化为u_morphWeightsuniform 与顶点着色器加权累加,通过ModelRuntimeNode.morphWeights做运行时驱动与长度校验,并通过 MorphTargetsPipelineStageSpec.js 与 GltfLoaderSpec.js 两条测试路径反复验证。掌握这一样本,你便能举一反三地理解人脸表情、布料褶皱、地形过渡等一切基于 Morph Target 的 glTF 资产在 Cesium 中的工作方式。

【免费下载链接】cesiumAn open-source JavaScript library for world-class 3D globes and maps :earth_americas:项目地址: https://gitcode.com/GitHub_Trending/ce/cesium

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询