hardware pipeline 的大阶段顺序不是 PSO 决定的,而是由 GPU graphics pipeline 类型本身决定的;PSO 决定的是这次 draw 在这条既定阶段链上,各阶段用什么程序、什么状态、哪些阶段启用。

也就是说,像:

IA -> VS -> HS/DS -> GS -> Raster -> PS -> OM

这条“骨架顺序”本身不是 PSO 发明出来的。
它是 graphics pipeline 的结构。
PSO 做的是给这条结构填具体配置。

例如:

  • VS 用哪个 shader bytecode

  • 有没有 HS/DS

  • 有没有 GS

  • Rasterizer state 是什么

  • DepthStencil state 是什么

  • Blend state 是什么

  • Primitive topology 类型是什么

  • Render target format / depth format 是什么

所以 PSO 更像:

对一次图元批处理的完整图形执行契约

更准确应该说:

PSO 包含 shader 编译产物,但 PSO 本身不是 HLSL 直接编译结果。

因为 HLSL 编译出来的首先是 shader bytecode / DXIL 之类的阶段程序。
而 PSO 是在 API 层把这些 shader bytecode 和固定功能状态一起封装成的对象。

拿 DX12 的语义说更清楚:

HLSL 编译产物通常是:

  • VS bytecode

  • PS bytecode

  • 可能还有 HS/DS/GS/CS/MS/AS bytecode

然后创建 PSO 时,再把这些东西连同:

  • BlendState

  • RasterizerState

  • DepthStencilState

  • SampleMask

  • RTV/DSV formats

  • Primitive topology type

  • Root Signature
    一起提交给驱动,形成 ID3D12PipelineState

所以关系更像是:

HLSL -> shader bytecode
然后
shader bytecode + fixed-function states + layout contract -> PSO

不是:

HLSL -> PSO

这点很重要,因为它解释了为什么同一份 shader bytecode 可能对应多个 PSO。
例如同一个 VS/PS,如果你改:

  • blend state

  • depth state

  • render target format

  • rasterizer state

那通常就是不同 PSO 了,即使 shader 代码根本没变。

Epic 在把材质系统从“少数几个固定模式的经验型开关”,重构成“更接近真实光学行为、也更利于渲染路径优化的声明式系统”。UE 5.7 里,Substrate 已经是 production-ready,并且默认启用;官方明确把它描述为用更模块化、物理基础更强的框架,去替代过去那套固定 shading model / blend mode 组合。名字变长、变细,正说明设计目标已经从“给美术一个大概能用的几档选项”,转成“明确告诉渲染器:这个材质到底是在做覆盖、遮罩、加法、预乘合成,还是在做灰度透射、彩色透射”。UE 5.7 官方文档对 Blend Mode 的定义仍然是“当前材质如何和背景像素混合”,但 Substrate 文档同时强调它要表达更真实的 BSDF / 层叠 / 透射行为,而不是只靠过去那种粗粒度枚举。

底层架构的根本性变革

  • 核心变化:对 GBuffer (几何缓冲区) 的完全重新配置
  • 传统延迟渲染:使用固定的 GBuffer 布局,每个通道(RT)存储特定的信息(如 BaseColor、Normal、Roughness 等)。
  • Substrate 的方法:抛弃了固定布局,转而将材质属性打包存储在紧凑的 GPU 缓冲区 (Packed GPU Buffers) 中。这是一种更灵活、更具扩展性的数据结构,为复杂的材质分层提供了基础。

自适应 GBuffer (Adaptive GBuffer)

  • 目标平台: 设计为 Shader Model 6 (SM6) 平台(如 PC SM6、PS5、Xbox Series)的新默认模式。
  • 实现方式: 使用一组 位打包的 UAV (Bitpacked Unordered Access Views) 来逐像素编码 Substrate 数据。
  • 功能:
    • 解锁 Substrate 的所有高级功能,包括闭包混合 (closure blending)逐像素材质拓扑 (per-pixel material topology)
    • 提供了系统的全部灵活性和表现力。
  • 注意事项:
    • 由于数据是打包存储的,不支持硬件混合
    • 这一限制导致 DBuffer Decals 成为使用自适应 GBuffer 时唯一可用的贴花方法。
引入 Substrate(原名 Strada)材质系统主要是为了

打破传统固定着色模型(Shading Models)的限制,实现更真实、更灵活、可分层的材质渲染 。模块化的方式组合不同的材质层(Slabs),不再局限于原有的“漫反射+高光+粗糙度”单层模式。

Substrate 材质系统之所以能打破传统的“漫反射+高光+粗糙度”单层固定模式,是因为它从根本上

改变了材质的描述方式 ,从“硬编码的着色模型”转变为“基于Slab(薄片)的参数化堆叠系统” 。传统材质(Default Lit)是一个预定义的、单一的BRDF(双向反射分布函数)。而 Substrate 引入了 Slab(薄片) 的概念,材质不再是一个扁平的结构,而是像堆汉堡一样,允许将多个 Slab 节点组合、层叠(Layer)或混合(Mix)在一起。完美处理多层材质之间光的透射、吸收和散射。通过使用垂直堆叠(Vertical Layering),系统会自动计算第一层表面对第二层表面的遮挡和混合。这意味着可以轻松制作出珍珠、泡沫、清漆木材等具有复杂光线流转的材质。采用了“基于物理的组件化(Modular)策略” 。这让艺术家可以用更简单、更符合物理直觉的层级节点来描述极其复杂的真实材质,而不再被传统引擎的单个高光+漫反射模型所束缚 。传统材质系统区分不透明材质和透明材质(Translucent)。Substrate 将不透明和透明材质统一在同一个结构中,使得制作如“次表面散射的清漆金属”等跨模式材质成为可能。Substrate 允许用户通过节点图(Material Graph)将多个不同的材质描述按层堆叠。这与传统材质最大的不同在于,复杂材质不再是一个固定的着色模型 ,而是由多个基础层混合而成的复杂结构。节点式混合: 用户可以利用 Substrate Slab 节点和运算符节点(如 VerticalLayer HorizontalBlend )层层混合。例如,一个汽车漆材质可以是:一层透明清漆(Clear Coat) + 一层金属基底(Metal Base) + 一层汽车漆底色(Car Paint Base)。

stained glass 需要的是“彩色透射”,不是简单 alpha 混合;而普通半透明 UI 更接近 compositing 语义。Colored Translucent Shadows / transmittance 相关文档,说明他们是在把“透过去的光是什么颜色、如何投影”单独建模。材质语义更稳定地映射到底层渲染路径。Blend mode 不是纯 UI 选项,它直接决定哪些 material input 生效、走哪些 pass、能否参与某些光照/阴影路径。AlphaComposite、AlphaHoldout、不同 transmittance 形式拆开,本质是在减少歧义,让引擎知道你究竟要哪种数学混合和哪种光学行为。兼容历史,同时逐步迁移。你搜到的 API 页面里其实还能看到一些隐藏别名,例如 BLEND_TranslucentGreyTransmittance = BLEND_TranslucentBLEND_ColoredTransmittanceOnly = BLEND_Modulate 这样的映射痕迹。这说明 Epic 没有完全推翻旧 enum,而是在保留底层兼容的同时,把编辑器和 Substrate 语义往新模型上迁移。所以你会感觉“菜单长得不一样、术语也更学术”,但底层有一部分仍是对旧模式的语义重包装。

旧方案的问题是:
一个选项名字短,但语义过载;
美术靠经验试错,不知道自己选的是“混合方式”还是“透光模型”;
渲染后端很难根据一个含糊的 Translucent 推断最优路径。新方案的问题则相反:学习成本更高,但语义清楚,长期更适合 Substrate 这种 BSDF/层系统。UE 不再把材质面板当“效果快捷菜单”,而是当“渲染意图声明接口”。这很像从老式 fixed-function 风格 UI,转向更接近 render graph / explicit pipeline state 的思想。

Blend Mode 不只是“怎么混颜色”,而是一个高层语义标签,同时在声明三件事:

  1. 像素级混合算子(compositing operator)

  2. 光是否穿透(transmittance vs coverage)

  3. 是否参与光照/阴影/能量守恒路径

也就是说,它已经从“屏幕空间混合公式选择器”,变成“光学+管线行为的联合描述”。

  • Coverage(覆盖)
    → 物体要么挡住光,要么不挡(binary or masked)
    → 典型:Opaque / Masked
    → 对应 几何可见性(visibility)问题

  • Transmittance(透射)
    → 光穿过物体,被吸收/染色
    → 典型:TranslucentGrey / ColoredTransmittance
    → 对应 参与介质(participating media)问题

混合公式背后的物理含义:

  • Additive
    → 能量只增加(emissive-like)
    → 不守恒(典型 VFX)

  • AlphaComposite(Premultiplied)
    → 标准 Porter-Duff compositing
    → 假设 alpha = coverage

  • Transmittance
    → Beer–Lambert 类模型(近似)
    → alpha ≈ 吸收系数

这一步的本质是:

从“图像合成公式” → “光能如何流动”

不同模式会决定:

  • 是否写 GBuffer

  • 是否参与 deferred lighting

  • 是否有 shadow / GI / reflection

例如:

  • Opaque → 完整参与

  • Translucent → 单独 forward path / lighting approximation

  • Transmittance → 可能影响 shadow color(colored shadow)

Substrate 的目标是:

BSDF + layer + transmission 的组合系统

如果 blend mode 语义不清:

  • 无法正确组合 BSDF

  • 无法优化 shader permutation

  • 无法做 render graph 级别裁剪

blend mode ue5.7这套分类其实对应三个经典理论来源:


1. 渲染方程拆解(Kajiya)

把表面行为拆成:

  • 反射(BRDF)

  • 透射(BTDF)

  • 吸收(extinction)

现在 UE 的做法是:

Blend Mode 负责告诉你:有没有 BTDF / extinction

2. Beer–Lambert Law(透射)

Transmittance 类模式,本质在表达:

T=e−σdT = e^{-\sigma d}T=e−σd

UE 没完全物理,但语义已经对齐:

  • GreyTransmittance → scalar absorption

  • ColoredTransmittance → wavelength dependent

3. Porter–Duff Compositing

AlphaComposite / Holdout 属于:

  • 图像合成规则(coverage domain)

  • 与物理光传输无关

UE 现在是明确区分:

“这是 compositing 语义,不是光学语义”

现在的 Blend Mode 可以这样理解:

它定义的是:这个材质在 可见性(coverage) / 光传输(transmittance) / 合成规则(compositing) / 光照参与方式 四个维度上的组合状态。

UE 的视口默认渲染路径对材质做了多层光照/后处理叠加。你只贴了 BaseColor,但 viewport 里走的是完整 shading pipeline。

GBuffer(BaseColor, Normal, Roughness, etc.)

Light Accumulation(方向光 / 环境光 / Skylight / IBL)

Shading = Diffuse + Specular

即:


FinalColor ≠ BaseColor
FinalColor = BaseColor * Lighting + Specular + Indirect

你现在看到“灰掉”的原因主要是:

  • Skylight / HDRI 参与了 diffuse

  • 默认 tone 偏低(ACES)

  • 没有 unlit → 被物理光照压暗

不知道该效果属于哪个成本域
你至少得知道它主要吃的是:

  • CPU 提交

  • GPU ALU

  • GPU 带宽

  • 显存

  • overdraw

  • 阴影缓存

  • 屏幕分辨率

  • 几何复杂度

  • 动态物体数量

不知道它的放大因子
也就是它随什么增长:

  • 分辨率增长

  • 灯数量增长

  • 屏幕覆盖率增长

  • 三角形/cluster 增长

  • 透明层数增长

  • 骨骼数量增长

  • 视距增长

  • 哪个阶段执行?
    是 BasePass、ShadowPass、Lighting、PostProcess、Translucency,还是独立 compute?

  • 它主要吃什么?
    ALU、纹理采样、带宽、RT 读写、深度复杂度、CPU draw/setup?

  • 随什么放大?
    分辨率、灯数、屏幕覆盖、几何复杂度、材质指令数、骨骼数?

  • 不开它,有什么便宜替代?
    烘焙、贴图假效果、局部体积、半分辨率、材质近似、风格化简化?

  • 个问题答不上来,就不该默认大范围上生产内容。

    核心变化(本质)

    从:

    
    
    BaseColor → GBuffer → Lighting → Shadow → AO → ToneMapping → PostProcess

    变成:

    
    
    Material(Emissive/BaseColor) → 直接输出 → ToneMapping → PostProcess

    关键点:

    • ❌ 没有 GBuffer(不参与 deferred)

    • ❌ 没有任何光照(无 direct / indirect)

    • ❌ 没有 shadow / AO / SSR / Lumen

    • ✅ 仍然是 HDR → LDR 的显示链

    左边(黑背景角色)

    • 主关卡 viewport

    • 你关掉了部分 PostProcessing(比如 EyeAdaptation)

    👉 所以画面是:

    • 没曝光

    • 没 bloom / DOF

    • 更接近“裸输出”

    默认状态:引擎内置后处理 
    即使你不添加任何组件,UE 也会应用一套 默认的后处理设置 。这些设置定义在引擎的配置文件中,包括基本的曝光控制、色调映射(Tonemapper)和运动模糊等。 
    • 局限性 :这些默认值无法在编辑器窗口中直接调整,且往往不符合特定项目的美术风格。
    • 特征 :如果不加组件,你可能会发现画面有自动曝光(眼睛适应感)或特定的饱和度,这是因为内置的默认配置正在生效。
    核心组件:Post Process Volume(后处理体积) 
    想要手动控制和定制后处理效果,最标准的方法是添加 Post Process Volume 资产。 
    • 局部覆盖 :默认情况下,该组件仅影响相机进入其立方体范围内时的画面。
    • 全局覆盖 :在组件的“细节”面板中搜索并勾选 Infinite Extent (Unbound) ,它就会覆盖整个关卡,无论相机在何处。
    • 优先级 :你可以添加多个体积,通过调整 Priority (优先级)属性来控制不同区域的效果切换。
    自动曝光 (Auto Exposure / Eye Adaptation) 
    这是最明显的默认效果。当你从暗处看向亮处,或者场景光照剧烈变化时,画面会像人眼或摄像机一样自动调整亮度。 
    • 现象: 关卡里明明没放 Post Process Volume,但画面总是忽亮忽暗。
    • 原因: UE 默认开启了基于直方图的自动曝光。  
    色调映射 (Tone Mapper) 
    UE 使用电影级的 ACES 标准 色调映射。 
    • 现象: 即使是简单的纯色材质,在光照下也会呈现出非常柔和、写实的色彩过渡,而不是生硬的色块。
    • 作用: 确保高光部分(如太阳)不会直接变成一片纯白死区,而是有层次地向白色过渡。  
    颜色校正 (Color Correction) 
    默认会有微弱的对比度和饱和度调整,以确保渲染出的线性空间颜色(Linear Color)在你的显示器上看起来是“正常”的。
    如何“关掉”或修改这些默认行为? 
    如果你觉得这些默认效果干扰了你的设计(比如你想要一个纯二维的不带光影变化的画面),你需要: 
    1. 在场景中放入一个 Post Process Volume
    2. 勾选 Infinite Extent (Unbound) 使其全局生效。
    3. 覆盖默认值:
      • 关掉自动曝光: 找到 Lens -> Exposure -> Metering Mode 改为 Manual (手动),或者将 Min Brightness Max Brightness 设为相同的值(如 1.0)。
      • 调整饱和度: 找到 Color Grading -> Global -> Saturation 进行覆盖。
    简单来说: 引擎自带的默认值是为了保证“下限”,让你随手拉个模型进去看起来都不至于太糟糕;而添加 Post Process Volume 是为了提高“上限”,实现你真正想要的美术风格。 

实时预览设置 (Live Update 菜单)  
这个菜单控制的是材质编辑器里那些“小格子”(节点预览图)什么时候刷新:  
  • Preview Material :只实时刷新最终的材质预览球。
  • Realtime Nodes :实时刷新受时间影响的节点(如 Panner 这种会动的节点)。
  • All Node Previews(最广) 只要你改动任何参数或连线,所有节点的预览小图都会立即重新计算并显示结果。
    • 缺点 :如果材质极其复杂,开启这个会非常吃显卡性能,导致连线时卡顿。

如果你想改完立刻看到效果(不卡顿):
建议使用 Material Instance(材质实例) 。在实例里拖动数值或切换贴图,场景是完全实时 变化的,不需要点 Apply,也不需要等编译。

  • 发现 Scatter(散射) Backlit(背光) 等特有插槽被激活(变亮)了。
  • 置灰不可用 :如果你切换回默认的 Default Lit ,这些 Hair 特有的插槽就会变灰,无法连接。反之,Hair 模式下某些原本可用的插槽(如 Metallic)在某些特定模型下也会失效或改变含义。
  • 特定属性出现 :例如,只有在 Shading Model 设置为 Thin Translucent 时,才会出现“Transmission”(透射)相关的设置。
  • 底层算法切换 :不同的模型会开启或关闭底下的 Usage(用法) 勾选项。比如有些模型会自动勾选“Used with Hair Strands”。  

Shading Model = Hair,它会强制切换到一套专用的光照路径(Hair BSDF),这条路径和常规的 Translucency(半透明)是互斥的。

本质原因(渲染管线层面)

Hair Shading Model 走的是:

  • 专用的 Hair Lighting Model(Marschner / Dual Scattering 近似)

  • Forward-like lighting(即使在 Deferred Renderer 中)

  • 使用:

    • Tangent(发丝方向)

    • Scatter(透射近似)

    • Backlit

    • Anisotropy

Translucency 走的是:

  • Separate Translucency Pass / After DOF Pass

  • 非物理的透射(基于 opacity + lighting mode)

👉 这两套路径在 UE 里是完全不同的 shader permutation

所以引擎直接做了限制:

Hair → 禁用 Translucency 面板

幻引擎(Unreal Engine, UE)中,

Dither (抖动/交错)是一种材质技术和渲染技巧,用于通过交错分布的不透明像素来模拟半透明效果 。它通常与时间性抗锯齿(Temporal Anti-Aliasing, TAA 或 TSR)结合使用,通过这种方式,原本不透明的物体可以表现出类似透明的视觉效果,且性能消耗较低

Dither 的核心作用与原理  
  • 模拟半透明 :传统的透明材质(Translucent)非常消耗性能,尤其是在叠加层次很多时。Dither技术通过在材质的Masked(掩码)模式下,使用“抖动”模式,让像素点随机或按规律地出现和消失。
  • 利用TAA抗锯齿 :UE的TAA技术会比较前后两帧的像素。当Dither产生的像素每帧都在变化时,TAA会将这些点“混合”起来,使人眼看起来该物体就是半透明的。
  • 材质节点 :在UE材质编辑器中,最常用的节点是 DitherTemporalAA  
材质蓝图中,你可以找到以下相关的节点:  
  • DitherTemporalAA :最常用的节点,通常连接到“遮罩裁剪值(Opacity Mask)”,用于实现柔和的裁剪效果。

Blue Noise(蓝噪声) :UE5 中更推崇的一种噪声类型,因为它比传统的白噪声分布更均匀,视觉上的噪点感更低。

https://www.ntiaudio.cn/客户支持/拓展/五彩斑斓的噪声/

噪声在我们的生活中随处可“见”,从物理角度上看,噪声是那些频率、强弱无规律变化,或者说杂乱无章的声音。而从心理学 上说,任何让人感觉烦躁的声音都可以归类为噪声。噪声”是英文 noise 的标准翻译,“噪音”为不规范用法,因为“声”是物理学 术语,指能够引起听觉的机械波 ,而“音”是人文领域的用法,指有规律的乐音,故不能将两者混淆。

Hair 使用:

  • 多 lobes specular(R / TT / TRT)

  • 内部散射(沿发丝方向)

Translucency 使用:

  • Volumetric / Surface Lighting(简化)

👉 无法共存同一 BRDF

无法共存同一 BRDFDither Temporal AA:软边

Hair 会触发:


bUsesHairStrands = true

然后:

  • 禁用 Translucency permutations

  • 强制走 Hair lighting pipeline

  • 每个 Lobe 描述了一个光斑在角度空间中的分布。
  • R 波瓣最尖锐(主高光)。
  • TRT 波瓣较宽,通常在不同于主高光的方向。
  • 这种“多波瓣”设计能够精准模拟真实世界中,一根发丝上呈现主次两个高光斑、且呈现透射光和染色光的效果。
  • Marschner 模型: 由 Steve Marschner 等人提出,是现代毛发渲染的基石。
  • 游戏渲染: 在《虚幻引擎》(Unreal Engine)中的 Human Hair Shading 模型中应用了类似的原理,通过多层Specular分量来描绘写实皮肤和头发。
  • 真实感: 该模型考虑了鳞片引起的位移(R与TRT角分布的不同)和纤维内部的吸收,从而实现了高质量的写实角色制作。
  • 实时渲染中的“每像素每帧采样数(spatial samples per frame)”,而不是最终收敛质量对应的总采样数。

    单帧内的空间采样数(spatial samples)

    比如:

    • TAA / Dither TAA / stochastic sampling

    • DOF / motion blur / shadow PCF / SSGI 等

    这里的“8~15个采样”指的是:

    一个像素在当前帧内做了多少次随机/抖动采样

    而不是最终效果的“等效采样”。

    实际依赖的是 时间累积(temporal accumulation)

    TAA 类方法的本质是:

    C f i n a l = ∑ t = 0 N w t ⋅ C t C_{final} = \sum_{t=0}^{N} w_t \cdot C_t Cfinal=t=0NwtCt

    也就是说:

    • 每帧只做很少的 sample(例如 1~8)

    • 通过历史帧不断累积(几十甚至上百帧)

    👉 等效结果:

    • 单帧:8 samples

    • 30帧累计:≈ 240 samples(但带有temporal correlation)

    这就是为什么:

    实时渲染里“单帧采样很少”,但最终看起来像高采样

    为什么 PC 也只有 8~15?

    这是纯粹的 带宽 + ALU + latency budget 限制

    即便在高端 PC:

    • 一个 full-screen pass:

      • 4K 分辨率 ≈ 8.3M pixels

    • 如果每像素 30 samples:

      • 就是 2.5亿次采样(还不算 shading cost)

    这会直接:

    • 爆 L1/L2 cache

    • 增加 texture fetch latency

    • register pressure(尤其在 wave64 / SIMT 下)

    所以现实工程里:

    • SSR / SSGI:通常 1~8 samples

    • PCF shadow:4~16 taps(已经算重)

    • DOF stochastic:4~8

    移动端为什么 <6

    移动 GPU(tile-based + bandwidth constrained):

    • texture fetch 成本更高(尤其是 external memory)

    • ALU 也更紧(尤其是中低端 Mali / Adreno)

    所以:

    • 常见是 1~4 samples

    • 甚至完全依赖 temporal + reprojection

  • Lumen GI:

    • 单帧 trace 数非常少(甚至 1~2)

    • 靠 temporal + screen space reuse

  • TSR / DLSS:

    • 本质也是 temporal accumulation + reconstruction

“8~15采样”不是最终质量采样数,而是:

实时渲染中单帧可承受的空间采样预算,上限由带宽/延迟决定,最终质量依赖 temporal accumulation。

wave/warp 切换去隐藏部分 latency

每多一个 sample,就多一串读请求。GPU 虽然能靠 wave/warp 切换去隐藏部分 latency,但隐藏能力不是无限的。只要:

  • 访存太散

  • cache hit 低

  • register pressure 高导致 occupancy 降低

那 latency 就开始暴露成真实耗时。

cache miss 带来的层级存储访问延迟
采样不是只有“次数”问题,还有 空间局部性 问题。

比如径向模糊:

  • 采样点沿半径发散

  • 很容易跨 cache line

  • 命中 L1/L2 的概率下降

于是会发生:

  • 近邻 sample 还好

  • 半径一大,很多 sample 直接掉到更低层 cache,甚至外存

这时单次 sample 成本就明显上升。
所以“30+ 采样才够好”在算法上可能成立,但在硬件上会被 cache behavior 打爆。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐