4.0 KiB
Raw Blame History

title, date, excerpt, tags, rating
title date excerpt tags rating
未命名 2025-03-27 17:37:02

Toon Lumen

抹平法线思路

ViewVector Fix WorldNormal

参考:

LumenScreenProbeGather.usf中对法线进行抹平处理。其Pass位于

  • DiffuseIndirectAndAO
    • LumenScreenProbeGather
      • Integrate
        • SimpleDiffuse/SupportImportanceSampleBRDF?/SupportAll?

在如下位置添加代码:

if (IsValid(Material))
	{
		const float2 ScreenUV = (Coord.SvPosition + 0.5f) * View.BufferSizeAndInvSize.zw;
		const float3 WorldPosition = GetWorldPositionFromScreenUV(ScreenUV, Material.SceneDepth);
		const float3 WorldNormal = Material.WorldNormal;
		//BlueRose Modify 
		if (Material.ShadingID == SHADINGMODELID_TOONSTANDARD)
		{
			//使用Yu-ki016的方法“抹平法线”
			float3 V = normalize(LWCHackToFloat(PrimaryView.WorldCameraOrigin) - WorldPosition);
			const uint ToonDataAssetID = GetToonDataAssetIDFromGBuffer(Material.GBufferData);
			float DiffuseIndirectLightingFlatten = GetDiffuseIndirectLightingFlatten(ToonDataAssetID);
			Material.WorldNormal = normalize(lerp(WorldNormal, V, DiffuseIndirectLightingFlatten));
		}
		//BlueRose Modify End
		...
	}
}

该方法存在一些问题:当相机围绕角色旋转时,角色身上的 GI变化会比较明显

低频化WorldNormal & Spherical Harmonics

参考:

!Lumen_能量补偿1.png !Lumen_能量补偿2.png UE5中采样球谐贴图方法(ReflectionEnvironmentShared.ush)

/** 
 * Computes sky diffuse lighting from the SH irradiance map.  
 * This has the SH basis evaluation and diffuse convolution weights combined for minimal ALU's - see "Stupid Spherical Harmonics (SH) Tricks" 
 */
float3 GetSkySHDiffuse(float3 Normal)
{
	float4 NormalVector = float4(Normal, 1.0f); 

	float3 Intermediate0, Intermediate1, Intermediate2;
	Intermediate0.x = dot(SkyIrradianceEnvironmentMap[0], NormalVector);
	Intermediate0.y = dot(SkyIrradianceEnvironmentMap[1], NormalVector);
	Intermediate0.z = dot(SkyIrradianceEnvironmentMap[2], NormalVector);

	float4 vB = NormalVector.xyzz * NormalVector.yzzx;
	Intermediate1.x = dot(SkyIrradianceEnvironmentMap[3], vB);
	Intermediate1.y = dot(SkyIrradianceEnvironmentMap[4], vB);
	Intermediate1.z = dot(SkyIrradianceEnvironmentMap[5], vB);

	float vC = NormalVector.x * NormalVector.x - NormalVector.y * NormalVector.y;
	Intermediate2 = SkyIrradianceEnvironmentMap[6].xyz * vC;

	// max to not get negative colors
	return max(0, Intermediate0 + Intermediate1 + Intermediate2);
}

Cel适配

需要实现Cel多光源方案。

大致的思路就是Copy Lumen结果之后在Toon多光源参考中提取亮度再根据亮度采样Ramp计算光影结果。