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描述文件的光源,以模拟真实灯光的分布曲线。
相关推荐
VidDown1 天前
VidDown 工具站:免费、本地优先的开发者工具箱
javascript·编辑器·音视频·视频编解码·视频
VidDown1 天前
显卡处理视频技术详解:从硬解码到 NVENC,GPU 如何让视频处理起飞?
javascript·编辑器·音视频·视频编解码·视频
夜猫逐梦1 天前
【UE基础】03.蓝图与编辑器工作流
编辑器·ue·蓝图·ue编辑器
VidDown1 天前
视频帧率技术详解:从 24fps 到 120fps,帧率如何影响你的观看体验?
网络·网络协议·编辑器·音视频·视频编解码·视频
爱就是恒久忍耐1 天前
VSCode里如何比较2个branch
ide·vscode·编辑器
bloglin999991 天前
vscode中可视化的合并分支,在“合并编辑器中解析”中“与基线进行比较”是什么意思
ide·vscode·编辑器
zyplayer-doc2 天前
企业知识库安全与权限管理完全指南:从加密到审计的六层防护
人工智能·安全·pdf·编辑器·创业创新
古德new2 天前
鸿蒙PC迁移:Photoflare Qt 图片编辑器鸿蒙PC适配全记录
qt·编辑器·harmonyos
春日见2 天前
vscode的AI编程插件推荐:
大数据·ide·vscode·算法·机器学习·编辑器·ai编程
jieshenai2 天前
VScode sys.path,并使CTRL+左键可访问源码
ide·vscode·编辑器