【附仓库代码和详细实现】为 SPlayer 添加一个新的伪流体效果 #1072
viceasha2008
started this conversation in
想法 Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Fork 仓库地址: https://github.com/viceasha2008/refined-now-playing-netease-rebound/tree/master
预览视频:
preview.mp4
前言
尊敬的 SPlayer 开发团队,非常感谢你们写出了这样一个具有精美 UI/UX 的客户端!我恳请你们能否将我的伪流体实现添加到 SPlayer 的播放背景中。下面是详细信息:
我在使用旧版本的网易云音乐的时候,曾经感觉到 BetterNCM 项目中的 RefinedNowPlaying 插件的流体实现(FluidBackground)非常消耗 GPU 资源。
从原本的插件结构分析来看,FluidBackground 的卡顿原因可能如下:
<canvas>元素,各自渲染专辑封面的一个象限(CSSanimation让它们各自旋转,60 s 一圈)scale(1.2)<feTurbulence> + <feDisplacementMap>叠加在整个旋转容器上(通过filter: url(#fluid-filter))——这是最大的性能瓶颈,GPU 需要对大面积元素每帧重算湍流置换backdrop-filter: blur(64px)叠在整个背景的::after伪元素上requestAnimationFrame循环每帧修改feDisplacementMap的scale属性来做音频响应FluidBackground 美丽至极!但我的电脑 GPU 是 RTX 4060 Laptop,从任务管理器里面看,GPU 的占用可以达到 30%甚至更高,这导致在播放页面时要想欣赏美丽的流体效果,就不得不忍受电脑的高温和风扇的噪声。
我的想法
在巨大的 GPU 占用之下,我开始思考是否有更好的解决路径。我没有编程基础,也没有系统地学习过编程,最多只算是一个使用 Agent 进行 Vibe Coding 的爱好者。因此,起初我觉得我的想法很疯狂,但我仍然决定尝试。
一开始,我为我的毕设项目网站写了一个动态背景,它从歌曲封面取若干颜色,然后绘制若干多边形进行随机扭曲变形的背景。多边形没有覆盖到的部分则用一个歌曲封面的主色调填充。这个实现方式在巨大的高斯模糊下看起来好像还不错,但我总觉得离 RefinedNowPlaying 的流体效果相差甚远。
后来,我在水群的时候看到有群友在做关于等高线绘制的项目,我忽然有了一个想法。我的毕设项目网站里面有一个 three.js 写的流体,它的灵感来自于 Google Antigravity 的官网。当时我已经了解到 three.js 是一个三维渲染组件库。既然如此,为什么我不用一个 3D 等高线来模拟流体呢?这个想法一出来,我就紧锣密鼓地投入了 Vibe Coding 中()一开始,它只是一个 HTML 文件。也就是下文的 「参考原型」 。后来经过多次的调试,我终于使用 DeepSeek V4 Pro 和 Claude Opus 4.6,在 Copilot Agent 中将它融合进了 RefinedNowPlaying 插件内!
这个伪流体的实际资源占用要比 FluidBackground 下降 50%以上。我附上了一段视频以演示这个效果,下面是该伪流体涉及到的文件:
核心实现文件(2 个)
PseudoFluidCover类、默认参数PSEUDO_FLUID_DEFAULTS、颜色提取算法、Three.js WebGL 渲染背景系统(2 个)
PseudoFluidBackground子组件在此创建 & 管理PseudoFluidCover实例.rnp-background-pseudo-fluid设置/配置入口(2 个)
fluid-cover导入PSEUDO_FLUID_DEFAULTS;绑定滑块→rnp-pseudo-fluid-config事件;控制参数面板显隐样式联动(2 个)
body:not(.rnp-bg-pseudo-fluid) .rnp-pseudo-fluid-only控制非伪流体模式下隐藏相关选项参考原型(1 个)
数据流总结:设置面板滑块 → main.js 派发
rnp-pseudo-fluid-config自定义事件 → background.js 接收并更新 state →PseudoFluidCover.updateConfig()同步到 shader uniform。详细的说明文档
下面是关于该伪流体实现的文档。
一、概述
伪流体背景(PseudoFluidCover)是 RNP 插件的一种背景渲染模式。它从专辑封面提取色彩,通过 WebGL(Three.js)在 GPU 上实时生成类似等高线地形图的流动色彩效果。
核心思路:封面 → 色彩提取 → 1 D 色板纹理 → Simplex 噪声 + FBM + 域扭曲 → 地形高度 → 色板采样 → 流体画面。
二、架构与数据流
当切歌时,
updateImage()→_updateColorPalette()只更新色板纹理数据,不重建整个渲染管线。三、色彩提取算法详解
3.1 缩略图采样
将封面图片绘制到 128×128 的离屏 canvas 上,读取 RGBA 像素数据。忽略 alpha < 128 的半透明像素。
3.2 HSL 三维直方图分箱
将每个像素的 RGB 转为 HSL,按 21×11×11 的粒度分箱:
共
21×11×11 = 2541个箱子。每个箱子累加像素计数和 RGB 分量和。3.3 聚类筛选
筛掉像素占比低于
MIN_COLOR_RATIO_THRESHOLD的箱子。对每个有效箱子计算平均 RGB 和平均 HSL,形成一个颜色聚类。按计数值降序排列。3.4 颜色选取策略(平原 + 山丘)
选取分两阶段,总数 =
PLAIN_CONTOUR_COUNT+HILL_CONTOUR_COUNT:3.5 优先级排序
每个颜色计算优先级分数:
saturation × (1 - |lightness - 0.4| × 2),偏好中高明度、高饱和的颜色3.6 色板展开(Interleaving)
将排序后的颜色按占比映射到 2048 个槽位。采用中心交替展开策略:第 0 个颜色向右展开,第 1 个向左展开,交错进行。这样做的好处是相邻颜色在色板上不会突变,shader 中相邻高度值映射到相近颜色。
3.7 色彩增强
展开后对每个颜色应用:
DARK_COLOR_LIGHTNESS_THRESHOLD的颜色,明度 +DARK_COLOR_LIGHTNESS_BOOST,饱和度 +DARK_COLOR_SATURATION_BOOSTGLOBAL_SATURATION(1.65 默认,即增强 65%)GLOBAL_LIGHTNESS(0.95 默认,即略微压暗)四、Shader 渲染管线
4.1 噪声函数
使用经典 3D Simplex 噪声(Ashima Arts 实现),通过 FBM(Fractal Brownian Motion)叠加多层噪声:
FBM_OCTAVES控制叠加层数(1-6),每层频率翻倍、振幅减半。4.2 域扭曲(Domain Warping)
两阶段域扭曲,产生有机的流体感:
DOMAIN_WARPING越大,扭曲越强,形状越碎TURBULENCE_SPEED控制第一层扭曲的变化速度4.3 高度映射
ALL_COLORS_PRESENCE_FACTOR:高度循环倍数。值越大,同一画面区域出现的颜色种类越多(色板被「压缩」更多次)4.4 地形重塑
TERRAIN_UNIFORMITY:幂指数。>1 时中间值被压向两端(高原/深谷更分明),<1 时趋向均匀CONTOUR_SMOOTHNESS:混合原始曲线和平滑版本的权重,越高过渡越柔和4.5 抗锯齿(fwidth)
FWIDTH_AA控制是否启用。通过屏幕空间梯度多采样混合,消除等高线边缘的色彩跳变。4.6 运动拖影(Motion Trail)
每帧先绘制一个半透明黑色覆盖层衰减旧画面,再叠加新流体帧:
MOTION_TRAIL = 0:无拖影,直接覆盖MOTION_TRAIL → 1:衰减层透明度 0.5→0.01,流体层 alpha 1.0→0.15,产生越来越强的帧残留效果五、参数完整参考
色彩选取参数
PLAIN_CONTOUR_COUNTHILL_CONTOUR_COUNTMIN_COLOR_RATIO_THRESHOLDCOLOR_MID_DISTRIBUTION_STRICTNESS色彩增强参数
DARK_COLOR_LIGHTNESS_THRESHOLDDARK_COLOR_LIGHTNESS_BOOSTDARK_COLOR_SATURATION_BOOSTGLOBAL_SATURATIONGLOBAL_LIGHTNESS地形参数
PLAIN_AREA_RATIOTERRAIN_UNIFORMITYCONTOUR_SMOOTHNESSALL_COLORS_PRESENCE_FACTOR噪声与动画参数
NOISE_SCALETURBULENCE_SPEEDDOMAIN_WARPINGTERRAIN_DEFORMATION_SPEEDTERRAIN_TRANSLATION_SPEEDTERRAIN_TRANSLATION_DIR_XTERRAIN_TRANSLATION_DIR_Y渲染质量参数
FPSRENDER_SCALEGAUSSIAN_BLURMOTION_TRAILFWIDTH_AAFBM_OCTAVES六、性能考量
目前已知的缺点为,该伪流体在 C++ & CEF 编写的旧版本网易云上会比较频繁地触发内存的 GC,每次 GC 的时候 JS 主线程会短暂卡死,导致流体卡住十几毫秒。我尝试多次修复发现可能受限于老版本网易云的架构,这一问题无法修复,因为引入了较大的 three.js 库。但我想 SPlayer 采用了更新的 Electron 架构,也许这个问题就不会存在了。
结语
最后,我再次衷心感谢 SPlayer 的开发者。由于该文件为自用,且本人能力有限、信心不足,恐怕难以长期维护,因此本人目前并未将插件提交 BetterNCM 审核。若开发者对此感兴趣,能够将其融入 SPlayer 的播放页面背景中,我将不胜感激!
Beta Was this translation helpful? Give feedback.
All reactions