这个 Shader 的目标不是「画一张冰贴图」,而是用 多层纹理 + 视差采样 + PBR 光照 + 深度透明 组合,在实时渲染里模拟冰的 体积感、内部吸收、表面高光和边缘融合。
一、真实冰面有哪些视觉特征?
| 特征 | 表现 | Shader 对应 |
|---|---|---|
| 半透明体积 | 能看到内部,厚处更暗 | 十层 _Ice_Gloss 视差采样 + 内部变暗 |
| 表面高光 | 光滑、有反射 | 高 Smoothness + 环境反射 |
| 微观结构 | 冰晶、裂纹、起伏 | _Normal 法线贴图 |
| 局部脏/暗 | 夹杂物、气泡 | _AOMap |
| 边缘柔和 | 与地形/水面自然衔接 | 场景深度差 Alpha |
| 局部发光 | 内部散射、蓝调 | _EmissionMap |
Shader 把上述特征拆成 4 条独立管线,最后在 PBR 里合成。

二、整体流程

渲染状态:Transparent 队列、ZWrite Off、Alpha 混合,所以冰是「盖在场景上」的透明层,而不是不透明固体。
三、核心模块详解
1. 基础色(冰的本体颜色)
baseColor = MainColor × BaseMap × BaseMapIntensity
_BaseMap:冰的整体色调、纹理变化(偏蓝、偏白、裂纹底色等)_MainColor:整体染色_BaseMapIntensity:亮度倍增(Ice2 材质里约 9,让冰更亮、更「透」)
这是后续所有效果的底色。
2. 内部深度模拟(最关键的部分)
真实冰里,光穿过内部时会因杂质、气泡、厚度而被 吸收/散射,厚或脏的地方更暗。Shader 用 伪体积采样 来近似,而不是真 3D 体渲染。
原理:视差 + 多层连乘
视线 → 切线空间 → parallaxDir (viewDirTS.xy)
每层 UV 偏移 = uv × Tiling + depthOffset × parallaxDir
depthOffset 每层累加 _DepthValue
10 层 _Ice_Gloss.r 连乘 → depthMask
示意(侧视):
表面 ─────────────────────────
↘ 视线
层1 层2 层3 ... 层10 ← 每层采样 _Ice_Gloss,UV 沿视线方向偏移
● ● ● ●
_Ice_Gloss:内部结构噪声(亮=更「透/空」,暗=更「实/厚」)_DepthValue:每层步进(约 -0.0007,负值控制偏移方向)_Ice_GlossTiling:噪声缩放- 10 层连乘:一层偏暗会拉低整体 → 模拟「穿过多层都遇到吸收」
内部变暗公式
darkened = baseColor × (1 - saturate(pow(depthMask, DepthIntensity)))
albedo = lerp(darkened, baseColor, FinalColorLerp)
| 参数 | 作用 |
|---|---|
_DepthIntensity |
变暗强度;越大内部对比越强 |
_FinalColorLerp |
在「全暗内部」和「原色」之间混合;0=完全内部效果,↑=更亮、更平 |
为什么用连乘而不是相加?
连乘更像「每层都有概率被吸收」;任一层很暗,整体就明显变暗,体积感更强。
3. 表面 PBR(看起来像冰,而不是塑料)
内部颜色算完后,仍走 URP 标准 Lit PBR:
| 参数 | 来源 | 含义 |
|---|---|---|
| Normal | _Normal × _NormalScale |
表面微观起伏、反射方向 |
| Smoothness | (1 - IceRougness.r) × SmoothNess |
越光滑高光越强 |
| Occlusion | _AOMap.r |
缝隙/脏区变暗 |
| Emission | _EmissionMap × EmissionIntensity |
内部散射、蓝调 |
| Metallic | 固定 0 | 冰是电介质,不是金属 |
| Specular | 固定 0.5 | 中等镜面反射 |
最后调用 UniversalFragmentPBR:主光、附加光、阴影、环境反射、Fog 都由 URP 处理。
4. 深度透明(边缘与接触面融合)
alpha = saturate((sceneDepth - pixelDepth) / DepthFadeDistance)
sceneDepth:屏幕该像素处 背后场景 的深度pixelDepth:冰表面自身的深度- 差值大(冰浮在水面/悬空)→ Alpha 高 → 更实
- 差值小(冰贴着地面/与其他面重合)→ Alpha 低 → 更透、边缘化开
这是 Soft Depth Fade,避免冰与地形交接处出现硬边。
四、三条 Render Pass
| Pass | 作用 |
|---|---|
| Forward | 主渲染:算冰面颜色 + 透明 Alpha |
| DepthOnly | 写深度缓冲,供后续效果使用 |
| DepthNormals | 输出法线,供 SSAO 等 |
Forward 关 ZWrite,DepthOnly 开 ZWrite,是透明物体常见配置。
五、制作与调参流程(美术向)
Step 1:准备贴图
| 贴图 | 建议内容 |
|---|---|
| BaseMap | 冰整体色调、大尺度变化 |
| Ice_Gloss | 内部噪声(Grayscale),亮=疏松,暗=致密 |
| Normal | 表面冰晶/起伏 |
| IceRougness | 粗糙度(亮=糙,暗=滑) |
| AOMap | 裂缝、脏污遮挡 |
| EmissionMap | 可选,内部蓝调/亮点 |
Step 2:基础外观
- 设
_MainColor(偏冷蓝/青白) - 调
_BaseMapIntensity控制整体亮度 - 用
_Normal、_SmoothNess定表面质感
Step 3:内部体积感
_DepthIntensity↑ → 内部明暗对比增强_DepthValue控制视差步长(观察角度变化时内部纹理位移)_FinalColorLerp控制「有多像实心冰 vs 有多亮」
Step 4:边缘融合
_DepthFadeDistance(Ice2 约 0.4)- 太小→过渡硬;太大→整体发虚
Step 5:场景验证
- 不同角度:视差是否自然
- 与地形/水面交界:是否有硬边
- 光照变化:高光 + 环境反射是否合理
六、设计思路小结
冰面效果 = 体积假阴影(Ice_Gloss 视差)
-
标准 PBR 表面(Normal / Roughness / AO)
-
深度透明(与场景融合)
-
可选自发光(内部散射)
没有真体积渲染或光线步进,而是用 10 层 2D 视差采样 近似体积吸收------在手游/实时场景里,这是 性能与效果 之间较平衡的做法。