Spine 骨骼动画入门:Skeleton 运行时 3.8 版本

前面我们把高达拼好了、也写好动作程序了,现在终于到了 "上手把玩高达" 的核心环节 ------Skeleton 运行时 **。

Skeleton 运行时 = 你上手把玩拼好、写好动作程序的高达(核心是操作 + 状态实时变化),渲染就是把你把玩高达的每一个姿势、每一个动作,实时拍下来展示在屏幕上 ------ 二者结合,就是 Spine 动画从「数据加载→程序配置→实际动起来被看到」的完整闭环。

这篇用 "高达把玩" 的场景,拆解 Skeleton 运行时的核心概念(世界变换、程序化动画、初始姿势等),每个知识点都配高达类比 + 实操代码,最后附上完整把玩流程,看完就能直接上手改高达姿势~

一、先搞懂:Skeleton 运行时 = 你 "把玩高达" 的全过程

Skeleton 运行时,就是你对拼好的高达做的所有操作:

  • 让高达按程序自动动(AnimationState 驱动);
  • 手动掰高达关节调整姿势;
  • 给高达换贴纸 / 武器;
  • 把高达挪到桌子另一头;
  • 让高达的手对准某个目标(比如瞄准)。

而 Skeleton 运行时的核心机制,就是 "高达的关节怎么联动、姿势怎么算、修改后怎么生效"------ 这其中最基础、最关键的就是 "世界变换"。

二、核心基础:世界变换(高达关节怎么联动、姿势怎么算)

你掰高达的 "手臂关节",整个 "小臂 + 手" 都会跟着动 ------ 这就是 Skeleton 的 "世界变换" 机制 ,是骨骼能 "联动" 的核心。

1. 世界变换的本质:高达关节的 "父子联动"

Skeleton 的骨骼是层级结构 (像高达的 "躯干→大臂→小臂→手"),每根骨骼的姿势(位置 / 旋转 / 缩放)都会被父骨骼影响,最终计算出 "这根骨骼在整个世界中的最终姿势"(即 "世界变换")。

举个高达的例子:

  • 你掰 "大臂关节" 旋转 30 度 → 父骨骼(大臂)的世界变换变了;
  • 子骨骼(小臂、手)会自动基于大臂的新姿势,重新计算自己的世界变换 → 小臂和手跟着大臂一起转。

2. 世界变换的核心参数(高达关节的 "动效数据")

每根骨骼(Bone)都有两类变换数据,最终算出世界变换:

数据类型 对应高达关节 作用
本地变换(x/y/scaleX/scaleY/shearX/shearY) 你直接掰的关节姿势(比如大臂转 30 度) 记录 "你对这根关节的手动 / 程序修改"
世界变换(a/b/c/d/worldX/worldY) 关节最终的实际姿势(比如大臂转 30 度后,小臂的最终位置) 基于 "本地变换 + 父骨骼世界变换" 计算得出,是骨骼在整个世界中的真实状态

3. 必调方法:updateWorldTransform()(高达姿势 "锁死")

你掰完高达的关节,得 "轻轻晃一下让关节卡紧"------updateWorldTransform()就是干这个的:

  • 每次修改骨骼的本地变换(手动掰 / 程序驱动)后,必须调用它;
  • 它会按骨骼层级顺序,重新计算所有骨骼的世界变换,同时应用约束(比如 IK 关节限制);
  • 只有调用后,修改的姿势才会真正生效,渲染时才能看到新姿势。

世界变换的实操流程(代码对应高达把玩)

cpp 复制代码
// 1. 让高达按程序走一步(程序驱动修改本地变换)
state->update(deltaTime);
state->apply(*skeleton);

// 2. 手动掰高达的"躯干关节"转45度(手动修改本地变换)
Bone* torso = skeleton->findBone("torso");
torso->setRotation(45);

// 3. 锁死姿势(计算所有骨骼的世界变换,让修改生效)
skeleton->updateWorldTransform();

// 4. 拍下达当前姿势(渲染)
renderSkeleton(skeleton);

三、进阶玩法:程序化动画(手动干预高达的动作)

"程序化动画" 就是 **"在程序自动动的基础上,手动干预高达的姿势"**------ 比如高达自动走路时,你让它转头瞄准某个目标,或者让它的手始终指向鼠标。

程序化动画的核心逻辑:"程序动完,手动改"

通常的玩法是:先让高达按预设程序动,再手动修改部分关节的姿势,最后锁死姿势,这样能同时保留 "程序自动动" 和 "手动干预" 的效果。

实操样例 1:高达走路时,手动让躯干转向目标

cpp 复制代码
// 1. 找到要手动改的"躯干关节"
Bone* torso = skeleton->findBone("torso");

// 2. 让高达按程序走一步(走路动作)
state->update(deltaTime);
state->apply(*skeleton);

// 3. 手动计算躯干该转的角度(比如转向鼠标位置)
float targetRotation = calculateAimRotation(mouseX, mouseY);
torso->setRotation(targetRotation);

// 4. 锁死姿势,让"程序走路+手动转向"的效果生效
skeleton->updateWorldTransform();

// 5. 渲染新姿势
renderSkeleton(skeleton);

实操样例 2:基于世界变换调整(更精准的手动干预)

如果要 "先看高达当前的姿势,再手动调整",可以先算一次世界变换,再修改:

cpp 复制代码
Bone* torso = skeleton->findBone("torso");

// 1. 程序驱动+先算一次世界变换(拿到高达当前的姿势)
state->update(deltaTime);
state->apply(*skeleton);
skeleton->updateWorldTransform();

// 2. 基于当前姿势,手动微调躯干角度
float currentRotation = torso->getWorldRotation(); // 拿到躯干当前的世界角度
torso->setRotation(currentRotation + 10); // 再转10度

// 3. 再算一次世界变换,让微调生效
skeleton->updateWorldTransform();

// 4. 渲染
renderSkeleton(skeleton);

四、基础重置:Setup Pose(让高达回到 "刚拼好的初始姿势")

"Setup Pose" 就是高达的 **"初始姿势"**------ 刚拼好时的默认姿势,所有关节都在初始位置,贴纸都在默认位置。

什么时候用 Setup Pose?

  • 高达姿势掰乱了,一键恢复初始状态;
  • 切换皮肤 / 动作前,先回到初始姿势,避免状态混乱。

核心方法(对应高达操作)

方法 高达操作 作用
setToSetupPose() 把掰乱的高达恢复成刚拼好的样子 重置所有骨骼、插槽、附件到初始状态
setBonesToSetupPose() 只把关节恢复到初始位置,贴纸保持不变 仅重置骨骼姿势
setSlotsToSetupPose() 只把贴纸恢复到初始位置,关节姿势保持不变 仅重置插槽 / 附件

实操样例:切换皮肤前,先重置插槽到初始姿势

cpp 复制代码
// 1. 把高达的贴纸恢复到初始位置
skeleton->setSlotsToSetupPose();

// 2. 切换皮肤(换一套贴纸)
skeleton->setSkin("new_skin");

// 3. 锁死姿势
skeleton->updateWorldTransform();

五、扩展玩法:用骨骼世界变换做特效(高达的手放粒子特效)

Skeleton 的骨骼世界变换(worldX/worldY),可以用来 **"把特效 / UI 绑定到高达的某个部位"**------ 比如高达的手开枪时,在手心位置放 "枪口火焰" 特效。

实操样例:在高达的右手位置画粒子特效

cpp 复制代码
// 1. 找到"右手关节"
Bone* rightHand = skeleton->findBone("right_hand");

// 2. 程序驱动+算世界变换(拿到右手当前的位置)
state->update(deltaTime);
state->apply(*skeleton);
skeleton->updateWorldTransform();

// 3. 渲染高达
renderSkeleton(skeleton);

// 4. 在右手的世界位置,画粒子特效
renderParticles(rightHand->getWorldX(), rightHand->getWorldY());

六、通用渲染逻辑(把把玩的高达拍下来)

渲染的本质,就是 **"按高达当前的姿势,把每个贴纸(附件)画到对应的位置"**------ 核心是遍历 Skeleton 的drawOrder(插槽绘制顺序),按顺序画每个附件。

渲染核心流程(代码伪代码)

cpp 复制代码
// 遍历高达的"贴纸挂钩顺序"(drawOrder)
for (Slot* slot : skeleton->getDrawOrder()) {
    // 拿到挂钩上的贴纸(附件)
    Attachment* attachment = slot->getAttachment();
    if (attachment == nullptr) continue;

    // 处理不同类型的贴纸(比如矩形贴纸、网格贴纸)
    if (attachment->isRegionAttachment()) {
        RegionAttachment* region = (RegionAttachment*)attachment;
        // 计算贴纸的顶点位置(基于骨骼的世界变换)
        region->computeWorldVertices(slot->getBone(), vertices);
        // 拿到贴纸对应的纹理
        Texture* texture = region->getRendererObject()->page->getRendererObject();
        // 画贴纸
        draw(texture, vertices, region->getTriangles());
    } else if (attachment->isMeshAttachment()) {
        // 网格贴纸的处理逻辑(类似,只是顶点更多)
        MeshAttachment* mesh = (MeshAttachment*)attachment;
        mesh->computeWorldVertices(slot->getBone(), vertices);
        Texture* texture = mesh->getRendererObject()->page->getRendererObject();
        draw(texture, vertices, mesh->getTriangles());
    }
}

七、完整把玩流程总结(代码可直接复用)

把前面的所有操作,整合成 "程序驱动 + 手动干预 + 渲染" 的完整把玩流程:

cpp 复制代码
// 前期准备:拼好高达+写好动作程序
Skeleton* skeleton = getLoadedSkeleton();
AnimationState* state = getAnimationState();

float deltaTime = 1.0f / 60.0f;
while (true) {
    // 1. 让高达按程序走一步(走路动作)
    state->update(deltaTime);
    state->apply(*skeleton);

    // 2. 手动干预:让躯干转向鼠标
    Bone* torso = skeleton->findBone("torso");
    float targetRotation = calculateAimRotation(mouseX, mouseY);
    torso->setRotation(targetRotation);

    // 3. 锁死当前姿势(程序+手动的混合效果)
    skeleton->updateWorldTransform();

    // 4. 渲染高达当前的姿势
    renderSkeleton(skeleton);

    // 5. 在右手位置画粒子特效
    Bone* rightHand = skeleton->findBone("right_hand");
    renderParticles(rightHand->getWorldX(), rightHand->getWorldY());
}

八、核心必记要点(把玩高达不踩坑)

  1. updateWorldTransform()必调:任何修改骨骼的操作后,必须调用它,否则姿势不生效;
  2. 程序化动画的顺序 :先state->apply(程序驱动),再手动改,最后updateWorldTransform
  3. Setup Pose 的作用:状态混乱时,一键重置到初始姿势,避免 bug;
  4. 世界变换是最终状态:渲染 / 特效都用世界变换的数据,本地变换只是 "中间修改值"。

到这里,Skeleton 运行时的核心逻辑就全通了 ------ 本质就是 "怎么把玩高达":从基础的关节联动,到手动干预姿势,再到绑定特效,都是围绕 "修改 Skeleton 状态→算世界变换→渲染" 的流程。

相关推荐
茉莉玫瑰花茶7 天前
Spine 软件入门学习笔记:面向 2D 游戏动画 + C++ API 开发 - 1
学习·spine
小码哥kylin3 个月前
spine动画监听动作播放完成重复执行
cocoscreator·spine
da_vinci_x4 个月前
2D角色动画进阶:Spine网格变形与序列帧特效的混合工作流
游戏·设计模式·设计师·photoshop·spine·游戏策划·游戏美术
黑客飓风6 个月前
Spine动画入门
spine
Tipriest_7 个月前
基于 Web 的 3D 设计工具Spline介绍
前端·3d·3d设计·spine·网页制作
MF_AI1 年前
颈椎X光数据集(cervical spine X-ray dataset)
图像处理·人工智能·深度学习·yolo·计算机视觉·spine
CN-Dust1 年前
【Spine】引入PhotoshopToSpine脚本
spine
是嘟嘟啊1 年前
【Unity】在Unity 3D中使用Spine开发2D动画
3d·unity·spine·spine pro·龙骨·dragonbones·spine unity
小张不爱写代码1 年前
Unity 使用Spine动画切换时有残影
unity·spine