Cesium 中的 glTF 2.0 动画模型 AnimatedTriangle:缓冲区布局、四元数旋转关键帧与 ModelAnimation 驱动原理
2026/9/14 7:55:24 网站建设 项目流程

Cesium 中的 glTF 2.0 动画模型 AnimatedTriangle:缓冲区布局、四元数旋转关键帧与 ModelAnimation 驱动原理

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

导读

AnimatedTriangle 是 Cesium 仓库中内置的最简 glTF 2.0 动画示例模型:一个由 3 个顶点构成的灰色三角形,通过 glTF 动画系统绕自身旋转 360°。本文以该模型为最小案例,逐层拆解 glTF 2.0 的 Buffer/BufferView/Accessor 数据布局、LINEAR 插值下的四元数旋转关键帧,以及 Cesium 引擎中ModelAnimation/ModelAnimationCollection对 glTF 动画的驱动与循环机制。读完本文,你将能够读懂任何 glTF 模型的几何与动画 JSON 结构,并掌握在 Cesium 中播放、循环、调速模型动画的完整实战方法。

模型文件一览

AnimatedTriangle 模型位于仓库 Specs/Data/Models/glTF-2.0/AnimatedTriangle,目录结构如下:

  • glTF/AnimatedTriangle.gltf—— glTF 2.0 主 JSON 文件,描述场景、网格、动画与数据引用;
  • glTF/simpleTriangle.bin—— 44 字节几何数据缓冲(顶点位置 + 索引);
  • glTF/animation.bin—— 100 字节动画数据缓冲(时间轴 + 旋转四元数);
  • screenshot/screenshot.gifscreenshot/simpleTriangle.pngscreenshot/animation.png—— 官方效果动图与数据布局示意图。

其官方 README 声明该模型为公有领域(Public domain,CC0)授权,可自由用于学习与测试。

几何数据布局:从 Buffer 到 Accessor 的三级结构

glTF 2.0 中,几何数据按 "Buffer(缓冲)→ BufferView(缓冲视图)→ Accessor(访问器)" 三级组织。打开 AnimatedTriangle.gltf 可以看到,buffers[0]指向simpleTriangle.bin,长度 44 字节,被拆成两个 BufferView:

BufferViewbufferbyteOffsetbyteLengthtarget用途
000634963(ELEMENT_ARRAY_BUFFER)索引数据
1083634962(ARRAY_BUFFER)顶点位置属性

两个 Accessor 将原始字节解释为有语义的数据:

  • accessors[0]componentType: 5123(GL_UNSIGNED_SHORT)、type: SCALARcount: 3,即 3 个无符号短整型索引,值为[0, 1, 2],构成三角形的顶点连接顺序;
  • accessors[1]componentType: 5126(GL_FLOAT)、type: VEC3count: 3,即 3 个三维浮点位置,min: [0,0,0]max: [1,1,0],对应坐标(0,0,0)(1,0,0)(0,1,0)

可见 "Triangle" 之名名副其实:整个几何体只有 3 个顶点和 3 条索引,simpleTriangle.png示意图直观展示了这一布局。nodes[0]挂载该网格并带有初始rotation: [0,0,0,1](单位四元数),scenes[0]引用该节点,构成完整的 glTF 场景图。

动画数据:5 个关键帧的旋转通道

AnimatedTriangle 的动画核心位于 AnimatedTriangle.gltf 的animations数组,其结构如下:

"animations": [ { "samplers": [{ "input": 2, // 时间轴 accessor "interpolation": "LINEAR", "output": 3 // 旋转四元数 accessor }], "channels": [{ "sampler": 0, "target": { "node": 0, "path": "rotation" } }], "name": "Sample Animation" } ]

动画数据缓冲animation.bin(100 字节)通过单个 BufferView 暴露,再被两个 Accessor 切片使用:

  • accessors[2]SCALAR/FLOAT/count: 5,时间轴采样值[0.0, 0.25, 0.5, 0.75, 1.0](对应max: [1.0]min: [0.0]);
  • accessors[3]VEC4/FLOAT/count: 5,byteOffset 20,即 5 个四元数[x, y, z, w]max: [0,0,1,1]min: [0,0,0,-0.707]

channel 的target.path: "rotation"表明该通道驱动节点 0 的旋转。四元数序列描绘了绕 Z 轴的整圈旋转:从单位四元数(0,0,0,1)出发,经过(0,0,0.307,0.952)(0,0,1,0)(半圈)等中间姿态,最终回到起点,配合interpolation: "LINEAR"在相邻关键帧间做线性插值,形成平滑的 360° 旋转。animation.png示意图清晰标注了 TIME 与 rotation 两组访问器在 100 字节缓冲中的偏移关系(0 与 20),screenshot.gif则是该动画的实际运行效果。

对比例:同一仓库的 BoxAnimated 模型同样基于四元数关键帧驱动 node 旋转,而 BoxTextured、BoxInterleaved 则展示了顶点属性交织等不同的几何布局变体,可用于对比学习。

Cesium 中的动画运行时:ModelAnimationCollection

glTF 文件中的动画描述的是"静态的动画定义",而真正驱动它播放的是 Cesium 引擎的运行时类。Cesium 中模型动画的入口是Model#activeAnimations,其类型为 ModelAnimationCollection。

官方注释明确要求:"Access a model's animations viaModel#activeAnimations,Do not call the constructor directly"——即动画集合由模型自动创建,用户通过add/addAll/remove/removeAll管理动画实例。每次add都会创建并返回一个 ModelAnimation 实例;同一个 glTF 动画可以创建多个不同起始时间的活动实例,这正是"活动动画是动画的实例"这一设计的体现。

ModelAnimationCollection还暴露了animationAddedanimationRemoved事件(用于 UI 同步),以及animateWhilePaused属性——设为true时动画在场景时间暂停时仍可播放,但实际取决于动画自身的animationTime函数。

add 的核心参数

ModelAnimationCollection#add 的参数(节选)包括:

  • name/index:按 glTF 动画名或索引标识要播放的动画(二者必须给出其一);
  • startTime/stopTime:场景时间(JulianDate)维度的起止点,缺省时分别表示"下一帧开始"和"播满全时长";
  • delay:距startTime的延迟秒数,仅当loopNONE时生效;
  • removeOnStop:停止后自动从集合移除,仅当loopNONE时生效;
  • multiplier:播放倍速,大于 1 加速、小于 1 减速;
  • reverse:反向播放;
  • loop:循环模式(见下文)。

循环模式与状态机

循环行为由 ModelAnimationLoop 枚举控制:

  • NONE (0):只播一次;
  • REPEAT (1):播完后立即从头循环;
  • MIRRORED_REPEAT (2):先正向、再反向交替循环。

运行时状态则记录在 ModelAnimationState 中,仅有STOPPED (0)ANIMATING (1)两态,说明 Cesium 对 glTF 动画的状态管理非常轻量——动画是否"在播"由集合中的实例与时间函数共同决定。

事件钩子

每个 ModelAnimation 实例提供三个事件:

  • start:动画开始播放(在渲染完一帧后触发,可用于联动音效或粒子系统);
  • update:每帧更新时触发,回调携带当前 glTF 动画时间,可在动画进行到特定时刻时启动新动画;
  • stop:动画停止时触发。

实战:在 Cesium 中播放 AnimatedTriangle

方式一:直接加载 glTF 模型

将模型文件放入可访问的静态目录后,通过Model.fromGltfviewer.entities.addmodel图形加载:

const entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883), model: { uri: "AnimatedTriangle/glTF/AnimatedTriangle.gltf", scale: 100.0, runAnimations: true, // 默认 true }, }); entity.model.readyEvent.addEventListener((model) => { // 模型就绪后获取动画集合,按名称播放 const animations = model.activeAnimations; animations.add({ name: "Sample Animation", loop: Cesium.ModelAnimationLoop.REPEAT, multiplier: 1.0 }); });

方式二:Entity 的 runAnimations 属性

Entity 模型默认自动播放 glTF 动画。引擎内部在 ModelVisualizer 中监听model.ready,当runAnimationstrue时执行model.activeAnimations.addAll({ loop: ModelAnimationLoop.REPEAT }),一次性循环播放模型所有动画;为false时则removeAll()停止。因此想快速预览 AnimatedTriangle 的旋转,加载即可看到效果,无需写任何播放代码。

事件与参数组合示例

entity.model.readyEvent.addEventListener((model) => { const animation = model.activeAnimations.add({ name: "Sample Animation", multiplier: 2.0, // 2 倍速 reverse: true, // 反向旋转 loop: Cesium.ModelAnimationLoop.REPEAT, }); animation.start.addEventListener((m, a) => console.log(`start: ${a.name}`)); animation.update.addEventListener((m, a, t) => console.log(`glTF 时间: ${t}`)); animation.stop.addEventListener((m, a) => console.log(`stop: ${a.name}`)); });

注意事项

  • AnimatedTriangle 的动画名称为"Sample Animation"(见 AnimatedTriangle.gltf),按名称add时需精确匹配;也可改用index: 0按索引引用。
  • delayremoveOnStop仅在loop: NONE时生效;需要循环播放时请使用REPEATMIRRORED_REPEAT
  • 时间轴采样值[0.0, 1.0]表示动画时长为 1 秒(glTF 内部时间),实际播放速度同时受multiplier与场景时钟控制。

小结

从数据角度看,AnimatedTriangle 是 glTF 2.0 三级数据布局(Buffer/BufferView/Accessor)与动画系统(sampler + channel + 四元数关键帧)的最小教科书:44 字节几何 + 100 字节动画,即可表达一次完整的 360° 旋转。从引擎角度看,Cesium 通过ModelAnimationCollection将 glTF 静态动画定义实例化为可播放的活动动画,并提供循环模式、倍速、反向、事件钩子等运行时控制能力。理解了这个最小模型,你就掌握了阅读任意 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),仅供参考

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

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

立即咨询