本文是为了方便讲解PBR过程中的一些问题造的一个轮子,加深理解,毕竟实践才是最好的。
首先我们先构建类似URP一样自己的customLitData,用于在Fragment中渲染光照
CustomLitData customLitData;
InitializeCustomLitData(input,customLitData);
CustomSurfacedata customSurfaceData;
InitializeCustomSurfaceData(input,customSurfaceData);
在customLitData中,我们需要得到V、T、B、N相关的信息,用于后面的Vector等相关计算ScreenUV用于SSAO计算,不加也没关系,毕竟这只是一个simpleLit。
customLitData.positionWS = input.positionWS;
customLitData.V = GetWorldSpaceNormalizeViewDir(input.positionWS);
customLitData.N = normalize(input.normalWS);
customLitData.T = normalize(input.tangentWS.xyz);
customLitData.B = normalize(cross(customLitData.N,customLitData.T) * input.tangentWS.w);
customLitData.ScreenUV = GetNormalizedScreenSpaceUV(input.positionCS);
在customSurfaceData,我们需要处理albedo、alpha、roughness、normal等信息,用于后面处理光照。
处理完各类信息后,我们需要计算光照:
albedo:
specular:
customSurfaceData.specular = lerp(float3(0.04,0.04,0.04),albedo,customSurfaceData.metallic);
roughness:
customSurfaceData.roughness = max(customSurfaceData.roughness,0.001f);
如果我们在URP中开启了SSAO,我们还要把这部分添加上
#if defined(_SCREEN_SPACE_OCCLUSION)
AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(customLitData.ScreenUV);
customSurfaceData.occlusion = min(customSurfaceData.occlusion,aoFactor.indirectAmbientOcclusion);
#endif
然后计算直接光照:
对应的BRDF,这部分我借鉴的UE5中的实现:
Diffuse:用lambert:
return DiffuseColor * (1 / PI);
D项,用UE5的GGX(大家可自行对比下Unity的GGX):
Unity URP GGX(实际上和UE5一样,但是比较繁琐):
V项:
float Vis_Implicit()
{
return 0.25;
}
F项:
float3 F_None( float3 SpecularColor )
{
return SpecularColor;
}
Specular:
float3 specularTerm = ((D * Vis) * F) * NoL * lightColor * shadow;
添加对点光源的支持:
对于移动端,URP提供了一个特别版本的D、V、F,移动端也可以采用这套拟合后的方案
由于这套SimpleLit方案漫反射采用了lambert(lambert无光的地方就是一片死黑),没有考虑间接光,所以和URP的效果肯定不一样。下一章写StandardLit,会重点讲一下间接光该如何写。