4.0 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	
			4.0 KiB
		
	
	
	
	
	
	
	
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?
 
 
 - Integrate
 
 - LumenScreenProbeGather
 
在如下位置添加代码:
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
参考:
- [UFSH2024]用虚幻引擎5为《幻塔》定制高品质动画流程风格化渲染管线 | 晨风 Neverwind 完美世界游戏】【精准空降到 12:55】
 - [UFSH2024]用虚幻引擎5为《幻塔》定制高品质动画流程风格化渲染管线 | 晨风 Neverwind 完美世界游戏】 【精准空降到 36:52】
- 需要实现:法线平滑 => 饱和度平滑。(没说细节,不清楚算法)
 
 - [UFSH2024]用虚幻引擎5为《幻塔》定制高品质动画流程风格化渲染管线 | 晨风 Neverwind 完美世界游戏】【精准空降到 35:09】
- 小于等于High存储的是一个八面体,提前加一个Pass进行平滑:采样法线方向半球面的平均数值。
 - 大于等于Epic存储的是一个三阶球谐,保持1阶球谐数值不变,对2~3阶球谐按照系数进行平滑。并且添加能量补偿,大致与PBR的结果接近。 !Lumen_SHData.png
 
 
!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计算光影结果。