UE5 如何在延时渲染在材质编辑器提前使用到多灯光的数据

1、首先我们要去了解custom hlsl的include file paths

  • Include File Paths 和 C/C++ 的 #include 指令功能相同,用于在编译当前材质的 HLSL 代码时,将指定的文件内容"粘贴"进来。

include file 的内容:

复制代码
#pragma once

#ifndef IS_BASE_PASS
	#define IS_BASE_PASS 0
#endif

#ifndef SHADING_PATH_DEFERRED
	#define SHADING_PATH_DEFERRED 0
#endif

#ifndef MATERIALBLENDING_ANY_TRANSLUCENT
	#define MATERIALBLENDING_ANY_TRANSLUCENT 0
#endif

#define GM_BASEPASS_FORWARD_LIGHT_ACCESS (IS_BASE_PASS && SHADING_PATH_DEFERRED)

#if GM_BASEPASS_FORWARD_LIGHT_ACCESS

	#ifndef ForwardLightStruct
		#define GM_DEFINED_FORWARD_LIGHT_STRUCT 1
		#if MATERIALBLENDING_ANY_TRANSLUCENT
			#define ForwardLightStruct TranslucentBasePass.Shared.Forward
		#else
			#define ForwardLightStruct OpaqueBasePass.Shared.Forward
		#endif
	#else
		#define GM_DEFINED_FORWARD_LIGHT_STRUCT 0
	#endif

	#include "/Engine/Private/LightGridCommon.ush"

#endif

uint GM_GetBasePassForwardEyeIndex(FMaterialPixelParameters Parameters)
{
#if MOBILE_MULTI_VIEW
	return GetViewId(Parameters);
#else
	// 当前材质参数里没有直接等价于 BasePassPixelShader.usf 中 EyeIndex 的通用字段。
	// 非 multiview / 非 instanced stereo 路径用 0。
	return 0;
#endif
}

uint GM_GetForwardLightGridIndex(FMaterialPixelParameters Parameters)
{
#if GM_BASEPASS_FORWARD_LIGHT_ACCESS && FEATURE_LEVEL >= FEATURE_LEVEL_SM5
	const uint EyeIndex = GM_GetBasePassForwardEyeIndex(Parameters);
	const uint2 PixelPos = (uint2)((Parameters.SvPosition.xy - ResolvedView.ViewRectMin.xy) * View.LightProbeSizeRatioAndInvSizeRatio.zw);
	return ComputeLightGridCellIndex(PixelPos, Parameters.SvPosition.w, EyeIndex);
#else
	return 0;
#endif
}

#if GM_BASEPASS_FORWARD_LIGHT_ACCESS && defined(GM_DEFINED_FORWARD_LIGHT_STRUCT) && GM_DEFINED_FORWARD_LIGHT_STRUCT
	#undef ForwardLightStruct
#endif

#ifdef GM_DEFINED_FORWARD_LIGHT_STRUCT
	#undef GM_DEFINED_FORWARD_LIGHT_STRUCT
#endif

写入gbuffer的流程就是BasePass

|------------------------------------|------------------------------------------------|
| IS_BASE_PASS | 当前是否在 BasePass 中渲染 |
| SHADING_PATH_DEFERRED | 当前是否使用延迟渲染路径 |
| MATERIALBLENDING_ANY_TRANSLUCENT | 当前材质是否是透明材质 |
| GM_BASEPASS_FORWARD_LIGHT_ACCESS | 最终开关:是否在延迟渲染的 BasePass 中允许访问 Forward+ 灯光网格 |

复制代码
#if GM_BASEPASS_FORWARD_LIGHT_ACCESS

    #ifndef ForwardLightStruct
        #define GM_DEFINED_FORWARD_LIGHT_STRUCT 1
        #if MATERIALBLENDING_ANY_TRANSLUCENT
            #define ForwardLightStruct TranslucentBasePass.Shared.Forward
        #else
            #define ForwardLightStruct OpaqueBasePass.Shared.Forward
        #endif
    #else
        #define GM_DEFINED_FORWARD_LIGHT_STRUCT 0
    #endif

    #include "/Engine/Private/LightGridCommon.ush"

#endif
  • 如果开关开启,且 ForwardLightStruct 没有被外部定义过,就定义它

  • 根据材质类型(透明 / 不透明),指向不同的 Uniform Buffer

  • Uniform Buffer 是 CPU 传递给 GPU 的数据块,这里包含灯光网格的索引、光源列表等

  • 然后包含 LightGridCommon.ush------这个文件里定义了 ComputeLightGridCellIndexGetForwardLightingDataFromGrid 等核心函数


在材质编辑器的 Custom 节点中,HLSL 代码会被封装在一个函数里。这种"隔离"环境限制了你直接访问很多引擎内部功能,而这些功能通过 #include 相应的头文件就能解锁。

当你通过 Include File Paths 引入一个头文件时,就相当于把那个文件的全部内容"粘贴"到了 Custom 节点的代码中,从而获得了访问其中所有声明的能力。这正是你突破 Custom 节点限制的关键。例如,通过包含 /Engine/Private/LightGridCommon.ush,你可以:

  • 调用内部函数 :你可以使用 ComputeLightGridCellIndex() 来获取当前像素的灯光网格索引,或者使用 GetLocalLightDataFromGrid() 来获取光源数据。这些函数是引擎内部多光源算法的核心,通常无法直接调用。

  • 获取核心数据结构 :可以访问 ForwardLightStruct 这样的 Uniform Buffer。这个结构体里存储着所有经过剔除(Culling)的光源列表,是 Forward+ 渲染的核心数据。

  • 引用全局变量 :除了 View.XXX,还能访问 ResolvedView 等更丰富的渲染状态变量。


复制代码
float3 Sum = 0.0.xxx;

#if GM_BASEPASS_FORWARD_LIGHT_ACCESS && FEATURE_LEVEL >= FEATURE_LEVEL_SM5
	const uint GridIndex = GM_GetForwardLightGridIndex(Parameters);
	const FCulledLightsGridHeader Header = GetCulledLightsGridHeader(GridIndex);
	const uint NumLights = min(Header.NumLights, GetMaxLightsPerCell());
	const uint EyeIndex = GM_GetBasePassForwardEyeIndex(Parameters);

	LOOP
	for (uint LightIndex = 0; LightIndex < NumLights; ++LightIndex)
	{
		const FLocalLightData LocalLight = GetLocalLightDataFromGrid(Header.DataStartIndex + LightIndex, EyeIndex);
		float3 LightPos = UnpackLightTranslatedWorldPosition(LocalLight);
        float3 LightDir = normalize(LightPos - GetTranslatedWorldPosition(Parameters));
        Sum += saturate(dot(LightDir,WorldNormal));
	}
#endif

return Sum;
  1. 判断是否可用 :首先检查 GM_BASEPASS_FORWARD_LIGHT_ACCESSFEATURE_LEVEL >= FEATURE_LEVEL_SM5,确保当前渲染环境支持访问 Forward+ 灯光网格数据。

  2. 获取当前像素的光源列表

    • GridIndex = GM_GetForwardLightGridIndex(Parameters):根据像素位置计算它在 3D 灯光网格中的格子索引

    • Header = GetCulledLightsGridHeader(GridIndex):获取该格子包含的光源列表元数据(起始位置、数量等)

    • NumLights = min(Header.NumLights, GetMaxLightsPerCell()):获取实际需要处理的光源数量

  3. 遍历所有影响该像素的光源

    • 对于每个光源,获取其完整属性数据(位置、颜色、半径等)

    • 将光源位置从编码格式解包到世界空间

    • 计算从像素指向光源的方向向量

    • 通过 saturate(dot(LightDir, WorldNormal)) 计算兰伯特漫反射强度(光线与法线的夹角余弦值,限制在 0-1 范围)

  4. 输出结果:将所有光源的漫反射强度累加后返回,这个值可以连接到材质的自发光或基础颜色等引脚。


以上是HLSL代码,其中GM_BASEPASS_FORWARD_LIGHT_ACCESS是include file path的文件里面定义的宏


FEATURE_LEVEL 是 UE5 着色器系统中的一个全局宏 。它并不是一个普通的变量,而是在着色器编译时,由引擎根据当前渲染平台的功能级别预定义并注入到代码中的。


GM_GetForwardLightGridIndex(Parameters);

是include file path的文件BasePassForwardLightGrid.ush声明的自定义函数


GetCulledLightsGridHeader

GetCulledLightsGridHeader和 FCulledLightsGridHeader 在BasePassForwardLightGrid.ush文件中的LightGridCommon.ush文件下:


GM_GetBasePassForwardEyeIndex(Parameters);

是include file path的文件BasePassForwardLightGrid.ush声明的自定义函数


FLocalLightData

是include file path的文件BasePassForwardLightGrid.ush里面包含了的头文件:

#include "/Engine/Private/LightGridCommon.ush"

头文件包含了LightData.ush

LightData.ush里面定义了FLocalLightData


0.0.xxx 是 HLSL 中的一种 swizzle(分量重组) 写法,意思是:将标量 0.0 当作一个只有 x 分量的向量,然后通过 .xxx 将其复制三份,构成一个 float3 向量,效果等同于 float3(0.0, 0.0, 0.0)0.0.xxx

在 HLSL 中,任何标量(如 0.0)都可以隐式地当作一个只有 .x 分量的向量,因此可以像向量一样使用 .x.y.z.w 等 swizzle 操作。例如:

  • (0.0).xxxfloat3(0,0,0)

  • (1.0).xxyfloat3(1,1,0)

  • (2.5).x → 还是 2.5(标量)

所以 0.0.xxx 实际上等价于 (0.0).xxx。由于编译器允许省略括号,就写成了 0.0.xxx


复制代码
struct FCulledLightsGridHeader
{
	uint NumLights;
	uint NumMegaLights;
	uint DataStartIndex;
	uint MegaLightsDataStartIndex;
	bool bHasRectLight;
	bool bHasTexturedLight;
};
  • bHasTexturedLight:"纹理光源"广义上指其光照属性由纹理决定的光源。在UE中,这通常指使用了光源函数(Light Function) 的光源。通过将材质应用到光源上,可以创造出类似水底焦散、云层阴影或霓虹灯图案等丰富的光照效果。此外,它也可以指使用IES描述文件的光源,以模拟真实灯光的分布曲线。
相关推荐
法雅特吉他1 天前
吉他面板材质技术解析:合板 vs 面单 vs 全单
经验分享·新媒体运营·学习方法·材质·内容运营
友人.2271 天前
补充章节:VSCode Wokwi 无法可视化连线?在线 Wokwi 网页拖拽绘图方案
ide·vscode·编辑器
zhanghaofaowhrql1 天前
为CSDN博客编辑器安装自定义CSS主题,打造个性化写作界面
前端·css·编辑器
HAPPY酷1 天前
【ROS2】 机械臂架构 vs UE5 游戏开发架构 终极对照表
架构·ue5
DoomGT1 天前
UE5 - 制作游戏中切换窗口后游戏自动暂停功能
游戏·ue5·ue4·虚幻·虚幻引擎·unreal engine
workbuddy小能手1 天前
用 WorkBuddy 部署 Node.js 项目实战:基金导航站与 Markdown 编辑器同机上线
人工智能·ai·node.js·编辑器·workbuddy
华万通信king1 天前
用 WorkBuddy 把两个 Node 网站搬上云:基金导航站 + Markdown 编辑器,宝塔托管实战复盘
人工智能·编辑器·workbuddy
Zhang~Ling2 天前
Vim 多模式详解:命令、插入、底行与插件配置
linux·编辑器·vim
fenghx2582 天前
仅用于个人记录:火狐有网,Vscode的codex连不上
vscode·编辑器
HhzZzzzz_2 天前
萨科微slkor2026年7月6日“每日芯闻”。国际芯闻:
人工智能·智能手机·编辑器