Unity Shader 冰面 Shader 制作原理与流程

这个 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:基础外观

  1. 设 _MainColor(偏冷蓝/青白)
  2. 调 _BaseMapIntensity 控制整体亮度
  3. 用 _Normal、_SmoothNess 定表面质感

Step 3:内部体积感

  1. _DepthIntensity ↑ → 内部明暗对比增强
  2. _DepthValue 控制视差步长(观察角度变化时内部纹理位移)
  3. _FinalColorLerp 控制「有多像实心冰 vs 有多亮」

Step 4:边缘融合

  1. _DepthFadeDistance(Ice2 约 0.4)
  2. 太小→过渡硬;太大→整体发虚

Step 5:场景验证

  • 不同角度:视差是否自然
  • 与地形/水面交界:是否有硬边
  • 光照变化:高光 + 环境反射是否合理

六、设计思路小结

冰面效果 = 体积假阴影(Ice_Gloss 视差)

  • 标准 PBR 表面(Normal / Roughness / AO)

  • 深度透明(与场景融合)

  • 可选自发光(内部散射)

没有真体积渲染或光线步进,而是用 10 层 2D 视差采样 近似体积吸收------在手游/实时场景里,这是 性能与效果 之间较平衡的做法。

相关推荐
探求虚无1 天前
用 AI 在 Unity 里做一款 RTS:最难的不是生成代码,而是证明它真的能玩
人工智能·unity·游戏引擎
17岁的勇气2 天前
Unity Shader unity文档学习笔记(二十二):shader变体
笔记·学习·unity
寂寞的船3 天前
【Unity知识速递】第10期 Unity GC 零分配实战:从 UnityEngine.Pool 到手动 GC 控制的全链路优化
jvm·unity·c#·游戏引擎·lucene
Martina_03214 天前
AI生成3D场景的霓虹灯一开就糊成光团?用6步检查Emissive、Bloom与曝光
人工智能·3d·ai·自然语言处理·游戏引擎·材质·贴图
寂寞的船5 天前
【Unity知识速递】第8期 IL2CPP 托管堆内存碎片与原生堆交互机制深度解析
unity·游戏引擎·交互
寂寞的船6 天前
【Unity知识速递】第5期 Unity 6.2 深度解析:AI Assistant 登场,World Space UI 与 Sentis 全面升级
人工智能·ui·unity
寂寞的船6 天前
【Unity知识速递】第4期 MCP for Unity:用 AI 自然语言控制编辑器
人工智能·unity·编辑器
淡海水6 天前
09-04-内存-Unity原生对象生命周期
unity·c#·游戏引擎·gc
寂寞的船6 天前
【Unity知识速递】第6期 URP性能优化完全指南:从内存到GPU的三维调优
unity·性能优化·编辑器
寂寞的船6 天前
【Unity Bug挑战】第10期 SerializeReference 内存泄漏之谜
unity·c#·游戏引擎·bug