阶段五完成
This commit is contained in:
+448
@@ -0,0 +1,448 @@
|
||||
# 网页粒子系统 · 阶段五
|
||||
|
||||
> 阶段定位:**粒子拖尾模块定版**
|
||||
> 完成日期:2026-08-28
|
||||
> 工程目录:`/Users/tianmokeji/Desktop/SpineParticle`
|
||||
> 技术栈:Vue 3 + TypeScript + Pinia + PixiJS 7 + Vite
|
||||
|
||||
---
|
||||
|
||||
## 一、阶段结论
|
||||
|
||||
阶段五完成了粒子拖尾模块的第一版完整实现。拖尾不再是独立于粒子的静态图片,而是由每个粒子自己的历史轨迹、拖尾骨骼链和网格蒙皮共同驱动,并与粒子的最终渲染位置保持连接。
|
||||
|
||||
本阶段主要完成:
|
||||
|
||||
1. 默认 `trail.png` 拖尾资源;
|
||||
2. 多拖尾图片资源和占比分配;
|
||||
3. 每张拖尾资源独立的骨骼、尺寸、旋转、颜色、透明度和曲线配置;
|
||||
4. 按网格行列自动生成蒙皮拓扑;
|
||||
5. 按拖尾骨骼数生成独立骨骼链;
|
||||
6. 使用相邻骨骼权重对图片网格进行 CPU 蒙皮;
|
||||
7. 拖尾跟随粒子最终渲染位置,包含移动噪声等视觉位移;
|
||||
8. 拖尾状态参与固定帧录制与回放;
|
||||
9. 画布蒙皮网格调试显示;
|
||||
10. 卡片全量重置和旧配置迁移。
|
||||
|
||||
拖尾模块默认关闭,不会改变未启用拖尾时的粒子表现。阶段三的外观资源和阶段四的修改器功能保持原有行为。
|
||||
|
||||
---
|
||||
|
||||
## 二、拖尾默认状态
|
||||
|
||||
### 2.1 模块默认状态
|
||||
|
||||
- “开启拖尾(Trail)”默认关闭;
|
||||
- 开启后默认创建一张拖尾资源卡片;
|
||||
- 默认图片为 `public/trails/trail.png`;
|
||||
- 默认名称为 `trail`;
|
||||
- 单资源时占比固定为 100%;
|
||||
- 画布“蒙皮网格”显示默认关闭。
|
||||
|
||||
### 2.2 每张拖尾资源的默认参数
|
||||
|
||||
| 参数 | 默认值 |
|
||||
|---|---:|
|
||||
| 图片 | `trail.png` |
|
||||
| 名称 | `trail` |
|
||||
| 占比 | 100%(单资源) |
|
||||
| 占比锁定 | 关闭 |
|
||||
| 旋转 | 0° |
|
||||
| 拖尾骨骼数 | 3 |
|
||||
| 初始长度 | 100 |
|
||||
| 初始宽度 | 100 |
|
||||
| 宽度缩放 | 跟随粒子 |
|
||||
| 生命周期长度曲线 | 关闭,默认水平线 1 |
|
||||
| 形状曲线 | 关闭,默认水平线 1 |
|
||||
| 颜色模式 | 跟随粒子 |
|
||||
| 混合模式 | 正常 |
|
||||
| 固定颜色 | `#ffffff` |
|
||||
| 透明度模式 | 跟随粒子 |
|
||||
| 固定透明度 | 1 |
|
||||
| 透明度曲线 | 默认水平线 1 |
|
||||
|
||||
### 2.3 网格默认参数
|
||||
|
||||
网格拓扑属于拖尾模块的公共结构参数:
|
||||
|
||||
| 参数 | 默认值 | 可调范围 |
|
||||
|---|---:|---:|
|
||||
| 网格行数 | 4 | 2~16 |
|
||||
| 网格列数 | 4 | 2~32 |
|
||||
|
||||
行数决定图片宽度方向的细分,列数决定图片从头部到尾部方向的细分。
|
||||
|
||||
---
|
||||
|
||||
## 三、多拖尾图片资源
|
||||
|
||||
### 3.1 资源卡片
|
||||
|
||||
拖尾图片复用了外观与资源模块的通用 `ImageResourceCard.vue`,因此两类图片资源保持统一的交互方式:
|
||||
|
||||
- 点击缩略图选择本地 PNG、JPEG 或 WebP;
|
||||
- 点击右上角 `+` 新增拖尾资源卡片;
|
||||
- 修改资源名称;
|
||||
- 查看当前图片文件名;
|
||||
- 调整资源占比;
|
||||
- 锁定或解除锁定当前占比;
|
||||
- 重置当前资源;
|
||||
- 删除当前资源,至少保留一张。
|
||||
|
||||
拖尾资源不显示“子文件夹”字段,其余通用卡片结构与粒子图片资源一致。
|
||||
|
||||
### 3.2 占比规则
|
||||
|
||||
- 单张拖尾资源时,占比固定为 100%,锁定按钮不可用;
|
||||
- 多张拖尾资源时,总占比始终保持 100%;
|
||||
- 锁定某张资源后,调整其他资源只会重新分配未锁定资源;
|
||||
- 新增、删除或重置资源后会重新平衡占比;
|
||||
- 每个粒子出生时,根据全局随机种子和资源占比选择一张拖尾图片;
|
||||
- 粒子出生后保持已选中的拖尾资源,不会在生命周期中跳换图片。
|
||||
|
||||
### 3.3 卡片重置
|
||||
|
||||
点击拖尾卡片的重置按钮会恢复该卡片的完整默认状态,不再只替换图片。重置内容包括:
|
||||
|
||||
- `trail.png`、名称 `trail`;
|
||||
- 占比和锁定状态;
|
||||
- 旋转、骨骼数、长度、宽度和宽度模式;
|
||||
- 生命周期长度曲线及其开关;
|
||||
- 形状曲线及其开关;
|
||||
- 颜色模式、固定色、颜色渐变和混合模式;
|
||||
- 透明度模式、固定透明度和透明度曲线。
|
||||
|
||||
多资源场景中,卡片恢复默认后仍会执行占比平衡,保证全部资源之和为 100%。
|
||||
|
||||
---
|
||||
|
||||
## 四、每张拖尾资源的独立控制
|
||||
|
||||
### 4.1 图片方向
|
||||
|
||||
拖尾图片约定:
|
||||
|
||||
- 图片左侧为拖尾头部;
|
||||
- 图片右侧为拖尾尾部;
|
||||
- 第 0 根拖尾骨骼位于粒子位置;
|
||||
- 后续骨骼沿粒子历史轨迹向后排列。
|
||||
|
||||
“旋转”用于修正所选图片的默认朝向。旋转通过图片中心的 UV 变换完成,不会改变粒子自身旋转。
|
||||
|
||||
### 4.2 骨骼与尺寸
|
||||
|
||||
每张拖尾资源独立设置:
|
||||
|
||||
- **拖尾骨骼数**:决定沿轨迹采样的骨骼节点数量,范围 2~16;
|
||||
- **初始长度**:决定从粒子头部向历史轨迹回溯的距离;
|
||||
- **初始宽度**:决定蒙皮网格横向展开宽度;
|
||||
- **宽度缩放**:可选择固定宽度或跟随粒子当前缩放。
|
||||
|
||||
“跟随粒子”模式使用粒子当前 X/Y 缩放绝对值的平均值作为宽度倍率。
|
||||
|
||||
### 4.3 生命周期长度曲线
|
||||
|
||||
开启后,曲线横轴为粒子归一化生命时间,纵轴为长度倍率:
|
||||
|
||||
```text
|
||||
当前拖尾长度 = 初始长度 × 生命周期长度曲线值
|
||||
```
|
||||
|
||||
曲线默认是值为 1 的水平线。关闭时始终使用初始长度。
|
||||
|
||||
### 4.4 形状曲线
|
||||
|
||||
形状曲线控制拖尾从首端到尾端的宽度变化:
|
||||
|
||||
```text
|
||||
当前列宽度 = 当前拖尾宽度 × 形状曲线值
|
||||
```
|
||||
|
||||
横轴表示从头部到尾部的位置,纵轴表示宽度倍率。默认曲线为值 1 的水平线,因此首尾等宽。
|
||||
|
||||
### 4.5 颜色与混合模式
|
||||
|
||||
每张拖尾资源支持三种颜色模式:
|
||||
|
||||
| 模式 | 行为 |
|
||||
|---|---|
|
||||
| 跟随粒子 | 使用当前粒子图片的实时颜色 |
|
||||
| 固定 | 使用拖尾资源自己的固定颜色 |
|
||||
| 曲线 | 按粒子生命周期使用多色渐变 |
|
||||
|
||||
固定色支持颜色选择器和十六进制文本输入。曲线模式复用生命周期多色渐变控件,可添加多个颜色标记。
|
||||
|
||||
每张资源还可独立选择四种混合模式:正常、相加、相乘、滤色。
|
||||
|
||||
### 4.6 透明度
|
||||
|
||||
每张拖尾资源支持三种透明度模式:
|
||||
|
||||
| 模式 | 行为 |
|
||||
|---|---|
|
||||
| 跟随粒子 | 使用粒子当前透明度 |
|
||||
| 固定 | 使用拖尾资源自己的固定透明度 |
|
||||
| 曲线 | 按粒子生命周期读取透明度曲线 |
|
||||
|
||||
透明度曲线默认是值为 1 的水平线。
|
||||
|
||||
---
|
||||
|
||||
## 五、拖尾骨骼与蒙皮实现
|
||||
|
||||
### 5.1 粒子历史轨迹
|
||||
|
||||
每个活动粒子维护自己的轨迹历史:
|
||||
|
||||
- 记录粒子每帧的最终渲染位置;
|
||||
- 相邻位置变化过小时更新首点,避免堆积大量重复点;
|
||||
- 按配置长度保留约 1.5 倍的历史距离;
|
||||
- 单粒子历史点设置上限,防止长时间运行无限增长;
|
||||
- 粒子死亡、拖尾关闭或重新绑定时清空对应历史。
|
||||
|
||||
记录的是粒子最终渲染位置,因此移动噪声造成的视觉位移也会进入拖尾轨迹,拖尾头部不会与画面中的粒子脱节。
|
||||
|
||||
### 5.2 独立骨骼链
|
||||
|
||||
每个粒子根据自己所选拖尾资源的骨骼数生成独立骨骼链:
|
||||
|
||||
1. 第 0 根骨骼固定在粒子最终渲染位置;
|
||||
2. 其余骨骼沿历史轨迹按距离等距采样;
|
||||
3. 每根骨骼根据前后采样点计算旋转方向;
|
||||
4. 不同粒子、不同拖尾资源可以使用不同骨骼数量。
|
||||
|
||||
### 5.3 网格拓扑
|
||||
|
||||
网格根据行列数自动生成:
|
||||
|
||||
- 每个交叉点生成一个顶点;
|
||||
- 相邻四个顶点组成两个三角形;
|
||||
- 列方向对应图片左侧头部到右侧尾部;
|
||||
- 行方向对应图片宽度;
|
||||
- UV 根据资源旋转参数绕中心重新计算。
|
||||
|
||||
### 5.4 蒙皮权重
|
||||
|
||||
每一列顶点绑定相邻两根拖尾骨骼:
|
||||
|
||||
- 根据列在拖尾长度中的归一化位置,计算前后骨骼索引;
|
||||
- 在两根骨骼之间使用线性权重插值;
|
||||
- 顶点中心沿骨骼链移动;
|
||||
- 顶点宽度方向使用轨迹切线的法线展开;
|
||||
- 形状曲线进一步调节每一列的宽度。
|
||||
|
||||
当前使用 CPU 更新 PixiJS `SimpleMesh` 顶点,蒙皮结果实时写回画布。
|
||||
|
||||
### 5.5 绘制层级
|
||||
|
||||
拖尾网格始终绘制在对应粒子图片下方,避免拖尾覆盖粒子头部。图片不可用、轨迹长度不足或最终透明度为 0 时,拖尾网格自动隐藏。
|
||||
|
||||
---
|
||||
|
||||
## 六、重新绑定规则
|
||||
|
||||
以下参数改变时会触发拖尾网格和蒙皮重新绑定:
|
||||
|
||||
1. 网格行数;
|
||||
2. 网格列数;
|
||||
3. 当前拖尾资源的骨骼数;
|
||||
4. 当前拖尾资源的旋转方向;
|
||||
5. 粒子切换到结构签名不同的拖尾资源。
|
||||
|
||||
重新绑定时:
|
||||
|
||||
- 保留当前正在使用的图片,不会错误恢复为 `trail.png`;
|
||||
- 重新生成顶点、索引、UV 和骨骼权重;
|
||||
- 清空旧轨迹和旧骨骼状态;
|
||||
- 从粒子当前最终位置重新开始采样;
|
||||
- 避免旧骨骼位置套用到新网格后产生偏移或拉伸。
|
||||
|
||||
只有用户主动点击卡片重置按钮时,图片和参数才会恢复为完整默认状态。
|
||||
|
||||
---
|
||||
|
||||
## 七、粒子跟随与修改器协作
|
||||
|
||||
此前出现的“拖尾像独立图片、没有跟随粒子”问题已经修正。当前拖尾更新顺序为:
|
||||
|
||||
1. 计算粒子的基础物理位置;
|
||||
2. 应用重力、风力、力场、吸附和阻尼;
|
||||
3. 计算移动噪声等最终视觉位移;
|
||||
4. 得到粒子最终渲染位置;
|
||||
5. 将该位置写入拖尾历史;
|
||||
6. 重新采样拖尾骨骼;
|
||||
7. 将首骨骼强制对齐粒子最终位置;
|
||||
8. 更新蒙皮顶点、颜色、透明度和混合模式。
|
||||
|
||||
因此拖尾与粒子画面位置使用同一坐标来源。粒子死亡时,对应拖尾历史、骨骼和网格会一起停止并清理。
|
||||
|
||||
---
|
||||
|
||||
## 八、固定帧录制与回放
|
||||
|
||||
粒子实时状态新增 `trailState`,记录:
|
||||
|
||||
- 当前拖尾资源 ID;
|
||||
- 拖尾骨骼位置和旋转;
|
||||
- 当前宽度;
|
||||
- 当前透明度;
|
||||
- 当前颜色。
|
||||
|
||||
固定帧录制会保存这些状态,回放时按资源 ID 恢复对应纹理和蒙皮参数,避免多拖尾资源在回放时全部退回第一张图片。
|
||||
|
||||
---
|
||||
|
||||
## 九、画布蒙皮网格调试
|
||||
|
||||
画布左上角新增“蒙皮网格”复选框:
|
||||
|
||||
- 默认关闭;
|
||||
- 开启后使用青色线条绘制正在显示的拖尾网格;
|
||||
- 显示网格的行列连接和所有顶点;
|
||||
- 多个粒子的网格可同时显示;
|
||||
- 只用于编辑器调试,不参与录制和导出;
|
||||
- 关闭拖尾或关闭开关时立即清空辅助线。
|
||||
|
||||
该功能用于检查图片方向、网格密度、骨骼变形和拖尾是否与粒子头部正确连接。
|
||||
|
||||
---
|
||||
|
||||
## 十、核心数据结构
|
||||
|
||||
### 10.1 `TrailImageResource`
|
||||
|
||||
每张拖尾图片已经成为完整的独立资源配置,主要包含:
|
||||
|
||||
- 资源 ID、纹理、名称和预览地址;
|
||||
- 占比和锁定状态;
|
||||
- 图片旋转;
|
||||
- 颜色模式、固定色、多色渐变和混合模式;
|
||||
- 透明度模式、固定透明度和曲线;
|
||||
- 骨骼数、初始长度、初始宽度和宽度模式;
|
||||
- 生命周期长度曲线;
|
||||
- 首端到尾端的形状曲线。
|
||||
|
||||
### 10.2 `TrailState`
|
||||
|
||||
`TrailState` 是实时预览与时间轴之间的拖尾状态载体,包含骨骼链、宽度、透明度、颜色和拖尾资源 ID。
|
||||
|
||||
### 10.3 兼容迁移
|
||||
|
||||
`ensureEmitterConfig()` 会:
|
||||
|
||||
- 把早期单拖尾字段迁移为 `trailResources`;
|
||||
- 为旧资源补齐旋转、混合模式、独立骨骼尺寸和曲线字段;
|
||||
- 把旧版非水平拖尾曲线迁移为当前默认水平曲线;
|
||||
- 把旧网格默认值迁移为 4 行、4 列;
|
||||
- 保证热更新和旧内存配置不会把 `undefined` 传入运行逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 十一、本阶段新增或重点调整的文件
|
||||
|
||||
| 文件 | 本阶段职责 |
|
||||
|---|---|
|
||||
| `public/trails/trail.png` | 默认拖尾图片资源 |
|
||||
| `src/views/ImageResourceCard.vue` | 粒子图片与拖尾图片共用的资源卡片 |
|
||||
| `src/views/ParticlePanel.vue` | 拖尾开关、多资源卡片、独立参数、曲线、占比和重置逻辑 |
|
||||
| `src/core/particleEmitter.ts` | 轨迹记录、骨骼采样、网格生成、CPU 蒙皮、资源选择、录制和回放状态 |
|
||||
| `src/views/Stage.vue` | 默认拖尾纹理注入、画布蒙皮网格显示及实时刷新 |
|
||||
|
||||
---
|
||||
|
||||
## 十二、验证结果
|
||||
|
||||
本阶段已完成以下检查:
|
||||
|
||||
- 默认拖尾资源能加载 `trail.png`;
|
||||
- 图片左侧为头部、右侧为尾部;
|
||||
- 拖尾首骨骼与粒子最终渲染位置保持一致;
|
||||
- 移动噪声开启时,拖尾沿粒子视觉轨迹移动;
|
||||
- 多张拖尾图片可新增、删除、选择和按占比分配;
|
||||
- 每张资源可独立设置骨骼、长度、宽度、旋转、颜色、混合模式和透明度;
|
||||
- 生命周期长度曲线和形状曲线已移动到各自资源卡片;
|
||||
- 修改行列数、骨骼数或旋转后会重新绑定,并保留当前图片;
|
||||
- 卡片重置会恢复图片和全部默认参数;
|
||||
- 网格默认值为 4 × 4;
|
||||
- 画布“蒙皮网格”开关默认关闭,可正常开启和关闭;
|
||||
- 本地页面交互过程中没有控制台错误;
|
||||
- `npm run build` 通过;
|
||||
- `git diff --check` 通过。
|
||||
|
||||
Vite 仍会提示主包体积超过 500 kB,该提示不影响当前功能运行。
|
||||
|
||||
---
|
||||
|
||||
## 十三、当前边界与已知风险
|
||||
|
||||
1. **拖尾不会在粒子死亡后继续残留**:粒子死亡时拖尾一起清理,尚未支持尾迹独立淡出。
|
||||
2. **蒙皮在 CPU 中逐帧更新**:高粒子数、高网格细分和多拖尾资源同时使用时需要性能压测。
|
||||
3. **历史轨迹按帧采样**:极端帧率波动下,弯曲细节可能出现密度差异;当前骨骼按距离重新采样可缓解但不能完全消除。
|
||||
4. **所有拖尾资源共用网格行列数**:骨骼数和外观参数可独立配置,但网格拓扑尚未移动到每张资源卡片。
|
||||
5. **资源仍依赖运行时纹理对象**:本地上传图片尚未进入正式工程保存、加载和资源打包流程。
|
||||
6. **旋转使用 UV 中心变换**:非矩形有效内容或带大面积透明边距的图片可能需要额外裁切、翻转或轴向选项。
|
||||
7. **时间轴保存的是运行状态**:尚未形成独立、版本化、可跨工程交换的拖尾动画格式。
|
||||
8. **缺少自动化测试**:当前以类型检查、生产构建和浏览器交互验证为主。
|
||||
|
||||
---
|
||||
|
||||
## 十四、下一步开发建议
|
||||
|
||||
### 优先级 P0:拖尾性能与稳定性
|
||||
|
||||
- 对 100、200、400 粒子分别测试 4 × 4、8 × 8、16 × 32 网格;
|
||||
- 记录 CPU 蒙皮耗时、顶点数量和内存占用;
|
||||
- 将不在视口内或透明度为 0 的拖尾提前跳过;
|
||||
- 缓存资源 ID 到配置对象的映射,减少每帧数组查找;
|
||||
- 评估把顶点变形迁移到 GPU Shader 的收益。
|
||||
|
||||
### 优先级 P1:拖尾生命周期收尾
|
||||
|
||||
- 增加粒子死亡后拖尾残留时间;
|
||||
- 支持尾迹独立淡出和收缩;
|
||||
- 明确吸附完成、碰撞死亡和自然死亡时的不同拖尾结束策略;
|
||||
- 增加拖尾采样间隔或最小距离参数;
|
||||
- 增加轨迹平滑和尖角处理。
|
||||
|
||||
### 优先级 P2:工程保存与资源打包
|
||||
|
||||
- 定义正式 `ProjectSchema` 和版本号;
|
||||
- 将 Pixi Texture 与可序列化拖尾配置分离;
|
||||
- 保存多拖尾资源、占比、锁定、颜色、曲线和网格参数;
|
||||
- 采用 Data URL、ZIP 工程包或资源目录保存自定义拖尾图片;
|
||||
- 为阶段三到阶段五建立明确的配置迁移测试。
|
||||
|
||||
### 优先级 P3:导出准备
|
||||
|
||||
- 明确拖尾骨骼链在 Spine 中的命名和层级;
|
||||
- 固化网格顶点、三角形、UV、权重和骨骼数据格式;
|
||||
- 将 `TrailState` 烘焙为骨骼关键帧或网格变形关键帧;
|
||||
- 验证多拖尾资源的槽位、附件和混合模式表达;
|
||||
- 评估不同 Spine 版本对加权网格和变形时间轴的兼容性。
|
||||
|
||||
### 优先级 P4:后续模块
|
||||
|
||||
- 实现碰撞体和粒子碰撞响应;
|
||||
- 实现轨道路径与路径跟随;
|
||||
- 为修改器辅助图形增加统一显示入口;
|
||||
- 增加撤销/重做、预设和参数复制粘贴。
|
||||
|
||||
---
|
||||
|
||||
## 十五、阶段五验收标准
|
||||
|
||||
阶段五可视为完成,当以下条件持续满足:
|
||||
|
||||
- 拖尾默认关闭,开启后默认使用 `trail.png`;
|
||||
- 每个粒子拥有独立的轨迹、骨骼链和蒙皮网格;
|
||||
- 拖尾图片左侧连接粒子,右侧沿历史轨迹延伸;
|
||||
- 多拖尾资源按占比确定性选择,并支持占比锁定;
|
||||
- 每张拖尾资源可独立调整旋转、骨骼、尺寸、曲线、颜色、混合模式和透明度;
|
||||
- 网格按行列自动生成,并由相邻骨骼权重驱动;
|
||||
- 拖尾与粒子最终渲染位置保持连接;
|
||||
- 修改结构参数后保留当前图片并重新绑定,不产生旧蒙皮偏移;
|
||||
- 卡片重置可恢复完整默认状态;
|
||||
- 画布可选择显示实际蒙皮网格,且默认关闭;
|
||||
- 拖尾状态能够参与时间轴录制和回放;
|
||||
- 阶段三外观资源和阶段四修改器功能没有发生回归;
|
||||
- TypeScript 类型检查和生产构建保持通过。
|
||||
Reference in New Issue
Block a user