22 KiB
网页粒子系统 · 阶段十一
阶段定位: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 预览对象不直接导出,与粒子有关的最终表现均烘焙到粒子动画数据中。
本阶段主要完成:
- 实现 Spine 4.2 JSON 导出设置与文件下载;
- 建立独立导出模块、关键帧精简模块、Mesh 构建模块和结构校验模块;
- 粒子系统导出为系统骨骼、粒子骨骼、插槽和附件;
- 拖尾导出为固定拓扑加权 Mesh 与同级拖尾骨骼组;
- 图片只写资源路径,不把图片文件写入 JSON;
- 隐藏粒子系统不导出,图片缺失时仍保留附件路径;
- 支持固定图和序列帧附件时间轴;
- 支持线性与平滑贝塞尔关键帧精简;
- 按数据类型设置导出误差容限;
- 修正 Spine 版本字段为
4.2; - 修正拖尾 Mesh 的 hull、edges、三角形和权重结构;
- 粒子骨骼增加粒子系统父级,拖尾骨骼改为同级结构;
- 拖尾整组骨骼同生同死,假死改为插槽透明度控制;
- 拖尾未展开阶段同时插值位置和旋转;
- 曲线编辑器实现真正的贝塞尔控制手柄;
- “跟随导出”模式正确读取全局插值设置,不再反向覆盖设置;
- 普通发射模式第 0 帧固定为空,循环持续保留独立衔接规则;
- 修复
update(0)导致爆发数量重复的问题; - 画布骨骼调试增加固定屏幕尺寸的方向轴;
- 拖尾资源增加拖尾比例以及固定/随机长度、宽度;
- 增加新手使用说明弹窗;
- 完成 TypeScript、Vite、浏览器交互和 Spine Runtime 解析验证。
详细且长期有效的导出约束另见:
导出设计标准规范.md
阶段十一文档记录实际开发结果;导出设计标准规范记录后续导出功能必须继续遵守的标准。
二、Spine JSON 导出范围
2.1 导出对象
当前只导出可见粒子系统:
visible !== false
不会直接导出:
- 碰撞对象;
- 场景路径;
- 加载进编辑器用于预览的 Spine 对象;
- 背景图;
- 画布网格、发射点和调试骨骼;
- 编辑器 UI 状态。
如果粒子运动受到碰撞、路径或其他模块影响,导出的是已经计算完成的粒子最终位置、旋转、缩放和颜色,不保留对外部模块的运行时引用。
2.2 图片资源
JSON 不内嵌 PNG,也不额外复制图片。附件只写入正确的图片资源路径。导入 Spine 后,由用户重新选择图片文件夹完成扫描。
图片缺失不会阻止导出。导出器会:
- 保留原图片文件名和路径;
- 使用可用尺寸或安全占位尺寸建立附件;
- 在导出结果中返回资源提示;
- 允许用户在 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 未完全展开时的位置
拖尾刚生成时,历史轨迹可能短于配置长度。当前规则不是把后方骨骼全部堆叠在最旧点,而是:
- 从粒子出生点开始记录首个轨迹段;
- 计算当前已经积累的有效轨迹长度;
- 在有效轨迹内把全部拖尾骨骼等距分布;
- 随有效轨迹增长,整组骨骼逐渐展开到完整配置长度。
因此即使拖尾尚未达到完整长度,Mesh 也始终由完整骨骼组驱动。
9.3 未完全展开时的旋转
位置插值期间,旋转也必须平滑。
当前做法:
- 计算头部切线方向;
- 计算当前尾端切线方向;
- 将角度差转换为最短旋转方向;
- 按骨骼序号在头尾角度之间插值;
- 达到完整轨迹长度后恢复按真实局部切线计算。
这样可以避免同级骨骼方向突然折跳造成网格不平滑。
缩放不参与这段“轨迹不足”的补间,继续由拖尾宽度和形状参数控制。
9.4 假死方式
早期方案把尚未出现或死亡的拖尾骨骼缩放到 0。整组骨骼生命周期统一后,不再需要逐骨骼缩放假死。
当前规则:
拖尾存在:插槽 alpha = 实际透明度
拖尾不存在:插槽 alpha = 0
骨骼缩放始终保留,原因是缩放还负责:
- 拖尾宽度;
- 粒子宽度跟随;
- 拖尾形状曲线;
- 后续在 Spine 中继续编辑。
出生前使用首次有效骨骼姿态但插槽透明,死亡后保持最后有效骨骼姿态但插槽透明。Mesh 和骨骼对象不会在时间轴中删除和重建。
十、拖尾比例与随机尺寸
10.1 拖尾比例
每张拖尾资源卡片新增:
拖尾比例 (%)
有效范围为 0~100:
| 数值 | 行为 |
|---|---|
| 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.1~10。参数会进入:
- 配置保存;
- 配置加载;
- 预设;
- 撤回快照。
旧配置缺少字段时自动恢复默认值。
十三、使用说明
画布右上角增加“使用说明”按钮。点击后显示可关闭的新手说明弹窗,内容包括:
- 创建和选择场景对象;
- 粒子常用面板;
- 时间轴播放和逐帧查看;
- 图片、序列帧和拖尾资源;
- 配置保存、加载和预设;
- 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 导出体系与拖尾蒙皮定版”完成落盘。