UE5 材质 基础知识

前言

本篇总结一些常用的UE5材质相关的知识点,因为其中有些是图形学内容而这些内容在笔者以前的博客中均有记载,所以只是简单提及。随着本人的不断学习,该篇总结也会不断丰富

uv

与unity不同,UE的uv坐标的u轴正方向指向右,而v轴正方向指向下
例如下图,我输出了屏幕的坐标值,可以看到左上角是完全黑的,右边红色更多,下面绿色更多

坐标系

  • UE使用左手坐标系且向上轴是z轴,x轴向左
    image-20230510222327897
  • 俯仰角(Pitch):绕Y轴旋转
  • 偏航角(Yaw):绕z轴旋转
  • 翻滚角(Roll):绕y轴旋转

PBR

Base Color

  • Base Color定义物体表面的diffuse颜色
  • 对于粗糙的物体,颜色值范围[50,240]
  • 对于光滑的物体,颜色值范围[20,240]

image-20230509232435840

法线

  • 法线定义物体表面的形状
  • 不可以手动创建法线图!而是使用烘培

image-20230509232957693

镜面反射

  • Specular代表反射率——有多少光被反射
  • 适用于非金属材质。非金属材质仅仅反射4%的光
  • 菲涅尔现象:从很斜的角度看向镜面反射材质的物体,会看到绝大部分高光

image-20230509233754446

粗糙度

  • 1代表最粗糙,0代表最光滑

image-20230509234528365

金属度

  • Metallic与Base Color 和 镜面反射有关
  • 所有金属的Base Color都大于180

image-20230509235307304

  • Base Color 和 Specular使用金属度的区别
    image-20230509235054823

数据类型

float

  • float

    常用于粗糙度、镜面反射、金属度等

  • float2

    常用于uv

  • float3 & float4

    常用于计算

ComponentMask & SplitComponents

  • ComponentMask允许从输入中挑选某个通道子集(R、G、B和/或A)并输出
  • SplitComponents与Mask类似,不过它更加灵活
    image-20230510002009642

Append & AppendMany

  • Append合并两个类型,形成一个新类型
    image-20230510002405885

  • AppendMany可以合并多个通道
    image-20230510002634393

Swizzle

  • 排列floatn分量
    image-20230510002820218

TextureCoordinate

虚幻引擎坐标材质表达式

image-20230510132055844

  • 坐标索引:指定要使用的 UV 分量
  • U 平铺(UTiling):指定 U 方向上的平铺量(可理解为范围)
  • V 平铺(VTiling):指定 V 方向上的平铺量
  • 解除镜像U:如果为 true,那么撤销 U 方向上的所有镜像(镜像寻址模式)
  • 解除镜像V:如果为 true,那么撤销 V 方向上的所有镜像

TexCoord[0] & SceneTexelSize

  • 获取当前像素的uv坐标

  • 避免纹理分辨率对纹理的采样影响

    • 假设有个100x100的纹理图,若想采样某uv坐标右边的像素,可以加上(0.01,0)。但这存在一个问题,当纹理图的分辨率变化后,采样的可能就不再是右边的像素

    • 解决方法:SceneTexelSize

Time

Constant Material Expressions in Unreal Engine

  • Time节点用于为材质添加一个时间属性,随时间变化材质的uv坐标也会改变

  • Ignore Pause:如果为true,即使游戏停止,时间也会继续变化

  • peroid(周期):在t时长内从0到t,时间不断增长,到t时会自动回到0
    image-20230510141437407

TwoSidedSign

  • 当开启"Two Sided"后,再使用"TwoSidedSign"节点可以用于确定normal方向,因为"TwoSidedSign"会输出正面朝向的法线为1,输出背面朝向的法线为-1
    image-20230527134757630

函数

Absolute World Position

  • 输出当前pixel基于相机的world space中的位置,也就是用vertex world space - camera world space。相当于Unity中的基于深度重建世界坐标

ActorPositionWS

  • 输出物体在world space中的位置

BlendAngleCorrectedNormals

  • 与普通的lerp不同,该函数用于混合两个normal map
  • 关于计算方式及其他常用的blend normal map的方法可以参考笔者的另一篇(blend normal map的四种方式)

CheapContrast

  • 通过将高光值拉低,把阴影值拉高来提高图像的对比度

  • 一般用于风格化渲染

  • 实现

    half CheapContrast(half In, half Contrast)
    {
        half temp = lerp(0 - Contrast, 1 + Contrast, In);
        return clamp(temp, 0.0f, 1.0f);
    }
    

DeriveNormalZ_Function

  • 给定xy分量求切线空间的z分量并输出
    image-20230520155320994
  • 计算公式:\(1=x^2+y^2+z^2\)

DepthFade

image-20230520174655649

  • 隐藏半透明对象与不透明对象相交时出现的硬线

  • Opacity:接收DepthFade的对象的不透明度

  • FadeDistance:发生Fade的距离阈值

  • 工作原理

    当两个深度相同时,像素的不透明度为0;当间距增加时,像素的不透明度为1

    • 需要两个对象

      1. 当前绘制的半透明像素深度
      2. 半透明像素后的第一个不透明像素的深度(通过depth buffer获取.半透明像素的深度不写入深度缓冲区)
    • 公式

      float spacing = sceneDepth - pixelDepth;
      float fade = saturate(spacing/fadeDistance);
      

Desaturation

Color Material Expressions in Unreal Engine | Unreal Engine 5.1 Documentation

  • Desaturation(去饱和度)用于降低输入颜色的饱和度,转换为一定百分比的灰度——彩色图变灰度图
  • Luminance Factors:每个通道的贡献量
  • Fraction:去饱和度量.如果是负数则是增强饱和度
  • 计算公式:定义去饱和颜色 D、输入颜色 I 和亮度系数 L
    Out = (1 - Fraction) * dot(I, D) + Fraction * I 
    

DistanceToNearestSurface

  • 含义:输出当前点到最近物体的带符号的距离(其实就是距离场)

  • 启用距离场:单单启用DistanceToNearestSurface,还没法计算距离场,需要改一下"Project Setting"

    启用下图中的"Generate Mesh Distance Fields"
    image-20231018153633607

DistanceFieldGradient

  • 含义:输出距离场方向(向外)
    image-20231018154122798
  • 注意:一定记得normalize!

Fresnel

image-20230520172112625

  • 作用:计算基于表面法线和相机方向点积的衰减。当表面法线和相机方向向量平行,则输出0;当表面法线和相机方向向量垂直,则输出1;输出范围[0,1]

  • 公式
    关于Fresnel的公式民间有两种版本

    • 第一种:基于PBR
      \(R_F(\theta_i) = R_F(0°) + (1 - R_F(0°))(1-\cos \theta_i)^5\)\(R_F\)也就是PBR常提到的\(F_0\)

      float Fresnel(float VoH, float F0)
      {
          return F0 + (1 - F0) * MyMath::Pow5(1 - VoH);
      }
      

      常见\(F_0\)image-20230221140853371

    • 另一种:基于表面法线和相机方向

      float Fresnel(float VoN, float Power)
      {
          return pow(1.0 - saturate(VoN), Power);
      }
      
  • ExponentIn:控制衰减速率

  • Base Reflect Fraction:从正对表面的方向查看表面时,镜面反射的小数。若使用此参数,会取代"ExponentIn"

Frac

  • Frac用于输出参数的小数部分,且输出范围为[0,1]

  • 图像

    image-20231128165401811

  • 例子
    frac(0.2) = 0.2;frac(-0.2) = 0.8;frac(0.0,1.6,1.0) = (0.0, 0.6, 0.0)

Floor

  • Floor()四舍五入到小于参数的整数值

  • 图像

    image-20231128165443488

  • Floor(0.2, 1.6) = (0.0, 1.0)

InvLerp

float Invlerp(x, y, a)
{
    return (a - x) / (y - x);
}

Lerp

  • 根据 Alpha 在 A 和 B 之间进行线性插值(当 Alpha = 0时为 A ,当 Alpha = 1时为 B )

    out = (1 - Alpha) * A + Alpha * B
    

Motion_4WayChaos

  • 对同一纹理进行四次不同uv的叠加,以实现运动混乱效果

    • Divisor
      一般情况是取0.25,因为该函数对四个纹理相加,最后需要乘以0.25来取平均值。当然,该值也表示纹理的明亮程度

Noise

Utility Material Expressions in Unreal Engine | Unreal Engine 5.1 Documentation

  • Scale

    缩放噪声单元大小

  • Quality

    外观/性能

  • Function

    噪声的分类

  • Turbulence

    每个噪声给结果加一个它的绝对值。用于改变视觉特征,如陡峭的山脊

  • Levels

    噪声大小乘以Levels。如若shader执行64个指令和8个纹理样本,而levels = 6,则循环六次(64x6个指令,6x8个纹理样本)

  • Output Min

    输出的最小值

  • Output Max

    输出的最大值

  • Level Scale

    确定新的信号频率的Scale变化量。一般设为2或更高

  • Tiling

    用于noise函数,支持平铺

  • Repeat Size

    noise多久重复一次

  • FilterWidth

    控制noise纹理的模糊程度

Panner

image-20230520144758447

  • 用于纹理动画。它可以输出用于创建平移或移动纹理的 UV 坐标
  • SpeedX:在 U 方向上平移坐标的速度
  • SpeedY:在 V 方向上平移坐标的速度
  • Coordinate:UV 纹理坐标
  • Time:用于确定当前平移位置的值

Pixel Depth

  • 以相机为视角,返回场景中离相机最近的一个物体的距离(若最近的为半透明物体,则返回该半透明物体,也就是说不忽略半透明物体
  • 来源:深度缓冲区

Round

  • 将输入值舍入为最接近的整数
  • 若输入值的小数部分为0.5或更大,则将输出值向上舍入;否则将输出值向下舍入
    image-20231128165305162

Step

  • step(y, x),用x与y进行比较,大于y返回1,小于y返回0

SceneDepth

  • 以相机为视角,返回场景中离相机最近的一个物体的距离且忽略透明物体

Sign

虚幻引擎中的数学类材质表达式 | 虚幻引擎5.0文档 (unrealengine.com)

  • 若参数为负数,则输出-1

  • 若参数为0,则输出0

  • 若参数为正数,则输出1

  • 图像

    image-20231128165718494

SphereMask

将SphereMask看作一个球体,该球体分为三个部分,一个是小圈部分,一个是小圈和大圈间过渡的部分,一个是大圈以外的部分

image-20230904155727758

  • A:球心
  • B:目标位置
  • Radius:大圈半径
  • Hardness:用于确定过渡区域

小圈半径 = Hardness * Radius

  • 输出
    • 小圈内输出1
    • 小圈到大圈间输出[0,1]
    • 大圈外输出0

SceneColor

Texture Material Expressions in Unreal Engine | Unreal Engine 5.2 Documentation

  • 该节点输出当前场景的颜色
    image-20230827230550497

ScreenPosition

  • ViewPortUV:输出screen space中正在渲染的像素的uv坐标,范围[0,1]
  • Pixel Position:输出ViewPortUV * View,范围是[0, ViewSize],也就是screen space对应的视口
    image-20231004175622344

SkyAtmosphereLightDirection

  • 接受direction light的light index(需要指定接受哪一个光源),并输出此光的光方向

SmoothStep

  • 作用

    在[0,1]内,实现平滑的过渡。解决step的过度生硬问题

  • 实现

    float SmoothStep(float a, float b, float x)	// a为最小值,b为最大值,x为用于插值的值
    {
        float t = saturate((x - a)/(b - a));
        
        return t*t*(3.0 - (2.0*t));
    }
    
  • 原理

    • t*t*(3.0 - (2.0*t))
      image-20230921225800145
      不难看出,该函数在0和1附近的变换都比较平缓,在0和1中间区域变换相交更快

    • saturate((x - a)/(b - a))

      将此处xab看作某一轴上的三个点,即表示将x限制在ab范围内,若小于a则等于0,若大于b则等于1

VertexColor

  • VertexColor使用来自模型的顶点颜色数据

ViewSize

Coordinates Material Expressions in Unreal Engine | Unreal Engine 5.1 Documentation

  • 输出一个向量,该向量表示当前视口的分辨率大小

Custom Node

注意事项

  • 在#include所需shader文件后,还需写一句"return 1;"
    image-20230906152059224

    这是因为在此处写的代码都会转换为HLSL,也包括return 1。它会被转换为如下形式

    MaterialFloat3 CustomExpression0(FMaterialPixelParameters Parameters)
    {
    	return 1;
    }
    
  • 在编写完最后一个函数时,不要带上"}"

    例如如下函数

        return 1;
    }
    
    float MyGlobalVariable;
    
    int MyGlobalFunction(int x)
    {
        return x;
    

    会转变为

    MaterialFloat3 CustomExpression0(FMaterialPixelParameters Parameters)
    {
        return 1;
    }
    
    float MyGlobalVariable;
    
    int MyGlobalFunction(int x)
    {
        return x;
    }
    

    以上会生成一个全局变量MyGlobalVariable、一个全局函数MyGlobalFunction()

纹理采样

  • 采样方式
    在custom node中对纹理进行采样时,需要输入一个TextureObject的parameter(假设名为tex),此时UE会自动生成一个名为texSampler(末尾跟个"Sampler")

    采样的函数形式如下:Texture2DSample(texName, texNameSampler, uv);

  • 半透明/后处理的采样

    对纹理进行采样时,可以使用以下函数

    float4 SceneTextureLookup(float2 UV, 	//采样的uv坐标
                              int SceneTextureIndex, 	// scenetexture的27个索引坐标
                              bool Filtered)	//是否采用双线性插值.一般为flase
    

    scenetexture的27个索引坐标含义如下
    image-20230906151612186

    示例

    return SceneTextureLookup(GetDefaultSceneTextureUV(Parameters, 8), 8, false);
    

ViewSizeAndInvSize

该语句表示viewport的分辨率

// 假设viewport的分辨率为1920 * 1080,那么xy表示viewport的长宽,zw表示长宽分之1
ViewSizeAndInvSize.xy = float2(1920, 1080);
ViewSizeAndInvSize.zw = float2(1/1920, 1/1080);

使用内置变量

  • 目前看来custom node很有限制,不能使用材质编辑器里提供的变量。其实UE给我们提供了一个可以使用与View相关的内置变量及函数,无需通过Parameter引用

  • 这些变量及函数定义在"/Engine/Source/Runtime/Engine/Public/SceneView.h"中的class FViewUniformShaderParameters
    image-20231016004908911

  • 引用方式:View.xxx("xxx"为变量)

  • 常用变量
    注意:以下带有"Translated"的是UE为了高精度的另一种实现方式

    https://docs.unrealengine.com/4.26/en-US/API/Runtime/Engine/FViewUniformShaderParameters/

    • TranslatedWorldToClip
    • WorldToClip
    • ClipToWorld
    • TranslatedWorldToView
    • ViewToTranslatedWorld
    • TranslatedWorldToCameraView
    • CameraViewToTranslatedWorld
    • ViewToClip
    • ClipToView
    • ClipToTranslatedWorld
    • SVPositionToTranslatedWorld
    • ScreenToWorld
    • ScreenToTranslatedWorld
    • WorldCameraOrigin:get camera position in world space
    • TranslatedWorldCameraOrigin

使用内置函数

  • UE同样提供了一系列内置函数供我们使用,这些函数定义的路径在"\Engine\Shaders\Private\Common.ush";以及一些生成的HLSL代码,这些代码由Parameters提供

  • 引用方法:在函数中引用定义的struct Parameters(存在多个)

    • FMaterialParticleParameters
    • FMaterialVertexParameters(用于vertex shader)
      // 部分定义
      struct FMaterialVertexParameters
      {
          float3 WorldPosition;
          
          half3x3 TangentToWorld;
          
          half4 VertexColor;
      }
      
    • FMaterialPixelParameters(用于pixel shader)
      // 部分定义
      struct FMaterialPixelParameters
      {
          half4 VertexColor;
      
          half3 WorldNormal;
          
          half3 WorldTangent;
      
          half3 ReflectionVector;
      
          half3 CameraVector;
      
          half3 LightVector;
      
          float4 SvPosition;
              
          float4 ScreenPosition;
      
          half UnMirrored;
      
          half TwoSidedSign;
      
          half3x3 TangentToWorld;
          
          float3 AbsoluteWorldPosition;
          
          float2    LightmapUVs;
      }
      
    • FMaterialTessellationParameters(用于domain shader)
  • 一些常用函数
    注意:以下大部分函数都存在多个类型的Parameters的重载。对于"()"内没填参数的并不是笔误,这些函数定义在"Common.ush"

    • Material Attribute

      half3 GetMaterialEmissive(FPixelMaterialInputs PixelMaterialInputs)
      
      half3 GetMaterialBaseColor(FPixelMaterialInputs PixelMaterialInputs)
      
      half GetMaterialMetallic(FPixelMaterialInputs PixelMaterialInputs)
      
      half GetMaterialSpecular(FPixelMaterialInputs PixelMaterialInputs)
      
      half GetMaterialRoughness(FPixelMaterialInputs PixelMaterialInputs)
      
      half GetMaterialAnisotropy(FPixelMaterialInputs PixelMaterialInputs)
      
      half GetMaterialTranslucencyDirectionalLightingIntensity()
      
      half GetMaterialTranslucentShadowDensityScale()
      
      half GetMaterialMask(FPixelMaterialInputs PixelMaterialInputs)
      
      half GetMaterialOpacity(FPixelMaterialInputs PixelMaterialInputs)
      
      float3 GetMaterialWorldPositionOffset(FMaterialVertexParameters Parameters)
      
      half3 GetMaterialWorldDisplacement(FMaterialTessellationParameters Parameters)
      
      half GetMaterialAmbientOcclusion(FPixelMaterialInputs PixelMaterialInputs)
      
      half2 GetMaterialRefraction(FPixelMaterialInputs PixelMaterialInputs)
      
    • Space

      // Returns the upper 3x3 portion of the LocalToWorld matrix
      MaterialFloat3x3 GetLocalToWorld3x3()
      
      // Get position in world space
      float3 GetWorldPosition(FMaterialPixelParameters Parameters)
      
      // Get position in Clip space
      float4 GetScreenPosition(FMaterialPixelParameters Parameters)
      {
          return mul(float4(Parameters.WorldPosition, 1.0f), ResolvedView.TranslatedWorldToClip);
      }
      
      // Get pixel position in screen space
      float2 GetPixelPosition(FMaterialPixelParameters Parameters)
          
      /** Transforms a vector from tangent space to view space */
      MaterialFloat3 TransformTangentVectorToView(FMaterialPixelParameters Parameters, MaterialFloat3 InTangentVector)
      
      /** Transforms a vector from local space to world space (PS version) */
      MaterialFloat3 TransformLocalVectorToWorld(FMaterialPixelParameters Parameters,MaterialFloat3 InLocalVector)
      
      half3 GetMaterialNormal(FMaterialPixelParameters Parameters, FPixelMaterialInputs PixelMaterialInputs)
      
      half3 GetMaterialTangent(FPixelMaterialInputs PixelMaterialInputs)
      
      float3 TransformTangentNormalToWorld(MaterialFloat3x3 TangentToWorld, float3 TangentNormal)
      
      float3 CalculateAnisotropyTangent(FMaterialPixelParameters Parameters, FPixelMaterialInputs PixelMaterialInputs)
      
      //----------------------------------- common.ush--------------------------------------
      float3 SvPositionToWorld(float4 SvPosition)
      
      float4 SvPositionToScreenPosition(float4 SvPosition)
      
      float2 SvPositionToViewportUV(float4 SvPosition)
      
      float2 ViewportUVToScreenPos(float2 ViewportUV)
      
      float2 ScreenPosToViewportUV(float2 ScreenPos)
      
      float3 ScreenToViewPos(float2 ViewportUV, float SceneDepth)
      
      // normal from [0,1] to [-1,1]
      MaterialFloat4 UnpackNormalMap( MaterialFloat4 TextureSample )
      
      MaterialFloat3 TransformTangentVectorToWorld(MaterialFloat3x3 TangentToWorld, MaterialFloat3 InTangentVector)
      
      MaterialFloat3 TransformWorldVectorToTangent(MaterialFloat3x3 TangentToWorld, MaterialFloat3 InWorldVector)
      
      float3 TransformWorldVectorToView(float3 InTangentVector)
      
    • Depth

      float GetPixelDepth(FMaterialPixelParameters Parameters)
      
    • Texture

      float2 GetSceneTextureUV(FMaterialPixelParameters Parameters)
      
      MaterialFloat4 Texture2DSample(Texture2D Tex, SamplerState Sampler, float2 UV)
      
      // uv[0,1] in viewport
      float2 GetViewportUV(FMaterialPixelParameters Parameters)
      
      // from[0,0] to [w, h]
      float2 GetPixelPosition(FMaterialVertexParameters Parameters)
      
      // Returns the view size and texel size in a given scene texture.
      float4 GetSceneTextureViewSize(const uint SceneTextureId)
      
      // 针对于post process有不同处理。但若没有启用,则调用GetSceneTextureUV()
      // Get default scene texture's UV.
      MaterialFloat2 GetDefaultSceneTextureUV(FMaterialPixelParameters Parameters, const uint SceneTextureId)
      
      /** Applies an offset to the scene texture lookup and decodes the HDR linear space color. */
      float4 SceneTextureLookup(float2 UV, int SceneTextureIndex, bool bFiltered)
      
      //----------------------------------- common.ush--------------------------------------
      
      
    • Light

      // Direction light的光方向
      float3 MaterialExpressionAtmosphericLightVector(FMaterialPixelParameters Parameters)
          
      float3 MaterialExpressionAtmosphericLightColor(FMaterialPixelParameters Parameters)
      
      // 光照照度    
      float3 MaterialExpressionSkyAtmosphereLightIlluminance(FMaterialPixelParameters Parameters, float3 WorldPosition, uint LightIndex)
      
      // 日轮亮度
      float3 MaterialExpressionSkyAtmosphereLightDiskLuminance(FMaterialPixelParameters Parameters, uint LightIndex)
          
      // 视图亮度
      float3 MaterialExpressionSkyAtmosphereViewLuminance(FMaterialPixelParameters Parameters)  
      
      // 远距离光散射亮度
      float3 MaterialExpressionSkyAtmosphereDistantLightScatteredLuminance(FMaterialPixelParameters Parameters)
      
      // 空气透视率   
      float4 MaterialExpressionSkyAtmosphereAerialPerspective(FMaterialPixelParameters Parameters, float3 WorldPosition)
      
      //----------------------------------- common.ush--------------------------------------
      MaterialFloat Luminance( MaterialFloat3 LinearColor )
      
      // compute the pow() in the specular
      MaterialFloat PhongShadingPow(MaterialFloat X, MaterialFloat Y)
      
    • Fog

      float4 MaterialExpressionAtmosphericFog(FMaterialPixelParameters Parameters, float3 AbsoluteWorldPosition)
      
    • Util

      // Material Expression function
      float MaterialExpressionDepthOfFieldFunction(float SceneDepth, int FunctionValueIndex)
          
      /** Rotates Position about the given axis by the given angle, in radians, and returns the offset to Position. */
      float3 RotateAboutAxis(float4 NormalizedRotationAxisAndAngle, float3 PositionOnAxis, float3 Position)
          
      /** Calculate a reflection vector about the specified world space normal. Optionally normalize this normal **/
      MaterialFloat3 ReflectionAboutCustomWorldNormal(FMaterialPixelParameters Parameters, MaterialFloat3 WorldNormal, bool bNormalizeInputNormal)
          
      MaterialFloat2 GetLightmapUVs(FMaterialPixelParameters Parameters)
      
      //----------------------------------- common.ush--------------------------------------
      MaterialFloat length2(MaterialFloat2 v)	// 存在float3,float4
      
      uint Mod(uint a, uint b)	// 存在uint2,uint3
      
      // 存在float2, float3, float4
      float DDX(float Input)
      float DDY(float Input)
      
      float Square( float x )		// 存在float2, float3, float4
      // POW2-6
      float Pow2( float x )	// 存在float2, float3, float4
      
      
      

Substrate

  • What
    • Substrate是UE一个新的材质编辑系统,摒弃原来的PBR材质系统,替换为效果更好、更为模块化的框架——使用有度量的物质属性
    • 所用技术是BSDF。BSDF = BRDF + BTDF,BRDF表示的是光线在物体表面的反射,BTDF表示的是光线在物体内部的散射、吸收、透光、厚度等
      image-20231002152339314
  • Why
    • 以前无法解决分层材质(混合A,B材质)带来的巨大消耗,且不稳定,当涂层越多,带来的问题也会增多。而Substrate简化材质分层过程,可以更轻松地表示诸如金属上有液体或次表面散射上有透明涂层之类的表面
    • 可以更准确地呈现混合金属、玻璃、塑料等复杂的材质表面
  • How
    • 启用Substrate:打开Project Settings->搜索"Substrate material(Experimental)"->启用->重启
      不过需要注意,当启用了Substrate,旧版的材质系统将会被替换为Substrate,且无法恢复,因此注意进行项目备份
      image-20230925155605015
  • Material Root
    image-20230925154354915
    • 与旧版PBR的Material Root类似,Substrate Material Root使Substrate Slab和其他Substrate node被送入的地方
    • 在该节点下也可以定义Blend Mode
      image-20230925154507320

Substrate Slab BSDF

  • what & why
    仔细观察生活中的物体可以发现,大多数物体并不是单一物质,而是通过多层材质的叠加而来的。Slab也正是这个思想,Slab将物体分为两个部分,如下图所示1为表面,主要计算光的反射,2为内层,主要计算光的吸收和散射。旧版的PBR材质系统仅仅将物体看作一层,生成材质,并将材质赋予物体表面就没了
    image-20230925155535956

  • 优点

    • 旧版的PBR材质系统依赖blend mode表示可以使用的输入。而Substrate使用不同BSDF Slab来定义材质类型,由于这些材质不再直接绑定到blend mode,因此可以层层叠加和混合
  • 定义
    image-20230925160150820

    • Diffuse Albdo:光线在物体表面或内部发生散射的颜色

    • 表面:光线与材质表面交互的边界

      主要属性:roughness、normal、DiffusedAlbedo、F0、F90

    • 内层:控制光线的散射、吸收、透光,内层厚度(单位cm)

      主要属性:MFP(Mean Free Path)

    • F0&F90:以camera vector与物体表面的normal vector的角度差为0入射的Fresnel效果(F90就是角度差为90,一般值为1)的高光的颜色和亮度
      image-20230925161329035
      image-20230925161348286

      • 为什么需要F0?

        • 主要是为了表现金属和非金属,金属在F0下会表现出固有的高光颜色,大多数非金属的F0范围是0.02~0.04,大多数金属的F0范围是0.7~1.0。可以简单的理解为当光照射到金属表面时,金属内的共有电子会吸收特定波长的光波而显现出固有的颜色
        • 非金属的F0为float,金属的F0为float3
        • 代替金属度,来控制金属感
      • 为什么分为F90和F0?

        • 虽然一般情况下,F90表示Fresnel效果最强(也就是1),但并非所有物质的效果都是如此

          如下图所示,将F0设定为金色,F90设定为红色,效果正是外圈为红色,内圈为金色
          image-20230925165835799

    • SSS MFP

      • MFP控制材质的“密度”,在体积上控制材质深层对光源的吸收和散射——定义光子与物质粒子相互作用的平均距离(基于像素),该距离由每个RGB通道控制

      • 可以简单理解,MFP的值控制RGB各波长对内层的渗透长度(单位米)(但严格意义上,MFP控制长,中,短波长穿透物体时的持久性),这意味着base color的值不会影响MFP渗透产生的颜色

        例如下图我将MFP的R设置为1,GB都设为0,说明红色会完全透光该材质及物体,从而造成如下现象——虽然球的Base Color是灰色的,但光穿过球入射进相机(并非通过球看到后面的物体呈红色)。其中蓝绿色是因为GB为0无法渗透发生散射
        image-20230929225023655

        当把这些都设为1,会发现球没有颜色,这说明所有光并没有在物体表面和内部发生散射,都穿过了物体
        image-20230929230418635

      • Albedo 和 MFP常用值
        image-20230929233821152

    • SSS MFP Scale

      • 控制MFP的效果,范围在[0,1]
    • SSS Phase Anisotropy

      • 该值范围在[-1,1]。若为0则将光均匀地散射到各个方向;若为正值则沿光线方向延长相位函数,导致前向散射;若为负值则沿光线方向的反方向延长函数,导致后向散射(可以理解为物体的透光性)
    • Second Roughness & Second Roughness Weight

      • 简单来说,Roughness控制打在物体上中心的高光效果(需要注意Rougheness会影响透光性),而Second Roughness控制由中心到周围的衰减效果
      • 最终的Roughness = Roughness * (1 - t) + Second Roughness * t

Substrate BSDF

BSDF (双向散射分布函数)节点有多个,分别控制所对应材质的视觉效果,并自动设置对应的着色模型
image-20230925220726720

  • Substrate Simple Clear Coat:简单又快速地渲染顶部有透明涂层的材质。简化透明涂层的渲染工作流程,用于渲染旧版透明涂层材质
  • Substrate SingleLayerWater BSDF:渲染系统的单层水材质
  • Substrate Unlit BSDF:将旧版灰阶不透明度替换为彩色透射
    • 如果需要混合无光照Slab,需要使用只有自发光颜色输入的常规Substrate Slab

运算符节点

Substrate运算符节点用于混合或叠加多个Substrate Slab——可以通过将几块Slab一起混合和层层叠加来形成复杂的材质外观
image-20230925222007514

  • Substrate运算符并不适用于所有SubstrateBSDF。只有 Substrate Slab BSDFSubstrate Simple Clear Coat 可以使用这些运算符节点
  • 在运行时执行此操作的开销可能很高,主要原因在于光照求值
  • 优化:在运算符节点设置"Use Parameter Blending",可将其背景和前景混合到单个材质
  • Substrate Horizontal Layer:将两个Slab blend如下图所示进行水平方向的blend
    image-20230925224752083
  • Substrate Vertical Layer:将两个Slab blend如下图所示进行垂直方向的blend
    image-20230925224900451

Substrate Transmittance-To-MeanFreePath

  • 可以理解为MFP不再是控制光波的渗透程度,而是用指定颜色值来表现对应出的颜色(透光的颜色根据Substrate Transmittance-To-MeanFreePath上输入的颜色进行)
    如下图所示,MFP表现的是粉色,而发生散射的是互补色绿色

    image-20230929233027805

Haziness

  • 定义:影响物体的反射效果,Haziness(浑浊度)越高,物体反射效果越明显

  • Substrate Haziness to secondary roughness

    substrate提高了一个节点,提供第一Roughness和haziness可以计算出second roughness和权重比
    image-20230929013216987

Reroute Node

https://docs.unrealengine.com/5.0/zh-CN/organizing-a-material-graph-in-unreal-engine/#

  • 什么是 Reroute Node

    当编写的材质稍微有些复杂时,大部分情况下连线都会十分繁杂,不好区分。针对这一情况UE引入了Reroute Node,它的作用相当于material function,先实现某个你想要的功能节点,随后便可以像使用material function一样,将Reroute Node作为输入

  • 如何实现Reroute Node

    Reroute Node目前有两种常用的使用方法

    1. 直接声明Reroute Node

      • 在材质编辑器内搜索并点击”Add Named Reroute Declaration Node”,会生成一个未命名的Reroute Node,你可以在左侧节点属性详细页对Reroute Node的名称和颜色进行修改
        image-20231003171853570
        image-20231003171959041

      • 像写material function一样编写Reroute Node

        如下,右侧的”POM UV”是笔者实现的Reroute Node
        image-20231003172121482

      • 使用方式与material function类似

        如下,”POM UV”是笔者实现的Reroute Node
        image-20231003172224815

    2. 由路由引脚创建Reroute Node

      • 例如下图,现在有一个float4节点作为slab BSDF的Diffuse Albedo的输入节点,且它们之间有一个路由引脚(图中橘色部分)
        image-20231003172450182

      • 鼠标右键路由引脚并点击”Convert to Named Reroute”,会生成两个未命名的Reroute Node
        image-20231003172626974
        image-20231003172712489

      • 现在左边的”Crack Albedo”无需与Diffuse Albedo进行连接,它甚至可以放在任何地方,虽然看起来没有连接,但他们是紧紧相连的,改变”Crack Albedo”也会影响Diffuse

reference

Math Material Expressions in Unreal Engine | Unreal Engine 5.1 Documentation

Constant Material Expressions in Unreal Engine | Unreal Engine 5.1 Documentation

Fading Workflows - VFXDoc

在虚幻引擎中使用纹理遮罩 | 虚幻引擎5.2文档 (unrealengine.com)

Coordinates Material Expressions in Unreal Engine | Unreal Engine 5.1 Documentation

UE4 后期处理 - c_dragon - 博客园 (cnblogs.com)

https://zhuanlan.zhihu.com/p/101503016

https://zhuanlan.zhihu.com/p/87762783

https://zhuanlan.zhihu.com/p/159374325

https://zhuanlan.zhihu.com/p/649865667

https://zhuanlan.zhihu.com/p/649882367

https://zhuanlan.zhihu.com/p/56967462

https://docs.unrealengine.com/5.3/zh-CN/overview-of-substrate-materials-in-unreal-engine/

https://rmanwiki.pixar.com/display/REN22/Subsurface+Scattering+Parameters

https://mp.weixin.qq.com/s/tXPN9GYPepJsU0aLznw3mg

https://zhuanlan.zhihu.com/p/66288908

https://zhuanlan.zhihu.com/p/444036214

https://zhuanlan.zhihu.com/p/367754430

https://docs.unrealengine.com/4.27/zh-CN/Basics/Actors/CoordinateSpace/

https://ikrima.dev/ue4guide/graphics-development/render-architecture/shader-common-params/

[UE4]动态液体材质浅谈 - 知乎 (zhihu.com)

posted @ 2023-05-21 17:41  爱莉希雅  阅读(2827)  评论(0编辑  收藏  举报