UE5一些材质技巧分享

01 雪

使用 菲尼尔 给基础颜色增加边缘过渡

闪烁的雪点

通过两层 闪烁的点进行混合

  • 使用 ViewSize / 512 ,其中512为贴图的尺寸

  • 由于雪点只有在 光照情况下才可以看到,因此使用 SkyAtmosphereLightDirection 和 VertexNormalWs,通过太阳的方向和顶点的法向 通过Dot计算得到遮罩

效果:

ScreenPosition

  • ViewportUV(常用)

    • 范围:(0,0) 左上 → (1,1) 右下
    • 就是屏幕 UV ,和 TexCoord0 在全屏后处理里基本一样。
  • PixelPosition

    • 范围:(0,0)(ViewSize.X, ViewSize.Y)
    • 等于:ViewportUV * ViewSize,直接是像素坐标

    PixelPosition = ViewportUV × ViewSize

    ViewportUV = PixelPosition ÷ ViewSize

ViewSize

输出当前渲染画面的宽度(X 轴)和高度(Y 轴)像素值

  • 主要用途:

    • 制作自适应效果,比如根据屏幕分辨率调整 UI、特效的大小
    • 实现和屏幕尺寸相关的后处理效果(如径向模糊、边缘检测)
    • 让材质在不同分辨率下保持效果一致
ScreenResolution

法线

计算法线的方式

只需要RG的内容

复制代码
DeriveNormalZ( RG * 2 - 1)
  • 多层法线混合增加细节
  • 使用 BlendAngleCorrectedNormals

使用 DeriveNormalZ(Normal * 2 -1) 是对 法线 进行增强边缘细节,需要配合正常的法线使用不然就会出现黑色法线,是负数

  • 乘2 减1 是 将取值区间由 0,1 转换为 -1,1

DeriveNormalZ

通过 法线的 XY 通道计算法线,注意 不同的 法线 计算方式略有不同,要考虑到平台以及存储时进行了什么设置

  • 通常生成的法线贴图 Z 通道 可以不需要,在UE中可以看到B通道是无法关闭的,因为是通过计算得到的
  • 因此 在 优化时,便可以只是要两个通道 存储法线,多余的通道可以存放 Roughness 、 AO 等灰度贴图

Normal = (X, Y, Z),且单位向量,满足勾股定理

,那么

使用 HLSL

复制代码
float2 N_xy = Normal.xy;
float Z = sqrt(1.0 - dot(N_xy, N_xy) );
return float3(N_xy, Z);

dot 计算,相当于两个向量的乘法,二维向量的乘法 是一个常量

  • (a,b)(c,d) = ac + bd

BlendAngleCorrectedNormals

专门用来正确混合两张法线贴图的材质函数(Material Function)

  • 避免直接 Add/Multiply 导致的细节变平、光照错乱问题

  • 直接 Add:细节会过强、扭曲

  • 直接 Lerp:细节会变平、丢失

  • BlendAngleCorrectedNormals:按角度校正算法重定向细节法线,保留基础形状 + 叠加细节,效果自然

02 岩石

缩放模型会导致 贴图的细节丢失,解决方法

将模型的 缩放与 UV 进行 相乘

多层法线的混合

利用加法进行计算,需要将混合的法线,B 设置为0,只需要将 RG 利用加法进行相加即可

复制代码
    ( RG \* (2,2,0) - (1,1,0) )

增加细节使用,三层法线,两层细节法线

  • 将 B 使用 1-x 取反后 ,用作粗糙度 并累加
  • 如果 有 AO 贴图,可以 将 AO 与 基础纹理 采用 Blend_Overlay 进行混合

效果:

Blend_Overlay

暗部相乘、亮部滤色 ,整体增强对比度、保留底层形状,非常适合叠细节(脏迹、划痕、磨损)

  • UE 里 的 Photoshop 叠加(Overlay)图层模式

03 积雪岩石

主要利用 法线在世界空间的 Z方向的朝向,得到遮罩

  • 用于材质的 Lerp混合

效果:

04 冰

冰表面

制作折射

  • 将顶点法线转换为 屏幕空间,并于 屏幕的 UV进行相加,相当于使用法线对屏幕进行空间的扰乱(类似于特效制作中Distortion),将得到的 UV传入 Scene Color

Scene Color

Scene Color = 当前屏幕已渲染完成的场景最终颜色(帧缓存画面)

  • 仅限:后处理材质、屏幕空间材质、UI 材质

Scene Color 与 SceneTexture:SceneColor(新)

  • 两种的一致的,只不过 Scene Color是直接调用的,SceneTexture需要设置

    Scene Color + ScreenPosition(ViewportUV) + ViewSize = 绝大多数屏幕特效基础

常用方式:

  • 给整张画面叠暗角、滤镜、胶片颗粒、划痕、雾效、复古滤镜

  • 局部颜色修正、调色

    • 色相偏移、饱和度调整、冷暖色调分离
    • 配合 ScreenPosition左右分色、上下渐变调色
  • 扭曲 / 扰动画面(水汽、热浪、镜头晃动)

  • 结合像素位置做锐化 / 模糊 / 描边

    • ScreenTexelSize + ViewSize 取相邻像素,实现:

      • 全屏模糊、径向模糊
      • 画面锐化、边缘描边、卡通轮廓

冰内部纹理

采用自定义 反射向量作为 UV进行采样

  • 使用 CustomReflectionVector 获取 反射向量

  • 使用 RG 作为基础 UV 的 Distortion

  • B取绝对值,用 100 / abs(B) * RG,其中 100 表示可见程度,数值越大,越深

  • 使用 1/1024 8 RG 控制平铺,其中 1024纹理的像素

使用两层反射,制作并冰层的遮罩

CustomReflectionVector

自定义法线 (可和材质主法线不一样)去算反射向量 ,专门用来做细节凹凸反射、镜面划痕、局部扭曲反射

和默认 ReflectionVectorWS 的区别

  • ReflectionVectorWS :固定用主法线 + 相机方向算(受材质 Normal 端口影响)
  • CustomReflectionVector :用你输入的任意法线 算,和主法线完全独立

反射公式:

复制代码
R = reflect(-CameraDir, CustomNormalWS)

HLSL 代码:

复制代码
// HLSL
float3 Nor = normalize(NormalVector);
float3 Cam = CameraVector;
return dot(Nor,Cam)*Nor*2 - Cam;

// 简化
float3 N = normalize(NormalVector);
return 2 * dot(N, CameraVector) * N - CameraVector;

根据平行四边行法则,2*Normal*cos=Ref+Camera

05 金属

利用法线,获取菲尼尔 边缘,作为 UV 采样一条颜色纹理,与金属 的基础颜色 混合

效果:

旗帜

注意:

  • 创建的平面坐标轴要在边缘
  • 注意平面又有很多的顶点,不然飘动不起来

基础飘动

通过采用本地位置,根据需要飘动的轴 使用 ComponentMask

  • 注意 要使用 要先乘以0.001,因为UE的单位是 1m,为何是0.001呢,是因为 频率1m作为基准还是有点大

然后就是使用 时间,控制 摆动速度和方向

使用 Sine 创建 波形,再通过 参数,控制 振幅

最后乘以 位置信息,作为渐变,让开始位置到结束位置 振幅依次增加

  • 平面位于XZ,则Y轴是 振幅 的方向
  • 平面位于YZ,则X轴是 振幅 的方向,此处 则是采用这种

LocalPosition

UE内置节点,其实就是 WoldPosituion 通过 Transform 进行空间变换得到的

优化

旋转,会导致 偏移失效

仅仅只需要,将偏移的向量 转换空间

  • 本地空间 到 世界空间即可

注意:需要修改 Amplitude 为 Z轴

  • 原因是 物体在场景中进行了旋转,会导致 世界空间 和本地空间的变换 出现差异
  • 注意模型的轴向 与 世界坐标轴的区别

本地轴向:

世界轴向:

法线

查看 法线信息

  • 视口 中 Lit 位置,找到 Buffer Visualization 可以查看所有渲染阶段的 输出

可以看到 旗帜的法线是没有变化的,是统一的颜色

  • 这很明显不合理,因此需要进行调整

制作思路:

  • 采用 sin + 0.5 = 1- Cos 作为法线的振幅,在数学的三角形中可以知道 Sin 和 Cos的关系

通过对比波形

最后得到的节点:

注意法线设置 与 模型轴向 有关