GBuffer LayoutGBuffer 布局

NeoX's deferred path uses a compact 3-RT GBuffer for the standard mode, or a 5-RT Single-Pass Deferred for mobile (TBDR) optimization. In the new engine the GBuffer layout changed: Roughness moved from RT1 to RT2, and the RT names were updated. A new shared gbuffer_struct.hlsl header is now used across all GBuffer passes.

NeoX 的延迟路径标准模式使用紧凑的 3-RT GBuffer,或为移动端(TBDR)优化使用 5-RT 单 Pass 延迟。新引擎 GBuffer 布局有变化:Roughness 从 RT1 移到 RT2,RT 名称也已更新。新引擎所有 GBuffer Pass 现在使用共享的 gbuffer_struct.hlsl 头文件。

Standard Mode (3 Render Targets) — NEW ENGINE: +=================================================================+ | | | SV_Target0: AlbedoAO | | +----------+----------+----------+----------+ | | | R: Alb.R| G: Alb.G| B: Alb.B| A: AO | RGBA8/16 | | +----------+----------+----------+----------+ | | | | SV_Target1: Normal (renamed from NormalRoughness) | | +----------+----------+----------+----------+ | | | R: N.x* | G: N.y* | B: N.z* | A: (free)| * = 0.5(n+1) | | +----------+----------+----------+----------+ | | NOTE: Roughness moved OUT of this RT | | | | SV_Target2: MetallicRoughnessShadingModelFlags (renamed) | | +----------+----------+----------+----------+ | | |R: Metalic| G: Rough. | B: (free)| A: Flags | Flags=byte | | +----------+----------+----------+----------+ | | NOTE: Roughness moved HERE; Flags moved to alpha channel | | | +=================================================================+ Single-Pass Deferred Mode (5 Render Targets -- Mobile TBDR): +=================================================================+ | SV_Target0: FinalResult // direct emissive output | | SV_Target1: Depth // manual depth (for GLSL) | | SV_Target2: AlbedoAO // same as standard RT0 | | SV_Target3: Normal // same as standard RT1 (new) | | SV_Target4: MetallicRoughnessShadingModelFlags // new layout | +=================================================================+
New vs replaced (GBuffer layout changed): The new deferred_shading_gbuffer.hlsl changes the GBuffer packing: Roughness moved from NormalRoughness.w (RT1 Alpha) to MetallicRoughnessShadingModelFlags.g (RT2 Green). Flags moved from .g (RT2 Green) to .a (RT2 Alpha). RT1 renamed from NormalRoughness to Normal. RT2 renamed from MetallicShadingModelFlags to MetallicRoughnessShadingModelFlags. The old res/shader/ version is no longer used at runtime since the new file takes priority. 新版替换(GBuffer 布局变更):deferred_shading_gbuffer.hlsl 改变了 GBuffer 打包方式:Roughness 从 NormalRoughness.w(RT1 Alpha)移到 MetallicRoughnessShadingModelFlags.g(RT2 Green)。Flags 从 .g(RT2 Green)移到 .a(RT2 Alpha)。RT1 从 NormalRoughness 改名为 Normal。RT2 从 MetallicShadingModelFlags 改名为 MetallicRoughnessShadingModelFlags。旧版在运行时不再使用,新文件优先。

GBuffer Write — ps_main()GBuffer 写入 — ps_main()

The GBuffer pixel shader now includes gbuffer_struct.hlsl (a shared struct definition), and the packed layout changed — Roughness is in RT2.g and Flags are in RT2.a:

GBuffer 像素着色器现在包含 gbuffer_struct.hlsl(共享结构体定义),打包布局变化——Roughness 在 RT2.g,Flags 在 RT2.a:

// From gbuffer_struct.hlsl (new shared header)
struct GBuffer {
  float4 AlbedoAO                         : SV_Target0;
  float4 Normal                            : SV_Target1;  // was NormalRoughness
  float4 MetallicRoughnessShadingModelFlags : SV_Target2;  // was MetallicShadingModelFlags
};

GBuffer ps_main(Fragment input, bool is_front_face : SV_IsFrontFace) {
  #if ENABLE_VIRTUALTEXTURE_SAMPLEING
    SamplingVirtualTexture(input);         // NEW: VT sampling before material
  #endif
  RawData raw_data = GetRawData(input);
  Material mtl = (Material)0;
  SetupMaterial(input, raw_data, mtl);
  #if DEFERRED_DECAL_ENABLE && !ENABLE_VIRTUALTEXTURE_SAMPLEING
    DeferredApplyNewDecal(input, mtl);     // conditional guard added
  #endif

  GBuffer gbuffer;
  gbuffer.AlbedoAO = float4(mtl.albedo, mtl.occlusion);
  gbuffer.Normal = float4(0.5 * (mtl.normal + 1.0), 0);  // A channel now free

  // Encode flags into alpha byte (was green byte in old engine)
  uint flags = 0;
  flags = EncodeShadingModel(flags, mtl.shading_model);
  flags = EncodeReceiveShadow(flags);
  #if SLPV_ENABLE && LIGHT_PROBE_ENABLE          // changed condition
    flags = EncodeClusteredShadingLightProbeVolumeEnable(flags);
  #endif

  gbuffer.MetallicRoughnessShadingModelFlags = float4(
    mtl.metalness,
    mtl.roughness,                        // NEW: Roughness in .g (was in RT1.a)
    0,
    float(flags) / 255.0                   // Flags in .a (was in .g)
  );
  return gbuffer;
}

Single-Pass Deferred — Mobile Optimization单 Pass 延迟 — 移动端优化

On tile-based deferred rendering (TBDR) GPUs (iOS/Android), NeoX supports Single-Pass Deferred Shading. This writes both GBuffer data AND lighting result in one pass, avoiding the costly off-chip GBuffer readback that destroys TBDR benefits.

在基于 Tile 的延迟渲染(TBDR)GPU 上(iOS/Android),NeoX 支持单 Pass 延迟着色。在一个 Pass 中同时写入 GBuffer 数据和光照结果,避免了破坏 TBDR 优势的昂贵离片 GBuffer 回读。

// Single-pass mode: output emissive directly + manual depth
#if SINGLE_PASS_DEFERRED_SHADING_ENABLE
  gbuffer.FinalResult = float4(mtl.emissive, 1);
  #ifdef NEOX_GLSL
    gbuffer.Depth = input.position.z;           // single float
  #else
    gbuffer.Depth = float4(input.position.z);   // packed
  #endif
#endif

Flag Encoding System标志位编码系统

The Alpha channel of MetallicRoughnessShadingModelFlags packs multiple boolean flags into a single byte (0-255). In the new engine the flags moved from the Green to the Alpha channel. Defined in flags.hlsl:

MetallicRoughnessShadingModelFlagsAlpha 通道将多个布尔标志打包到单个字节(0-255)中。新引擎中标志从 Green 通道移到 Alpha 通道。定义在 flags.hlsl

Flag标志BitsPurpose用途
ShadingModelbit 0-3Which shading model (0=Isotropy, 1=Skin, 2=Hair...12=Water, 13=Cloth, 14=Glint, 15=Sheen)哪个着色模型(0-11 同旧版,12=Water, 13=Cloth, 14=Glint, 15=Sheen)
ReceiveShadowbit 4Whether this pixel receives dynamic shadows此像素是否接收动态阴影
LightProbeVolumebit 5SLPV light probe active (condition changed: SLPV_ENABLE && LIGHT_PROBE_ENABLE)SLPV 光照探针激活(条件变更)
BakedShadowbit 6Use baked shadow from light probe使用来自光照探针的烘焙阴影
New vs replaced: Flags moved from Green channel to Alpha channel. Light probe condition changed from CLUSTERED_SHADING_LIGHT_PROBE_VOLUME_ENABLE || LIGHT_PROBE_ENABLE to the more concise SLPV_ENABLE && LIGHT_PROBE_ENABLE. The new GBuffer includes DEFERRED_DECAL_ENABLE and ENABLE_VIRTUALTEXTURE_SAMPLEING guards that did not exist in the old version. 新版替换:Flags 从 Green 通道移到 Alpha 通道。光探针条件从 CLUSTERED_SHADING_LIGHT_PROBE_VOLUME_ENABLE || LIGHT_PROBE_ENABLE 改为更简洁的 SLPV_ENABLE && LIGHT_PROBE_ENABLE。新 GBuffer 包含旧版中不存在的 DEFERRED_DECAL_ENABLEENABLE_VIRTUALTEXTURE_SAMPLEING 保护。

NeoX vs UE5 GBuffer ComparisonNeoX vs UE5 GBuffer 对比

Aspect方面 NeoX (New Engine) UE5.6
RT CountRT 数量3 (standard) / 5 (single-pass)3(标准)/ 5(单 Pass)5-6 (SceneColor + GBuffer A/B/C/D + Velocity)5-6 个
Normal Encoding法线编码0.5*(normal+1) in RT1 (RGB8/16)Octahedron encoding (2-channel)八面体编码(2 通道)
Roughness slotRoughness 槽位RT2.g (new) — freed RT1.a for other useRT2.g(新)——RT1.a 释放可供他用GBufferB.a or GBufferC.g
Shading Model ID着色模型 ID4-bit field in Flags alpha byte (RT2.a)Flags alpha 字节中的 4 位(RT2.a)4-bit in GBufferB.aGBufferB.a 中 4 位
Custom Data自定义数据None (limited by 3 RTs)无(受 3 RT 限制)GBufferD (full RGBA for SSS color, cloth, etc.)GBufferD(完整 RGBA 用于 SSS 颜色等)
Shared struct共享结构体gbuffer_struct.hlsl (new)(新)Various headers各头文件
Bandwidth带宽Lower (3 RT = less memory traffic)更低(3 RT = 更少内存流量)Higher (5+ RT = more flexibility)更高(5+ RT = 更多灵活性)
Design trade-off: NeoX sacrifices GBuffer flexibility for bandwidth efficiency. With only 3 RTs, there's no room for per-pixel custom data (e.g., subsurface color). This is why NeoX primarily uses forward shading for complex materials (skin, hair) and reserves deferred for simple opaque geometry. 设计取舍:NeoX 牺牲 GBuffer 灵活性换取带宽效率。只有 3 个 RT,没有空间放逐像素自定义数据(如次表面颜色)。这就是为什么 NeoX 主要对复杂材质(皮肤、头发)使用前向着色,将延迟留给简单不透明几何体。