关于 threejs-dynamic-surface-effects
threejs-dynamic-surface-effects 是管理屏幕空间外观历史及合成的 Three.js 技能,面向需要持久化表面效果的开发者。它以状态转换、时间一致的事件更新和 ping-pong GPU 资源为核心,并将物理状态与屏幕效果分开管理。
主要功能
- 01定义历史通道、时钟与资源所有权
- 02按状态转换选择全场或稀疏更新
- 03按时间积分衰减与指针事件
- 04使用 ping-pong StorageTexture 更新历史
- 05合成模糊、结构与折射并管理生命周期
适用场景
- 01制作随指针移动累积的霜痕或触摸效果
- 02实现按时间演化的屏幕空间表面历史
- 03验证稀疏更新、重置和 GPU 资源释放
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ linegel/ threejs-complete-set-of-skill --skill threejs-dynamic-surface-effects安装后在 Claude Code 中输入/threejs-dynamic-surface-effects确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEagents/openai.yamlreferences/ping-pong-accumulation.md详细介绍
状态转换型动态表面效果
自行负责视口锁定的外观历史及其合成。将世界/物体残留效果交由
$threejs-particles-trails-and-effects,将天气累积交由
$threejs-rain-snow-and-wet-surfaces,将边界有限的水体交由
$threejs-water-optics,并将共享的全帧输出决策交由
$threejs-image-pipeline。
当外观受温度、相态、加载、湿度、接触或天气驱动时,请在第 1 步之前完成此处的本地交接:
- 指明物理量及单位、生产者坐标系/原点、变换和原点代次,以及向屏幕 UV 的投影;
- 指明源数据时间区间、采样频率、采样相位、不可变的生产者/版本,以及渲染器使用方;
- 声明作用范围/滤波、有效性、过时数据、误差及信号缺失策略;
- 绑定 GPU 资源代次、生产和使用该资源的渲染通道,以及完成依赖;
- 将物理源保持为只读,并为屏幕历史设置独立的外观版本;时钟、原点、变换、投影或资源代次发生不兼容变化时,重置屏幕历史。
当需要反馈或额外的系统所有者时,调用 $threejs-choose-skills。物理所有者保留决策权;屏幕 UV 历史仍归渲染器所有,属于外观状态。
然后阅读外部外观信号,了解本地投影和重置规则。
流程
1. 定义状态转换和所有权
为以下各项编写一份契约:
- 每个历史通道及其无量纲含义;
- 屏幕空间事件的形状、时间戳、压力/强度和 UV 原点;
- 衰减、沉积、扩散或无变化等演化项;
- 状态时钟、暂停/跳转策略和重置依赖;
- 唯一的历史写入方、合成使用方和最终输出所有者;
- 任何外部物理信号,以及与其分离的装饰性叠加层。
对于触摸/霜冻历史,一种实用的划分是:在 R 中记录可见覆盖率,在 A 中记录更平滑的倾斜/折射响应;G/B 保持未使用或明确用作诊断。每个通道都有且仅有一个方程、写入方、单位域、时钟和使用方时,此步骤即告完成。
2. 选择更新拓扑
根据状态转换而非视觉主题进行选择:
| 转换 | 更新拓扑 |
|---|---|
| 衰减、扩散或强迫项会改变大多数纹素 | 全场乒乓计算 |
| 沉积稀疏,且未触及的纹素保持不变 | 事件边界或脏瓦片 |
| 状态稀疏且会衰减 | 带时间戳的瓦片,并在每次可见/滤波采样时进行解析追赶,或物化所有可见瓦片 |
| 许多事件相互重叠 | 将事件分桶到瓦片;限制/压实列表,或栅格化单个聚合沉积场 |
| 状态和输入均未变化 | 空闲:保留历史且不进行任何调度 |
扩散使用全场或带 Halo 扩展的活动区域。阅读更新拓扑,了解重叠成本和扩散稳定性。未触及的纹素严格按照所选模型演化,且空闲帧不调度状态处理工作时,此步骤即告完成。
3. 确保时间与事件集成不变
从同一时钟上的两个有序采样值推导 dt。将相等的采样值视为经过时间为零。缺少前一个采样值、时间倒退、跳转、映射无效或发生不连续时,应遵循已声明的冻结、重置、解析追赶或有界子步策略。
使用历史纹理的宽高比,将带时间戳的指针移动栅格化为扫掠胶囊体。将衰减与饱和沉积一并积分,使按住指针和扫掠手势的结果不受渲染帧数影响。仅当事件区间内的压力或覆盖率变化超过已声明的误差阈值时,才细分该区间。
实现衰减、沉积或扩散前,请先阅读与 dt 正确配合的历史记录。当相同的定时输入在 30、60 和 120 Hz 下产生等效历史记录,且应用挂起时不会悄然丢弃已流逝时间的演化过程,即表示此步骤完成。
4. 分配乒乓图
使用来自 three/webgpu 的 WebGPURenderer,调用 await renderer.init(),并在此规范路径中要求 renderer.backend.isWebGPUBackend === true。将明确说明 WebGPU 不可用时的教学内容路由至 $threejs-compatibility-fallbacks。分配两个由渲染器拥有的 StorageTexture 历史纹理,采用通过重建和量化测试的最低实测尺寸与格式。将历史记录、场景颜色、模糊中间结果和静态结构场分开作为不同资源。
按以下顺序构建图:
immutable external appearance signals + timestamped UI events
-> write next history from previous history
-> publish/swap the completed history generation
single scene pass
-> optional separable blur at its owned reduced extent
-> static structure + current history composite
-> optional history-gated normal refraction
-> one RenderPipeline output transform
使用 Fn().compute(...)、storageTexture() 和 textureStore() 更新历史记录。使用 renderer.compute(...) 入队;r185 的 computeAsync() 不是 GPU 完成栅栏。稳态路径中不要进行回读。输出节点、诊断路由、资源尺寸/格式或质量分支发生变化时,应标记或重建渲染图。
分配或交换纹理前,请先阅读资源与 r185 执行。当每个通道都读取已提交的代次、没有通道采样其正在写入的纹理,且场景只渲染一次时,即表示此步骤完成。
5. 合成模糊、结构与折射
在启动时,或在尺寸或质量发生变化时,生成一次静态晶体/噪声场。将其作为数据并使用 NoColorSpace。在由通道管理的缩小分辨率下执行可分离模糊;当 alpha 通道参与运算时,采用 alpha 感知归一化。将合成与折射构建为馈入 RenderPipeline.outputNode 的 TSL 节点。
在单次输出转换前,始终以线性/HDR 格式保留场景与工作缓冲区。将屏幕周期 uniform 作为周期使用;根据实际资源推导纹素尺寸。仅在结构覆盖率和当前历史记录满足条件时启用折射,明确规定法线环绕与源边缘行为,并在线性光照下应用菲涅耳效应。
任一分支启用时,请阅读合成与折射。当模糊尺寸、纹理域、UV 约定、折射边界和输出转换都分别有明确归属并可在诊断中查看时,即表示此步骤完成。
6. 完成生命周期管理
选择一种调整大小策略:清除两份历史记录、重新映射,或根据深度/相机进行重投影。时钟、原点、变换、投影、资源代次、表示方式或质量不兼容时,重置或重新投影。普通的连续源版本递增应通过采样处理,而不是重置。
空闲时,保留持久状态并停止更新工作。恢复时,在接受新输入前应用已声明的时间策略。释放资源或设备丢失时,使历史代次失效,并释放两份历史记录、模糊/静态资源、计算/管线节点以及输入/调整大小监听器;下次绘制前创建新代次。
请阅读调整大小、重置与释放。当调整大小、跳转、质量变化、空闲/恢复、释放和设备丢失都具有明确的状态转换与资源处理结果时,即表示此步骤完成。
7. 验证状态与呈现
显示上一帧历史、沉积量、下一帧历史、脏瓦片/活跃纹素、场景颜色、模糊轴、静态场、历史前/后的遮罩、折射偏移、无折射结果以及最终结果。添加暂停和单步控制。
测量事件数、瓦片列表占用率、调度的纹素数、历史和中间数据的字节数、流量下限、调度/绘制耗时以及整帧 p50/p95。先通过停止空闲工作、选择有效的稀疏路径来扩展规模,再通过状态等价测试后减少历史/模糊范围或降低精度。
阅读资源核算和诊断与故障特征。 完成此技能的标准是:定时输入在 30/60/120 Hz 下结果一致;全量、稀疏和空闲状态转换均按所选模式运行;乒乓代次绝不别名;调整大小/重置/释放控制均通过;物理输入保持只读;帧循环不执行任何历史数据回读;场景仅渲染一次;输出转换只有一个所有者;完整场景满足指定的内存、流量和耗时预算。