开发Chrome扩展时,我想让3D骰子拥有Chessex那种复古大理石质感——那种桌游玩家都想要的、带着流动纹理的石材效果。但渲染器允许用户为每种骰子自定义颜色(d4用红色、d6用蓝色、d20用金色等),所以纹理不能是固定的位图。大理石纹路要保留,但底色必须跟着用户选择走。
这篇是完整的技术方案:用simplex噪声从零生成纹理,不需要Photoshop,不需要大理石照片,纯代码输出类似这样的效果。
![]()
整个流程是三层噪声叠加,加上一个关于alpha通道的技巧。逐层拆解。
第一层:多倍频simplex噪声
单一样本的simplex噪声只能给出平滑的有机色块,更像云层而非岩石。真实大理石有跨尺度的细节——既有大块的色带,也有细如发丝的纹理。解决方法是叠加多个倍频的噪声,频率翻倍,振幅减半:
代码里freqX和freqY有轻微不对称(0.7 vs 1.3),这让纹理带有一点水平流向,类似切割石材的纹理走向。输出已经是灰度有机图案,但太均匀了——近似平行的条带像木纹,而非大理石那种卷曲回旋的纹理。真实的大理石纹理会弯曲、漩涡、自我缠绕。这是下一层要解决的问题。
第二层:域扭曲(Domain Warping)
这个技巧简单到像作弊,但效果极其显著。不在直白的(x, y)网格上采样噪声,而是先用另一组噪声场偏移每个坐标点,再采样:
两个独立的低频噪声场(每轴一个)把每个像素推向随机方向,最大偏移90像素。同样的噪声算法,同样的参数,只是输入坐标被"掰弯"了,平行条带就变成了漩涡状。现在有了大理石的回旋感,但画面还是偏软——对比度不足,色带边缘模糊。需要第三层来"雕刻"细节。
第三层:对比度塑形
真实大理石不是渐变色块,而是矿物颗粒的突然切换。把第二层输出的柔和灰度值用幂函数重新映射,可以强化这种硬边感:
pow函数把中间灰度压向两端,制造更锐利的过渡。指数越大,纹理越"碎"——像碎裂的冰面或密集的蛛网。指数越小,过渡越柔和,更像沉积岩层。这个参数直接控制大理石的"破碎感"。
Alpha通道的关键技巧
这里卡了很久。渲染器用纹理的alpha通道做两件事:一是控制透明度(显然),二是作为"光泽度贴图"——alpha高的区域更反光,模拟抛光石材表面的高光变化。
但问题来了:大理石纹理本身有深浅,深色区域在物理上应该更吸光、更少反光。如果直接把噪声值塞进alpha,深色处alpha低,反而变成"更透明"而非"更哑光"。
修正方案:alpha通道不直接用噪声值,而是用"距离边缘的远近"。具体做法是对比度塑形后的值做边缘检测,离突变边界越近的地方alpha越高(模拟抛光时镜面反射集中的棱线),平坦区域alpha压低。这样深色矿物和浅色基质可以有各自的光泽表现,而不会互相穿透。
着色:把灰度变成任意底色的大理石
现在有了单通道的纹理mask(0到1的浮点值)。用户选的颜色作为底色,mask值决定混合比例——靠近0用底色,靠近1用纹理色(通常是白色或米色的"矿脉")。
关键设计:矿脉颜色不是固定白色,而是基于用户底色自动计算的——取底色的亮度,往高明度偏移,但保持相近的色相和饱和度。这样红色骰子有粉色纹理,蓝色骰子有浅蓝纹理,始终协调。
最终输出是512×512的PNG,实时生成,内存占用不到1MB,在Chrome扩展里跑毫无压力。每次用户换颜色,200毫秒内重新生成全套纹理。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.