做半透明材质的人大概都踩过同一个坑:想要一块"毛玻璃",结果做出来要么像一张贴了图的塑料片,要么背景糊成一团看不出材质质感。真正让磨砂玻璃立住的,是虚幻引擎里法线对折射通道的扰动——法线决定光往哪偏,折射决定背景怎么错位,两者配合才有"厚玻璃+粗糙表面"的观感。这篇内容围绕"虚幻带法线效果的毛玻璃"这个主题展开,把材质骨架、IOR 标定、法线强度控制、半透明排序、移动端限制和性能降级这一整套东西拆开讲清楚。适合已经能独立连材质节点、但对折射参数心里没底的中级使用者,也适合刚接触半透明材质、想知道"为什么我做法线扰动没反应"的新手。下面所有步骤和参数都按可复现的方式写,能直接照着搭。
1. 先把"毛玻璃"拆开看:它到底在模拟什么
1.1 磨砂介质的两种光学行为
一块磨砂玻璃放在那里,你看到的效果其实是两件事叠在一起。第一件是透射偏移:玻璃有折射率,背景透过它过来的时候位置会错开一点,玻璃越厚、折射率越高,错得越明显。第二件是散射模糊:磨砂面是微观上无数不规则的小坑,每个小坑把入射光往不同方向掰一下,整体就成了一片柔和的光斑,背景的锐利边缘被抹掉了。
这两件事在物理上是同一个表面粗糙度在不同尺度上的表现,但在实时渲染里必须分开处理,因为成本结构完全不同。透射偏移只要采样一次屏幕颜色、按法线偏一下 UV 就行,几乎不要钱;散射模糊要做多次采样平均,天生物理开销大。理解这个拆分很重要,因为它直接决定了你在虚幻引擎里搭材质时,哪些部分能用引擎自带通道白嫖,哪些部分得自己动手写。
我见过不少人一上来就找"模糊"节点,找不到就以为引擎做不了毛玻璃,其实方向从一开始就偏了。引擎给你的是偏移通道,模糊得你自己补。
1.2 为什么"带法线"是分水岭
不带法线的毛玻璃材质,本质就是一张固定强度的半透明贴图加一个恒定的折射值。它的毛病是整块玻璃的折射方向完全一致,背景像被整体平移了一段距离,边缘硬、内部平,动起来尤其假——摄像机一移,整块背景跟着平移,一点起伏都没有。
加上法线之后,每个像素的折射方向都不一样了。法线朝左的像素背景往左错,朝右的往右错,微观起伏被打散成细碎的错位,肉眼看起来就是"糊"。这个"糊"不是真模糊,是高频的小幅错位欺骗了视觉系统。这也是为什么法线贴图的分辨率和重复次数对最终观感影响极大:低频法线只会让背景整体扭曲,看起来像水波;高频法线才像磨砂。
顺带说一句,法线扰动只能解决"视觉上的毛",解决不了"背景内容被平均掉"。如果镜头贴得很近、背景有高对比度的细节(比如一排栏杆、一串文字),单靠法线还是会露馅,因为栏杆的硬边缘还是硬的,只是位置歪了一点。这种场景就得往上叠真模糊,后面第 3.4 节会给做法。
1.3 三条技术路线的取舍
实际项目里做毛玻璃,我一般会先问一句:这块玻璃要不要跟场景光照互动?答案不同,路线就完全不同。
| 路线 | 实现方式 | 观感 | 成本 | 适用场景 |
|---|---|---|---|---|
| 纯半透明贴图 | Translucent + 一张磨砂图,不接折射 | 平、假,但极便宜 | 极低 | 远景装饰、手机低配档 |
| 法线扰动折射 | Translucent + Refraction + Normal | 有起伏、有厚感 | 中 | 室内隔断、近景主视觉 |
| 折射加真模糊 | 上一档再叠屏幕采样模糊 | 最接近实拍 | 高 | 特写镜头、过场动画 |
第一档在移动端低配档位里依然有它的位置,尤其是那种远在天花板上的磨砂灯罩、背景里一闪而过的隔断。第二档是我默认推荐的方案,性价比最高。第三档只在少数镜头用,因为它的成本跟采样次数线性相关,一旦画面上同时出现七八块大面积毛玻璃,帧数会掉得很明显。
注意:第三条路线不要一上来就全场景铺开。我的习惯是先按第二档做完全流程,等到美术觉得"还是不够柔"再局部升级,避免一开始就把性能预算吃光。
2. 材质骨架:把折射通道先跑通
2.1 混合模式与着色模型的前置开关
新建材质,第一件事是把Blend Mode 改成 Translucent,这一步不做,Refraction 引脚根本不会生效。改完之后你会看到材质属性面板里多出一批半透明专属选项,其中最关键的是Translucency Lighting Mode,它有 Volumetric、Surface TranslucencyVolume、Surface ForwardShading 三个值。
我个人的默认选择是Surface TranslucencyVolume,它在"能吃到点光源和高光"与"成本可接受"之间比较平衡。如果你需要玻璃表面出现清晰的镜面高光、甚至需要法线细节在光照下也看得出来,那就上 Surface ForwardShading,代价是它走的是前向着色路径,光源多的场景里开销会明显上涨。Volumetric 我基本不用在玻璃上,它更适合烟雾、粉尘那种体积感的东西。
另外两个容易漏的开关:Two Sided要勾上,不然从背面看玻璃会直接消失;Tangent Space Normal保持默认勾选,除非你的法线贴图是三平面映射或者用世界空间生成的,那种情况才需要关掉。
移动端项目还得额外确认一件事:材质的Shading Model建议用 Default Lit,别为了省一点开销换成 Unlit。毛玻璃一旦 Unlit,法线扰动带来的明暗层次全没了,只剩下背景错位,观感会掉一个档次。
2.2 折射模式:IOR 与像素法线偏移
Refraction 引脚旁边有个属性叫Refraction Mode,两个选项:Index of Refraction 和 Pixel Normal Offset。这两个的区别值得单独说清楚,因为绝大多数"法线接了没反应"的问题都出在这里。
Index of Refraction模式下,折射的偏移量由你填进 Refraction 引脚的 IOR 值决定,法线只负责决定偏移的方向。也就是说,你把 IOR 填成 1.0,无论法线怎么折腾,背景都不会动;填成 1.5,法线一扭,背景就跟着扭。这个模式下法线影响的是方向而不是强度,强度由 IOR 统一控制,做磨砂玻璃时手感更可控。
Pixel Normal Offset模式下,偏移量由像素法线与相机视线的夹角直接决定,Refraction 引脚的数值不再起作用。法线偏折越厉害,背景错位越大。这个模式的好处是厚度感更自然,因为玻璃边缘的曲率大、法线偏折多,折射自动就强,符合真实玻璃的观察经验;坏处是它不太好做全局统一控制,你想整体加强或减弱效果时没有单一的旋钮。
我的做法是:主体用 Index of Refraction,因为项目里经常要按不同玻璃厚度调不同 IOR,统一旋钮很省事;只有在做那种带明显倒角、边缘厚中间薄的异形玻璃时才切到 Pixel Normal Offset。
2.3 IOR 数值的估算与实测标定
IOR 不是随便填的数字,它对应真实材料的折射率。空気是 1.0,水是 1.33,普通玻璃大约 1.5 到 1.52,亚克力 1.49,钻石 2.42。填之前先想清楚这块玻璃在物理上是什么材质。
但直接照搬物理值往往会翻车,原因是屏幕空间折射的偏移量还跟相机距离、屏幕分辨率、玻璃在屏幕上的实际尺寸有关。同样填 1.5,镜头贴着玻璃看偏移巨大,退后三米看几乎看不出来。所以物理值只能当起点,实际还得现场标定。
我给一个自己常用的标定流程,五分钟能搞定:
- 先把 Refraction 接一个常量 1.0,确认画面没变化,说明通道通了。
- 把值提到 1.05,慢慢往 1.2 推,观察背景边缘开始出现错位。
- 停在"错位明显但还能认出背景轮廓"的位置,这个位置通常就是这块玻璃的合适值。
- 记录下这个值,同时记录当时的相机距离,方便别的镜头复用时按比例换算。
实测下来,室内隔断类的中距离镜头(3 到 8 米),IOR 落在 1.08 到 1.18 之间的居多;近景特写(1 米以内)取 1.03 到 1.06 就够了,取大了背景会碎得离谱。下面这张对照表是我自己攒的经验值,直接抄:
| 玻璃类型 | 推荐 IOR | 配套法线强度 | 观感描述 |
|---|---|---|---|
| 极轻微磨砂(半透光隔断) | 1.03 - 1.05 | 0.05 - 0.10 | 背景轻微错位,轮廓基本清晰 |
| 常规磨砂玻璃 | 1.08 - 1.15 | 0.12 - 0.20 | 背景明显打散,能看出起伏 |
| 厚磨砂玻璃砖 | 1.18 - 1.25 | 0.20 - 0.30 | 背景严重扭曲,有厚实感 |
| 冰花玻璃 | 1.20 - 1.30 | 0.30 - 0.50 | 背景几乎不可辨识 |
注意:表里的 IOR 和法线强度是配套的,不能只调一个。IOR 大而法线弱,背景会整体平移得像塑料板;IOR 小而法线强,背景会被高频噪声撕碎,看起来像信号干扰。
3. 法线扰动:让玻璃"毛"起来的核心手法
3.1 法线接在哪、强度怎么给
法线贴图直接接进材质的Normal引脚就够了,但"直接接"和"接得好"是两回事。渲染管线会拿这个法线去做两件事:一是在 Surface TranslucencyVolume 或 ForwardShading 模式下算光照,二是算折射方向。这意味着一处法线输入,同时影响了高光和折射,两个效果天然同步——这也是法线方案比"贴一张噪声图偏移 UV"高级的地方。
强度控制不要用贴图本身去调,而是用Lerp 在 (0,0,1) 和采样结果之间做插值,插值系数 t 就是强度。t=0 时法线完全平坦,t=1 时用满贴图强度。这种做法的好处是 t 是个干净的 0 到 1 参数,方便做成材质参数集暴露给美术,也方便后续做动画曲线。
我实测的经验区间:t 在 0.08 到 0.15 之间最适合"常规磨砂玻璃",超过 0.3 就开始不像玻璃了,像水波纹或者热浪扭曲。冰花玻璃那种效果可以到 0.4,但那时候基本是在做风格化,不是在模拟物理。
法线贴图的平铺次数比强度更影响观感。同样一张噪声法线,平铺 4 次的观感是"玻璃表面有起伏",平铺 20 次是"玻璃磨得很细"。我建议所有毛玻璃材质的法线平铺都不要低于 8,最好在 12 到 24 之间,否则近距离看会出现明显的大块扭曲,特别假。贴图分辨率也别省,256 的贴图平铺 20 次之后会出现明显的重复纹路,512 起步。
3.2 用粗糙度和菲涅尔做观感分层
单靠法线,玻璃会显得"均匀地毛",这不符合真实观察经验。真实玻璃有个特点:正对着看的时候最透,斜着看的时候最浑,这叫菲涅尔效应。磨砂玻璃在这点上尤其明显,贴脸看能看清后面,斜着瞄反而雾蒙蒙一片。
实现上我用一个Fresnel 节点(Exponent 设 3 到 5,Base Reflect Fraction 设 0.05 左右),输出接到两处:
- 接到Opacity,让边缘更不透明、中心更透明,形成自然的通透衰减;
- 通过一个 Lerp 混到法线强度上,让边缘的法线扰动更强、中心的扰动更弱。
第二处是关键。很多人只把菲涅尔接到不透明度上,结果玻璃边缘虽然变白了,但折射的扭曲程度没变,看起来像蒙了一层白纱而不是玻璃变厚。把菲涅尔混进法线强度之后,边缘的折射错位会同步加强,那种"外围厚实、中心清澈"的层次就出来了。
粗糙度这个通道,在纯折射方案里作用有限——半透明材质的 Roughness 主要影响高光形状,不会自动让背景变模糊。但它对高光的影响是真的:粗糙度 0.3 到 0.5 会让法线带来的明暗变化变柔和,0.1 以下则会出现细碎的高光颗粒,像玻璃上有砂。做磨砂玻璃我一般给 0.35 左右,配合法线能出一点点砂面的高光感。
3.3 双层法线与 UV 缓慢流动
单层法线有个问题:整块玻璃的扰动是静态的,纹理细节全一样,看久了会觉得像一张印上去的膜。解决办法是叠两层。
第一层用高频小尺寸法线(平铺 20 到 30),负责"磨砂"的细碎感,UV 完全不动,固定住材质的基本质感。第二层用低频较大尺寸法线(平铺 4 到 8),强度压低到 0.03 到 0.06,让它的 UV 做一个非常缓慢的平移,速度控制在 0.005 到 0.01 单位每秒。
两层法线叠加用BlendAngleCorrectedNormals节点,比直接 Add 或者 Lerp 效果好,能保住法线向量的单位长度,不会出现光照发灰。这一层慢速流动的作用不是做"水波",而是让玻璃上的扰动有一点点呼吸感,摄像机动起来的时候不会显得是完全静止的死纹理。
流动速度一定要慢到你几乎察觉不到。我做第一版的时候速度给到了 0.05,结果看起来像玻璃在融化,返工重做了三次才降到 0.008。这个参数没有理论值,纯靠看,原则是"盯着看十秒,不确定它到底动没动"就对了。
注意:如果这块玻璃要参与反射探针或者被镜面反射拍到,两层法线会让反射内容也变得有点破碎。这种情况要么把玻璃的Cast Ray Traced Reflection关掉,要么单独做一个干净版本给反射用,别指望一份材质通吃。
3.4 背景模糊的近似实现
前面说过,法线扰动只能打散位置,抹不掉内容。要让背景真正变柔,得自己采样多次做平均。虚幻引擎的半透明材质不会自动模糊背景,这一点跟某些离线渲染器不一样,必须自己动手。
做法是在材质里用Custom 节点,取屏幕 UV,在几个方向上偏移采样 SceneColor,然后取平均。核心逻辑大概是这样:
// Custom 节点内,UV 来自 ScreenPosition 的 ViewportUV // Radius 控制模糊半径,Samples 为固定方向数(不要用动态循环) float2 texel = Radius * ViewSizeAndInvSize.zw; float3 acc = 0; float2 dirs[8] = { float2( 1, 0), float2(-1, 0), float2( 0, 1), float2( 0, -1), float2( 0.7, 0.7), float2(-0.7, 0.7), float2( 0.7,-0.7), float2(-0.7,-0.7) }; for (int i = 0; i < 8; ++i) { acc += SceneTextureLookup(UV + dirs[i] * texel, 14, false).rgb; } return acc / 8.0;几个实操要点。第一,循环次数必须写死,用常量 8 或者 12,别写成由参数驱动的循环,编译器展开不了会直接掉性能。第二,采样器要开过滤,否则采出来是马赛克。第三,不同引擎版本里SceneTextureLookup的签名有细微差别,如果报错,改成用材质里的 SceneTexture 节点配合多组 UV 偏移手工连线,虽然连线难看但绝对能跑。
Radius我一般给 1.0 到 3.0,数值越大越糊,但采样点之间的空隙也会暴露成方块状的伪影。要更平滑就得升到 12 或 16 次采样,或者改用在两个方向做两次偏移的半近似做法。
这套东西的成本,在一个 1080p 分辨率下、屏幕占比 30% 的玻璃上,8 次采样大约会多出接近一毫秒的 GPU 时间。所以它只适合用在少量、大面积、占据画面主要的玻璃上。远景玻璃千万别开这个,纯浪费。
4. 管线配合:光照模式、深度与排序
4.1 半透明光照模式的三种选择
Translucency Lighting Mode 的选择,很多人是随手点的,其实三个值的行为差别很大。
Volumetric用的是体积光照贴图,光源对半透明物体的影响是空间查表,非常便宜,但精度低、会漏光。它适合大面积的雾、烟这类本来就不需要精确光照的物体。用在玻璃上的话,法线带来的高光基本上看不出来,效果会显得很"扁"。
Surface TranslucencyVolume是我最常用的。它会对半透明表面做一次近似的表面光照计算,能吃到一个方向光加若干点光源的影响,法线的高光能出来,折射的扰动也能被光照"呼应"上——也就是法线复杂的地方明暗也有变化,两个效果合在一起,玻璃的厚实感才立得住。
Surface ForwardShading走的是完整的前向着色,能吃到阴影、能吃到所有光源、高光最准确。代价是它把半透明材质当成一个不透明的表面来算光照,着色器指令数会翻好几倍。我的判断标准很简单:这块玻璃是不是画面主视觉?是就上 ForwardShading,不是就用 TranslucencyVolume。
有个细节值得提一句:ForwardShading 模式下,半透明材质能接收动态阴影,这在做那种阳光透过磨砂玻璃、玻璃上有树影斑驳的场景里非常关键。TranslucencyVolume 模式下阴影基本是吃不到的,只能靠贴图硬画。
4.2 深度与排序的冲突处理
半透明材质不写深度缓冲,这就带来两个老大难问题:排序错乱和穿透。
排序问题的表现是:两块玻璃前后重叠时,靠后的那块突然被画到前面来了,或者一块玻璃跟一片半透明树叶交叉时,树叶忽而挡在玻璃前、忽而跑到后面去。原因是半透明物体按物体中心到相机的距离排序,对于大面积或形状复杂的物体,这个"中心距离"根本不能代表真实的遮挡关系。
处理方法有三层:
- 在项目设置里把 Rendering 下的Translucency Sort Policy改成 Per Triangle。这会把排序粒度从物体级降到三角形级,排序错误率大幅下降,代价是 CPU 端的排序开销上升,三角形多的物体要慎重用。
- 在 Actor 上手动设Translucency Sort Priority,数字大的画在后面。玻璃这类大面积物体我一般给它设一个偏大的值(比如 10 到 20),让它在多数半透明东西后面画。
- 实在不行就拆模型,把一块大玻璃拆成几块,让每块的中心能代表自己的位置。
穿透问题指的是:玻璃后面的不透明物体被折射采样采到了错误的位置,导致看起来玻璃"穿"进了墙里。根因是折射采样的是 SceneColor,那里面只有已渲染的不透明内容,偏移之后可能采到了物体边缘之外的地方。缓解手段是给材质加一个Pixel Depth Offset,按视角做一点向内推,让边缘的采样点落在正确位置;或者用 Depth Fade 做柔化过渡,把最难看的那一圈糊掉。
注意:材质属性里的 RefractionDepthBias 是老版本遗留下来的办法,现在新版本里它跟 Pixel Depth Offset 的功能有重叠,同时用会打架。我只用后者。
4.3 反射与阴影的取舍
毛玻璃的反射很容易被忽略。真实磨砂玻璃是会反射的,但反射内容被粗糙表面打散成柔和的亮块,不会有清晰的镜像。屏幕空间反射对半透明材质基本无效,所以指望 SSR 给玻璃反射是不现实的。
我的替代方案是:用一张Cubemap 或者反射探针,通过一个按粗糙度采样对应 Mip 的方式接进来,混到 Emissive 或者 Base Color 上,用很低的强度(0.05 到 0.15)。这不会给准确的反射,但能让玻璃表面出现环境色的微弱起伏,视觉上"接住"了周围的光,比完全没反射要真实得多。粗糙度越高就采越粗的 Mip,跟法线的强度联动,法线强的地方反射也糊。
阴影这边,半透明物体默认不投影。如果想让玻璃在地上有影子,得开Cast Shadow 里的 Shadow as Two Sided或者用一张 Mask 做替代投影面片。但玻璃的影子应该是柔和的、带点透光的,用不透明面片投硬影会很假。我一般干脆不投,或者在玻璃正下方放一个美术手绘的柔和贴片阴影,配合 Fixed 的 Shadow 层级,控制起来更省事。
5. 性能预算与平台差异
5.1 折射的显存与带宽账
折射本身的开销,主要不在计算,而在采样。每个半透明像素都要去 SceneColor 纹理里做一次带偏移的采样,而且这个采样因为 UV 是动态的,命中率低,缓存帮不上忙。在一张 1080p 的画面上,如果玻璃占了 40% 的像素,那就是约 83 万个像素各做一次随机访问的纹理采样,带宽压力不小。
如果再加上第 3.4 节的 8 次模糊采样,成本直接乘八倍。这就是为什么我在项目里会给毛玻璃定一个像素预算:全画面所有毛玻璃的覆盖面积,控制在 25% 以内,超过就降级。降级的顺序是:先关模糊,再降法线平铺,最后降材质复杂度。
还有一个容易被忽略的点:折射会强制 SceneColor 的提前解析。在某些渲染路径下,一旦场景里出现了使用折射的材质,引擎就得把 SceneColor 从 MSAA 状态解析成普通纹理,这一步在开启较高采样数的时候不便宜。所以"我只加了一块小玻璃"这件事,有时反而会让整帧的渲染路径发生变化,帧时间跳动得莫名奇妙。
5.2 移动端与前向渲染的硬限制
移动端做毛玻璃,限制比想象中多。首先,移动端前向渲染下折射是可用的,但要求平台支持 SceneColor 采样(一般 ES3.1 / Vulkan 以上的设备都行),低端设备直接不生效,材质会退化成普通的半透明,看起来就是一块半透明的板子。
其次,移动端的半透明光照模式选择少,Surface ForwardShading 基本别想,多数情况下只能用简单光照。这意味着法线带来的明暗层次会弱很多,效果主要靠折射和贴图撑。
第三,移动端的半透明排序问题更严重,因为移动端的性能不允许开 Per Triangle 排序。所以移动项目的毛玻璃,我建议从设计上就规避重叠——别让两块玻璃互相穿插,别让玻璃和大量半透明特效叠在一起。
我在移动项目上的做法是准备两套材质:一套高品质的给主要镜头,一套降级版(去掉第二层法线、去掉菲涅尔混法线、法线平铺降到 8、IOR 固定 1.1)给远景和量产物件。切换靠 Quality Level 或者材质参数集的预设,不要把两套逻辑塞在一个材质里用开关控制,那样两边的指令都在,谁也没省下来。
5.3 用 LOD 和参数分级做降级
材质本身没有 LOD,但可以对它做参数分级。我在材质参数集里预留了几个标量:NormalStrength、IORScale、Layer2Enable、BlurEnable。然后在 Actor 的 Construction Script 或者 Blueprint 里根据距离往这些参数里写值。
距离分级我一般分三档:5 米内用满配,5 到 20 米关掉第二层法线和模糊,20 米以上把法线强度砍半、IOR 乘 0.7。这套逻辑写起来不超过二十行,但对大规模场景的帧数改善很实在。
另外还有个技巧,如果远处那些毛玻璃观众根本看不清细节,可以直接把它们换成不折射的普通半透明材质,只保留一个菲涅尔亮边。远看几乎分辨不出区别,成本降一个数量级。
6. 排查实录:这些现象分别对应什么
6.1 现象对照速查表
做这个效果踩过的坑不少,我把最常见的现象和原因整理成表,遇到问题先对一遍,能省很多时间。
| 现象 | 最可能的原因 | 处理方式 |
|---|---|---|
| 法线怎么调背景都不动 | Refraction 引脚填的是 1.0 或没接 | 把 IOR 提到 1.05 以上 |
| 背景整体平移,没有起伏 | 法线强度太低或法线平铺次数太少 | 强度提到 0.15,平铺提到 12 以上 |
| 背景像被信号干扰撕碎 | 法线强度过高或贴图频率过高 | 强度降到 0.2 以内,平铺降到 16 |
| 折射完全无效 | Blend Mode 没设成 Translucent | 改混合模式 |
| 移动端没有折射 | 设备不支持 SceneColor 采样 | 提供不折射的降级材质 |
| 两块玻璃排序错乱 | 半透明排序粒度不够 | 开 Per Triangle 或设 Sort Priority |
| 玻璃边缘穿进墙里 | 折射采样越界 | 加 Pixel Depth Offset 或 Depth Fade |
| 玻璃表面没有高光 | 光照模式选了 Volumetric | 换成 Surface TranslucencyVolume |
| 玻璃上的法线在光照下没变化 | 材质是 Unlit 或者法线接到了错误引脚 | 用 Default Lit,法线接 Normal |
| 远景玻璃闪烁 | 深度冲突或与半透明特效重叠 | 加排序优先级,或拉开空间距离 |
6.2 几个反直觉的坑
有几个坑是我反复栽跟头才记住的,写下来给后来人省点时间。
第一个:法线贴图的平铺次数,与材质实例里的参数覆盖会打架。如果你在材质里用的是 Texture Sample 节点的 UV 输入接了一个 Multiply,那么这个 Multiply 的 B 值(平铺次数)在材质实例里能不能改,取决于你有没有把它提升为参数。很多人以为改了参数没生效是引擎 bug,其实是那个值压根没暴露。解决办法是老老实实用 Scalar Parameter 节点,别嫌连线多。
第二个:Fresnel 混进法线强度的时候,顺序很重要。正确顺序是先用 Lerp 把原法线和平坦法线混合,再把菲涅尔的结果乘到 Lerp 的 Alpha 上,然后整体送到 Normal 引脚。如果反过来先乘菲涅尔再 Lerp,边缘的法线强度会被 Lerp 的基准值拉回去,菲涅尔的效果大打折扣。这两种接法在静态截图里看不出区别,摄像机动起来才露馅。
第三个:玻璃背后如果是天空盒,折射会采到错误的内容。因为天空盒在某些渲染路径下不写入 SceneColor 的深度,折射偏移之后可能采到上一帧的内容或者纯黑。表现就是玻璃边缘出现一圈黑边或者闪烁。这种情况我一般在材质里加一个很薄的 Depth Fade,或者干脆把折射强度在边缘压到很低。
第四个:Surface ForwardShading 模式下,材质的 Opacity 会影响光照计算。Opacity 设成 0.3,光照也会按 0.3 衰减,玻璃会显得特别暗。这不是 bug,是引擎的物理逻辑。想让玻璃亮起来,要么提高光照强度,要么在 Emissive 上补一点环境色,别指望通过强行把 Opacity 拉到 1 来解决,那样折射就没了。
第五个:预览窗口里好看,进游戏就变样。材质编辑器预览用的是自己的场景和光照,跟实际关卡完全不是一回事。我所有的参数标定都在实际关卡里做,用 Sequencer 摆一个能覆盖实际运镜的相机,一边走一边调,调完再回材质里把值写死。在预览窗口里调数值,十有八九要返工。
最后一个心得是关于迭代节奏的。毛玻璃这种东西,第一次调出来的参数大概只有 60 分,因为你的眼睛会适应。我的做法是每次调完就把材质存一版,隔一天再看,这时候不适应了,问题会自己冒出来。我自己那块"厚磨砂玻璃砖",前后存了十一版才定稿,最后一版跟第一版的数值差了快一倍。
如果后面还想继续扩展,可以在同一套骨架上加带噪点的散射——把法线扰动的同时,用一点点微弱的自发光做内部散射,模拟光从玻璃侧面穿过来的效果,那个东西在暗环境里能显著提升真实感。不过它需要灯光的配合,不是纯材质能搞定的,等主效果稳定了再动。