用户提供的参考图是一张四帧并列的技能前摇效果:绿色能量从“发散的光叶碎片”逐步汇聚到“完整的旋转能量环 + 核心光球”。如果拆成独立组件或逐帧 sprite,会违反“基于 shader”和“代码逻辑清晰、简单”的约束。因此本次选择“单平面 + 程序化 shader”的方案。
CustomShaderMaterial 完成四帧演进,让 shader 内部用单一 progress 平滑驱动在 shader 内部只保留一个 uProgress:
progress = 0:光叶分布在外圈并向中心飘动,整体散射状progress ≈ 0.33:光叶开始沿螺旋轨迹汇聚,出现新月弧progress ≈ 0.66:螺旋收紧,出现亮边能量环雏形progress = 1.0:形成完整能量环 + 中心核心光球 + 边缘火花这样 4 帧 → 1 个连续函数,代码自然是连续的而不是硬切。
动画模式:
autoAnimate = true:组件内部用 elapsed * animationSpeed 循环推进 progress(循环时长由 animationSpeed 控制,用 mod(t, 1.0) 实现平滑 loop)autoAnimate = false:progress 由外部驱动,组件只做 clamp<TresMesh rotation={-PI/2, 0, 0}> // 贴在地面
<TresPlaneGeometry args=[size, size]>
<CustomShaderMaterial>
- panel.vert : 平面直通,输出 vUv
- panel.frag : 极坐标空间内叠加
1) 螺旋光叶层 (blade):基于 bladeCount、swirlIntensity 计算 N 条旋臂亮度
2) 能量环层 (ring) :基于 progress 控制环的清晰度和亮度
3) 核心光球层 (core):progress 接近 1 时亮起
4) 火花点缀 (sparkle):由 hash21 + 时间生成微亮点
5) 颜色分层 :baseColor ↔ glowColor ↔ highlightColor ↔ coreColor 按亮度插值
</TresMesh>
shader 文件组织:
src/shader/radiantSwirlSkillComponent/panel.vertsrc/shader/radiantSwirlSkillComponent/panel.frag按“从动起来到长什么样”分三组:
autoAnimate(Switch)animationSpeed(Slider)—— 自动循环的速度倍率progress(Slider,0–1)—— 外部驱动进度,仅在 autoAnimate=false 生效baseColor:阴影/背景能量色glowColor:旋臂发光色highlightColor:边缘高光色coreColor:最终核心能量球颜色radius:可视范围半径(mesh 尺寸等比计算)bladeCount:能量叶片条数swirlIntensity:螺旋弯曲强度noiseScale:叶片细节粒度coreIntensity:完成态核心光球强度sparkleIntensity:火花亮度opacity:整体透明度所有数值型参数在组件内部都用 clampNumber 保护,防止越界导致 shader 失真或黑屏。
多层 mesh 更灵活但会增加组件代码量和管理成本。用户明确要求“代码逻辑清晰、简单”。因此选择单 shader 内部分层叠加。
纯外部驱动对预览环境不友好(默认进预览看不到动),所以保留 autoAnimate 默认开启。
参考图更像屏幕/地面贴面的能量爆发。为了和现有“*Panel / *Ground”系列风格一致,默认 rotation.x = -Math.PI / 2 贴地放置,同时用户仍可在 object3D 调整旋转。
src/dcsConfig.ts 中 radiantSwirlSkillComponent 注册段src/components/radiantSwirlSkillComponent.vuesrc/shader/radiantSwirlSkillComponent/