Files
SpineParticlesWeb/Document/网页粒子系统阶段十一.md
2026-09-02 10:45:10 +08:00

22 KiB
Raw Permalink Blame History

网页粒子系统 · 阶段十一

阶段定位:Spine JSON 导出体系、拖尾蒙皮定版与曲线编辑能力完善
完成日期:2026-08-31
工程目录:/Users/tianmokeji/Desktop/SpineParticle
技术栈:Vue 3 + TypeScript + Pinia + PixiJS 7 + Spine Runtime 4.2 + Vite


一、阶段结论

阶段十一在阶段十的序列帧和循环持续动画体系上,完成了第一版可重新导入 Spine 编辑器继续编辑的 Spine 4.2 JSON 导出功能,并围绕实际导入结果持续修正了骨骼层级、关键帧数量、加权 Mesh 拓扑、拖尾生命周期和首帧语义。

本阶段没有把粒子效果导出为不可编辑的逐帧图片,而是把粒子运行结果烘焙为 Spine 可编辑结构:粒子使用独立骨骼和插槽,拖尾使用同级骨骼组与加权 Mesh,运动、旋转、缩放和 RGBA 进入 Spine 时间轴。碰撞、路径和 Spine 预览对象不直接导出,与粒子有关的最终表现均烘焙到粒子动画数据中。

本阶段主要完成:

  1. 实现 Spine 4.2 JSON 导出设置与文件下载;
  2. 建立独立导出模块、关键帧精简模块、Mesh 构建模块和结构校验模块;
  3. 粒子系统导出为系统骨骼、粒子骨骼、插槽和附件;
  4. 拖尾导出为固定拓扑加权 Mesh 与同级拖尾骨骼组;
  5. 图片只写资源路径,不把图片文件写入 JSON;
  6. 隐藏粒子系统不导出,图片缺失时仍保留附件路径;
  7. 支持固定图和序列帧附件时间轴;
  8. 支持线性与平滑贝塞尔关键帧精简;
  9. 按数据类型设置导出误差容限;
  10. 修正 Spine 版本字段为 4.2
  11. 修正拖尾 Mesh 的 hull、edges、三角形和权重结构;
  12. 粒子骨骼增加粒子系统父级,拖尾骨骼改为同级结构;
  13. 拖尾整组骨骼同生同死,假死改为插槽透明度控制;
  14. 拖尾未展开阶段同时插值位置和旋转;
  15. 曲线编辑器实现真正的贝塞尔控制手柄;
  16. “跟随导出”模式正确读取全局插值设置,不再反向覆盖设置;
  17. 普通发射模式第 0 帧固定为空,循环持续保留独立衔接规则;
  18. 修复 update(0) 导致爆发数量重复的问题;
  19. 画布骨骼调试增加固定屏幕尺寸的方向轴;
  20. 拖尾资源增加拖尾比例以及固定/随机长度、宽度;
  21. 增加新手使用说明弹窗;
  22. 完成 TypeScript、Vite、浏览器交互和 Spine Runtime 解析验证。

详细且长期有效的导出约束另见:

导出设计标准规范.md

阶段十一文档记录实际开发结果;导出设计标准规范记录后续导出功能必须继续遵守的标准。


二、Spine JSON 导出范围

2.1 导出对象

当前只导出可见粒子系统:

visible !== false

不会直接导出:

  • 碰撞对象;
  • 场景路径;
  • 加载进编辑器用于预览的 Spine 对象;
  • 背景图;
  • 画布网格、发射点和调试骨骼;
  • 编辑器 UI 状态。

如果粒子运动受到碰撞、路径或其他模块影响,导出的是已经计算完成的粒子最终位置、旋转、缩放和颜色,不保留对外部模块的运行时引用。

2.2 图片资源

JSON 不内嵌 PNG,也不额外复制图片。附件只写入正确的图片资源路径。导入 Spine 后,由用户重新选择图片文件夹完成扫描。

图片缺失不会阻止导出。导出器会:

  1. 保留原图片文件名和路径;
  2. 使用可用尺寸或安全占位尺寸建立附件;
  3. 在导出结果中返回资源提示;
  4. 允许用户在 Spine 中按文件名补齐图片。

默认图片路径:

./images/

2.3 文件名和版本

默认导出文件名:

SpineParticle.json

骨架版本字段固定为:

{
  "skeleton": {
    "spine": "4.2"
  }
}

第一版设置面板只提供 Spine 4.2,不伪装支持其他版本。


三、导出设置

3.1 当前参数

导出设置模块包含:

参数 当前规则
图片路径 写入 skeleton.images
Spine 版本 固定 Spine 4.2
关键帧插值曲线 线性或平滑贝塞尔
导出 FPS 默认 30
不写 fps 只省略元数据,不改变动画时间
整数帧对齐 调整采样帧率时保持实际秒数不变
骨骼对象池 默认开启,稳定复用粒子骨骼轨道
排除无内容动画 按开关决定是否保留空动画

3.2 FPS 规则

修改导出 FPS 时保持动画实际秒数不变。

例如原动画为 30 FPS、30 帧,即 1 秒;改为 60 FPS 后会重采样到约 60 帧,仍保持 1 秒,而不是把 30 帧直接解释为 0.5 秒。

“不写 fps”只影响:

skeleton.fps

不会改变关键帧的 time 秒数。

3.3 空动画

空动画是否保留完全遵循“排除无内容动画”设置。

关闭开关时,即使动画当前没有粒子时间轴,也保留空动画名称,方便后续在 Spine 工程内继续编辑或与其他动画合并。


四、导出骨骼层级

4.1 粒子系统父级

每个粒子系统建立一根系统骨骼,直接挂在 root 下:

root
└─ ParticleSystem1

粒子骨骼和拖尾骨骼全部直接挂在粒子系统骨骼下:

root
└─ ParticleSystem1
   ├─ _particle_000
   ├─ _particle_000_trail_1_0
   ├─ _particle_000_trail_1_1
   └─ _particle_000_trail_1_2

不再使用以下错误结构:

root
├─ ParticleSystem1_particle_000
├─ ParticleSystem1_particle_001
└─ ParticleSystem1_particle_002

4.2 拖尾骨骼不组成骨骼链

早期导出把拖尾骨骼首尾相接:

trail_0
└─ trail_1
   └─ trail_2

这种结构会让子骨骼继承父骨骼的位置、旋转和缩放,导致世界变换逐级累积。网页画布与 Spine 编辑器中的拖尾表现因此不一致。

当前规则是所有拖尾骨骼同级:

ParticleSystem1
├─ trail_0
├─ trail_1
└─ trail_2

每根拖尾骨骼独立写入:

  • 世界位置;
  • 世界旋转;
  • 宽度和形状需要的缩放。

导出校验器会阻止拖尾骨骼再次组成父子链。

4.3 设置姿态

所有系统骨骼和粒子骨骼的设置姿态保持安全默认值:

位置:0, 0
旋转:0
缩放:1, 1

拖尾同级骨骼也从原点设置姿态开始,实际位置和旋转写入动画时间轴,避免设置姿态破坏 Mesh 蒙皮。

附件默认颜色使用透明状态,导入 Spine 后不会在设置模式中干扰已有图像显示。


五、粒子附件和动画

5.1 粒子图片

每根粒子骨骼根据图片混合模式创建相应插槽。支持:

  • normal
  • additive
  • multiply
  • screen。

固定图片使用区域附件。序列帧图片在同一插槽中通过 attachment 时间轴切换附件,不会为每张序列图创建新骨骼。

5.2 粒子动画时间轴

粒子骨骼导出:

  • translate
  • rotate
  • scale。

粒子插槽导出:

  • attachment
  • rgba。

粒子出生、死亡、资源切换和序列帧切换会被识别为强制边界,关键帧精简不能跨过这些离散事件破坏状态。

5.3 骨骼对象池

开启骨骼对象池后,同一粒子池槽位在多个出生周期中复用同一根导出骨骼。粒子死亡阶段通过附件显隐和 RGBA 时间轴表达,而不是不断创建新的骨骼名称。

该规则显著降低高发射率粒子系统的骨骼数量,并让重新导入 Spine 后的层级更适合继续编辑。


六、关键帧精简

6.1 数据容差

阶段十一最终采用以下导出容差:

数据 容差
粒子位置 0.1 像素
拖尾骨骼位置 0.1 像素
旋转 0.01°
缩放 0.01
透明度 0.01
RGB 单通道 1/255

这些数值用于判断中间关键帧是否可以由相邻关键帧安全重建。

6.2 线性模式

线性模式使用误差受控的数值关键帧精简。如果一段位置、旋转、缩放或颜色变化可以由线性插值在容差内还原,则只保留必要端点。

出生、死亡、附件切换和突变帧不会被普通线性精简跨越。

6.3 平滑贝塞尔

平滑贝塞尔模式对逐帧烘焙结果进行分段三次曲线拟合,并把控制值写入 Spine 曲线数据。

该模式主要用于:

  • 曲线运动;
  • 非线性透明度;
  • 平滑颜色变化;
  • 受修改器影响的连续轨迹。

拟合不会过度激进,优先保留动画精度和 Spine 编辑器中的可编辑性。

6.4 旋转展开

旋转精简前会先展开跨越 -180°/180° 的角度序列,避免真实连续旋转被误判为反方向大跳变。


七、曲线编辑器

7.1 三种模式

带“曲线模式”的参数支持:

模式 行为
跟随导出 读取导出设置的关键帧插值模式
线性 当前参数强制使用线性
贝塞尔 当前参数强制使用贝塞尔

“跟随导出”是单向读取关系:

导出设置 → 当前曲线参数

它不会反向修改导出设置。

7.2 贝塞尔控制手柄

曲线编辑器的贝塞尔模式现在会显示:

  • 节点输入手柄;
  • 节点输出手柄;
  • 节点到手柄的辅助线;
  • 三次贝塞尔实际曲线路径。

手柄位置作为曲线点的相对数据保存:

inX / inY
outX / outY

这些字段自动进入配置保存、加载、预设和撤回快照。

未手动调整的贝塞尔手柄默认位于相邻节点三分之一位置,因此初始外观仍与线性一致,但用户可以拖动手柄改变曲率。

7.3 当前联动范围

当前已接入曲线模式解析的主要参数:

  • 粒子系统透明度曲线;
  • 图片资源独立透明度曲线;
  • 碰撞对象路径跟随曲线。

粒子实时预览与导出使用同一套“跟随导出”解析结果。


八、拖尾加权 Mesh

8.1 固定拓扑

每个拖尾附件只建立一次固定拓扑 Mesh。生命周期中不会改变:

  • 顶点数量;
  • UV 数量;
  • 三角形索引;
  • hull 顶点数量;
  • edges
  • 顶点骨骼权重结构。

动画只改变拖尾骨骼和插槽数据,绝不在不同帧生成不同数量的网格顶点。

8.2 hull 与顶点顺序

Spine JSON 的 hull 表示顶点数组开头连续存放的外轮廓顶点数量。Mesh 构建器会先按顺时针顺序写入四周轮廓,再追加内部网格点。

该规则修复了早期导入 Spine 后出现的异常外轮廓、顶点连线和导入失败问题。

8.3 权重

每个网格列最多受相邻两根拖尾骨骼影响。权重之和严格为 1。

拖尾骨骼改成同级后,顶点局部位置不再依赖链式设置姿态偏移。每列中心主要由骨骼动画位置与相邻骨骼权重插值得到,网格宽度由骨骼 Y 缩放和局部横向顶点共同表达。

8.4 导入前校验

下载前会检查:

  • UV 数量是否合法;
  • 顶点编码是否合法;
  • 三角形是否越界;
  • hull 是否越界;
  • edges 是否为有效偶数索引;
  • 骨骼索引是否存在;
  • 每个顶点权重之和是否为 1
  • 加权 Mesh 是否使用了空附件;
  • 拖尾骨骼是否错误组成骨骼链。

随后使用项目内 Spine 4.2 Runtime 的 SkeletonJson 再解析一次,只有通过后才触发下载。


九、拖尾骨骼生命周期

9.1 整组出生和死亡

一个拖尾 Mesh 绑定的全部骨骼属于同一个固定骨骼组。只要该粒子生成拖尾,这组骨骼必须:

  • 同一帧出生;
  • 同一帧进入活动状态;
  • 同步移动;
  • 同一帧死亡或假死。

禁止根据轨迹长度逐节激活骨骼。旧字段 activeBoneCount 只保留配置兼容意义,当前有效状态始终等于拖尾骨骼总数。

9.2 未完全展开时的位置

拖尾刚生成时,历史轨迹可能短于配置长度。当前规则不是把后方骨骼全部堆叠在最旧点,而是:

  1. 从粒子出生点开始记录首个轨迹段;
  2. 计算当前已经积累的有效轨迹长度;
  3. 在有效轨迹内把全部拖尾骨骼等距分布;
  4. 随有效轨迹增长,整组骨骼逐渐展开到完整配置长度。

因此即使拖尾尚未达到完整长度,Mesh 也始终由完整骨骼组驱动。

9.3 未完全展开时的旋转

位置插值期间,旋转也必须平滑。

当前做法:

  1. 计算头部切线方向;
  2. 计算当前尾端切线方向;
  3. 将角度差转换为最短旋转方向;
  4. 按骨骼序号在头尾角度之间插值;
  5. 达到完整轨迹长度后恢复按真实局部切线计算。

这样可以避免同级骨骼方向突然折跳造成网格不平滑。

缩放不参与这段“轨迹不足”的补间,继续由拖尾宽度和形状参数控制。

9.4 假死方式

早期方案把尚未出现或死亡的拖尾骨骼缩放到 0。整组骨骼生命周期统一后,不再需要逐骨骼缩放假死。

当前规则:

拖尾存在:插槽 alpha = 实际透明度
拖尾不存在:插槽 alpha = 0

骨骼缩放始终保留,原因是缩放还负责:

  • 拖尾宽度;
  • 粒子宽度跟随;
  • 拖尾形状曲线;
  • 后续在 Spine 中继续编辑。

出生前使用首次有效骨骼姿态但插槽透明,死亡后保持最后有效骨骼姿态但插槽透明。Mesh 和骨骼对象不会在时间轴中删除和重建。


十、拖尾比例与随机尺寸

10.1 拖尾比例

每张拖尾资源卡片新增:

拖尾比例 (%)

有效范围为 0100

数值 行为
0 选中该资源的粒子均不生成拖尾
50 约一半粒子生成拖尾
100 所有选中该资源的粒子生成拖尾

判断发生在粒子出生时,使用粒子系统随机种子和周期内出生序号,因此相同配置与种子可以稳定复现。

当当前发射段计算出的粒子数量为 1、拖尾比例大于 0 时,第一颗粒子强制生成拖尾,避免开启拖尾却因概率采样完全看不到效果。比例明确设置为 0 时不执行保底。

10.2 长度和宽度模式

拖尾长度与宽度分别支持:

模式 参数
固定 单一比例值
随机范围 最小比例和最大比例

默认值:

固定长度:100%
固定宽度:100%
随机最小:100%
随机最大:100%

尺寸解释:

数值 行为
0 不生成拖尾
100 使用标准长度或宽度
200 标准尺寸的 2 倍

为支持超过 100 的比例放大,界面当前允许输入 0~500。

随机长度和宽度分别使用独立确定性采样,不会因为其他随机参数增加或删除而改变结果。

10.3 导出适配

不同粒子可以拥有不同拖尾长度和宽度:

  • 长度通过每根拖尾骨骼的实际动画位置表达;
  • 宽度通过骨骼 Y 缩放表达;
  • 形状曲线继续叠加到各骨骼宽度缩放;
  • 没有生成拖尾的粒子不创建对应拖尾动画内容;
  • 某个资源在整条轨道中从未出现拖尾时,不创建无用 Mesh 和拖尾骨骼。

十一、第 0 帧与发射规则

11.1 普通发射模式

以下模式第 0 帧固定为空:

  • 爆发;
  • 常规持续。

所有粒子发射行为从第 1 帧开始。第 0 帧画布中:

粒子数量 = 0
粒子骨骼数量 = 0
拖尾骨骼数量 = 0

11.2 循环持续例外

循环持续不受普通第 0 帧空白规则约束,而是继续使用阶段十已经确定的三段逻辑:

循环状态 第 0 帧
生成开始循环动画 空帧
纯循环 循环衔接帧,可包含骨骼
生成结束循环动画 循环衔接帧,可包含骨骼

缓存生成层和画布显示层都按粒子系统分别判断,不会因为同一场景中存在普通系统而错误清空循环系统的衔接帧。

11.3 爆发重复修复

时间轴固定帧之间会调用:

update(0)

用于保持当前画面而不推进时间。旧爆发判断使用:

burstTimer <= dt

dt = 0 时,0 <= 0 被误认为第一次爆发,导致设置单次数量为 1 时实际出现 2 个粒子。

当前增加明确限制:

dt > 0

零时间刷新不再触发发射。浏览器回归验证结果:

单次数量 = 1
第 0 帧粒子 = 0
第 1 帧粒子 = 1

十二、画布骨骼调试

12.1 骨骼方向轴

开启系统设置中的“骨骼连线”后,每个粒子骨骼和拖尾骨骼点都会显示局部方向轴:

颜色 含义
青色 骨骼正方向
黄色 与正方向垂直的辅助轴

粒子方向轴会处理网页画布 Y 轴向下与数学旋转方向的差异;拖尾方向轴直接使用拖尾轨迹切线旋转。

画布中的拖尾连接线也已改为同级语义,不再把相邻拖尾骨骼画成父子链。

12.2 固定屏幕尺寸

骨骼点和方向轴的视觉尺寸不随画布缩放改变。绘制前先把目标屏幕像素除以当前画布缩放,确保放大或缩小画布后调试标记仍保持相同大小。

系统设置新增:

骨骼点绘制大小:默认 1
坐标轴绘制大小:默认 2

有效范围为 0.110。参数会进入:

  • 配置保存;
  • 配置加载;
  • 预设;
  • 撤回快照。

旧配置缺少字段时自动恢复默认值。


十三、使用说明

画布右上角增加“使用说明”按钮。点击后显示可关闭的新手说明弹窗,内容包括:

  • 创建和选择场景对象;
  • 粒子常用面板;
  • 时间轴播放和逐帧查看;
  • 图片、序列帧和拖尾资源;
  • 配置保存、加载和预设;
  • Spine JSON 导出;
  • 常用快捷键。

弹窗不会改变编辑器配置,也不会阻塞画布以外的配置数据。


十四、配置、撤回与兼容

阶段十一新增的重要配置字段包括:

曲线点:inX / inY / outX / outY
系统设置:bonePointDrawSize / boneAxisDrawSize
拖尾资源:trailRatio
拖尾资源:lengthMode / lengthMin / lengthMax
拖尾资源:widthSizeMode / widthMin / widthMax

这些字段会自动进入编辑器 JSON 配置、预设、对象复制和撤回快照。

拖尾资源版本升级到:

trailResourceVersion = 6

旧资源迁移规则:

  • 缺少拖尾比例时使用 100
  • 缺少长度模式时使用固定;
  • 长度随机范围初始化为旧固定长度;
  • 缺少宽度模式时使用固定;
  • 宽度随机范围初始化为旧固定宽度;
  • 旧配置已有的长度和宽度数值保持不变,不强制覆盖为 100;
  • 新建资源和重置资源使用 100 的新默认值。

十五、主要代码落点

文件 阶段十一职责
src/export/spineJsonExporter.ts Spine JSON 文档、骨骼层级、动画时间轴、拖尾整组显隐、文件下载
src/export/spineKeyframeReducer.ts 线性与贝塞尔关键帧误差精简、控制值拟合、角度展开
src/export/spineMeshBuilder.ts 同级拖尾骨骼加权 Mesh、UV、三角形、hull、edges 和顶点权重
src/export/spineJsonValidator.ts Mesh 结构、拖尾层级与 Spine 4.2 Runtime 解析校验
src/export/spineExportSettings.ts 导出参数默认值与旧设置补齐
src/core/particleEmitter.ts 贝塞尔曲线采样、爆发修复、拖尾比例、随机尺寸、整组骨骼插值和录制状态
src/views/CurveEditor.vue SVG 贝塞尔路径、输入/输出控制手柄和节点编辑
src/views/ParticlePanel.vue 导出设置、拖尾资源比例、固定/随机尺寸、曲线模式与导出按钮
src/views/Stage.vue 第 0 帧规则、循环例外、骨骼方向轴、固定调试尺寸、缓存录制和回放
src/store/particleStore.ts 新系统设置字段和时间轴状态
src/editor/editorConfig.ts 新字段保存、加载、旧配置补齐与纹理恢复
导出设计标准规范.md Spine 导出长期标准与不可回退约束

十六、验证结果

16.1 构建

阶段结束执行:

npm run build

结果:

  • vue-tsc -b 通过;
  • Vite 生产构建通过;
  • 553 个模块完成转换;
  • 无 TypeScript 错误;
  • 无构建错误;
  • 仅保留既有的大包体积提示。

16.2 Spine JSON

使用 TrailTest 数据构造拖尾导出样例并通过项目内 Spine 4.2 Runtime 解析:

拖尾骨骼数量:3
拖尾骨骼父级:全部为 ParticleSystem1
动画数量:1
Mesh 顶点和 UV:固定且匹配

整组假死验证:

骨骼缩放归零:false
插槽透明度:00 → bf → 00

即骨骼缩放完整保留,拖尾通过统一插槽透明度出现和消失。

16.3 浏览器交互

已验证:

  • 贝塞尔模式显示控制手柄;
  • 跟随导出 + 线性时不显示贝塞尔手柄;
  • 跟随导出 + 平滑贝塞尔时显示手柄;
  • 第 0 帧普通粒子数量为 0
  • 爆发数量 1 时第 1 帧粒子数量为 1;
  • 骨骼方向轴正常显示;
  • 骨骼点绘制大小默认 1
  • 坐标轴绘制大小默认 2
  • 拖尾比例默认 100
  • 长度和宽度可切换固定与随机范围;
  • 随机范围初值正确继承当前固定值。

十七、阶段十一最终状态

阶段十一完成后,编辑器已经具备:

  • 可重新导入 Spine 4.2 编辑器的粒子 JSON
  • 可编辑粒子骨骼、插槽和附件;
  • 固定拓扑加权拖尾 Mesh
  • 同级拖尾骨骼结构;
  • 整组拖尾骨骼生命周期;
  • 插槽透明度假死;
  • 未展开拖尾的位置与旋转平滑插值;
  • 误差受控的关键帧精简;
  • 线性和贝塞尔导出模式;
  • 可操作的贝塞尔曲线手柄;
  • 普通发射第 0 帧空白规则;
  • 循环持续独立第 0 帧衔接规则;
  • 正确的单次爆发数量;
  • 固定屏幕尺寸的骨骼点与方向轴;
  • 拖尾比例与确定性随机长度、宽度;
  • 配置、预设、复制和撤回完整联动;
  • 下载前 Spine 4.2 结构校验。

至此,阶段十一“Spine JSON 导出体系与拖尾蒙皮定版”完成落盘。