1. 从静态到动态:为什么你的水墨效果“差点意思”
很多朋友在Unity里尝试过水墨风格Shader,照着网上教程写一个,贴图一挂,效果出来了——黑白灰,有点晕染的感觉,挺像那么回事。但玩一会儿,或者放到游戏里跑起来,总觉得哪里不对。画面是“水墨画”,但感觉是“打印出来的水墨画”,死板,没有灵气。问题就出在这里:缺少了“动态”和“随机”这两个水墨的灵魂。
真实的水墨在宣纸上,是流动的、扩散的、边缘会自然晕开,而且每一次落笔的痕迹都是独一无二的,有不可预测的“偶发美感”。我们之前写的很多基础Shader,就像是用钢笔勾了个水墨画的线稿,虽然形似,但神不似。动态扩散和边缘模糊优化,就是给这幅线稿注入灵魂的关键两步。前者让墨迹“活”起来,仿佛正在纸上洇开;后者则消除了生硬的数字边缘,让过渡变得柔和、自然。
想象一下这样的场景:你的游戏角色挥出一剑,剑痕不是一道简单的、边缘清晰的黑色贴图,而是像饱蘸浓墨的毛笔划过,墨色由实到虚,边缘有毛茸茸的、随机的水渍感,甚至墨迹在产生后还能微微地向周围“爬”一点点。或者,一片水墨风格的山峦背景,远山的轮廓不是僵硬的锯齿,而是带着一种朦胧的、空气透视般的模糊,深浅不一。这就是我们要进阶达到的目标。
这个进阶过程并不需要你成为图形学博士。核心思路就是引入两个好朋友:时间(_Time)和噪声(Noise)。用时间来驱动变化,用噪声来模拟自然的不规则。下面,我就带你一步步把这两个概念,塞进我们熟悉的Shader框架里,让静态水墨“动”起来。
2. 让墨迹“洇开”:动态扩散效果的实现秘籍
动态扩散,说白了就是让颜色的边界随着时间发生变化。在Shader里,我们不能真的去模拟流体物理,但我们可以用一些“视觉魔术”来骗过眼睛。最直接有效的方法,就是让决定水墨范围的阈值或噪声,随着时间变化而变化。
2.1 基础噪声的升级:加入时间变量
回顾一下原始文章里的那个简化Shader,它在片元着色器里生成噪声的代码是:
float2 noise = frac(sin(float2(i.uv.x * 123.45, i.uv.y * 654.32) * _Time.y) * 4321.23);
这行代码其实已经埋下了动态的种子:_Time.y。_Time是Unity内置的一个float4变量,它的y分量就是自游戏开始以来的总时间(以秒为单位)。用时间来乘以uv坐标,再经过sin和frac(取小数部分)函数,得到的噪声值就会每一帧都不同。但这只是噪声本身在闪烁变化,并不是我们想要的“扩散”感。
真正的扩散,是墨色的影响范围在变大。我们可以这样改造:将时间变量加到影响水墨强度计算的环节中。比如,原本我们用一个固定的_InkAmount(水墨量)来和噪声比较,决定哪里是墨色。现在,我们让这个“比较的基准”随着时间变化。
// 新增一个控制扩散速度的属性
_DiffuseSpeed (“Diffuse Speed”, Range(0, 2)) = 0.5
// 在片元着色器中计算动态阈值
float dynamicThreshold = _InkAmount * (0.8 + 0.2 * sin(_Time.y * _DiffuseSpeed));
float inkEffect = smoothstep(0, dynamicThreshold, noise.x + noise.y);
这样,_InkAmount就不再是一个死板的数值了。它会在一个基础值附近(我这里示例是80%到100%之间)周期性波动。当dynamicThreshold变小时,原本一些刚好低于阈值、不被显示为墨色的像素,就可能因为阈值降低而“变成”墨色,看起来就像是墨迹向外扩张了一点点;当阈值回升时,墨迹又略微收缩。一扩一缩,就形成了呼吸般的扩散动画。你可以调节_DiffuseSpeed来控制这个呼吸的快慢。


1288

被折叠的 条评论
为什么被折叠?



