在URP中的BRDF计算公式问题
1)在URP中的BRDF计算公式问题
2)Job System占用主线程时间问题
3)在Profiler中定位TempBuffer问题
4)Unity 2019使用HDRP的摄像机的GL画线问题
5)Unity WebCamTexture获取到的相机图片被旋转
这是第248篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。
UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)
Shader
Q:最近在看URP Shader的时候发现个问题,不知道是不是我理解的不对。首先贴代码:
先是URP的Lighting.hlsl里初始化BRDF的部分:
inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData) { #ifdef _SPECULAR_SETUP half reflectivity = ReflectivitySpecular(specular); half oneMinusReflectivity = 1.0 - reflectivity; outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular); outBRDFData.specular = specular; #else half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic); half reflectivity = 1.0 - oneMinusReflectivity; outBRDFData.diffuse = albedo * oneMinusReflectivity; outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic); #endif outBRDFData.grazingTerm = saturate(smoothness + reflectivity); outBRDFData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness); outBRDFData.roughness = max(PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness), HALF_MIN); outBRDFData.roughness2 = outBRDFData.roughness * outBRDFData.roughness; outBRDFData.normalizationTerm = outBRDFData.roughness * 4.0h + 2.0h; outBRDFData.roughness2MinusOne = outBRDFData.roughness2 - 1.0h; #ifdef _ALPHAPREMULTIPLY_ON outBRDFData.diffuse *= alpha; alpha = alpha * oneMinusReflectivity + reflectivity; #endif }
按照我的理解:
outBRDFData.perceptualRoughness 是我们说的粗糙度;
outBRDFData.roughness 是粗糙度的平方;
outBRDFData.roughness2 是粗糙度的4次方;
再看URP的Lighting.hlsl里计算BRDF的部分:
// Based on Minimalist CookTorrance BRDF // Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255 // // * NDF [Modified] GGX // * Modified Kelemen and Szirmay-Kalos for Visibility term // * Fresnel approximated with 1/LdotH half3 DirectBDRF(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS) { #ifndef _SPECULARHIGHLIGHTS_OFF float3 halfDir = SafeNormalize(float3(lightDirectionWS) + float3(viewDirectionWS)); float NoH = saturate(dot(normalWS, halfDir)); half LoH = saturate(dot(lightDirectionWS, halfDir)); // GGX Distribution multiplied by combined approximation of Visibility and Fresnel // BRDFspec = (D * V * F) / 4.0 // D = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2 // V * F = 1.0 / ( LoH^2 * (roughness + 0.5) ) // See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course // https://community.arm.com/events/1155 // Final BRDFspec = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2 * (LoH^2 * (roughness + 0.5) * 4.0) // We further optimize a few light invariant terms // brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD. float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f; half LoH2 = LoH * LoH; half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm); // On platforms where half actually means something, the denominator has a risk of overflow // clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles) // sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...)) #if defined (SHADER_API_MOBILE) || defined (SHADER_API_SWITCH) specularTerm = specularTerm - HALF_MIN; specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles #endif half3 color = specularTerm * brdfData.specular + brdfData.diffuse; return color; #else return brdfData.diffuse; #endif }
这里最终的公式是:
BRDFspec=roughness^2/( NoH^2*(roughness^2-1)+1)^2*(LoH^2*(roughness+0.5)*4.0)
然后看Unity 2015年的论文,也就是代码里写的那个地址:
https://community.arm.com/events/1155
代码里的roughness实际上是图里roughness的平方,为了防止混淆,下面用roughness©和roughness(n)来表示:
roughness©=roughness(n)^2
看到这里我产生了疑问,论文里roughness(n)+0.5这一步,对应到代码里,应该是roughness©^0.5+0.5才对,而URP代码里直接用了roughness©+0.5。我想问下是我理解的不对,还是URP的Shader写错了?
A:讲一下不太成熟的看法。我这边的结论是:
- 用平方(roughness(n)^2)加0.5是合理的
- 用一次方或者是平方差别不大
SIGGRAPH报告中最初V*F函数如下:
实际使用的V*F函数是对上述函数的一个近似,使用图像相近的函数进行优化:
笔者对取一次方和取平方的函数图像进行了绘制如下:
两个图像差别不大,而从走势上看,取平方似乎更最接近最初的VF(Modified KSK and Schlick Fresnel depend on LH)。
笔者修改了Lighting.hlsl的代码,使用一次方:
outBRDFData.normalizationTerm=outBRDFData.perceptualRoughness*4.0h+2.0h;
将使用roughness(n)+0.5和使用roughness(n)^2+0.5的材质绘制在同一个屏幕上如下,两者几乎没有差别:
根据图形学第一定律:如果它看起来是对的,那么它就是对的,所以理解成两个都对应该也可以。那么,是不是在差距不大的情况下就不必深究了。
感谢Prin@UWA问答社区提供了回答
Script
Q:如图,为什么放到Job System去执行还会占用主线程的时间?
A:等待子线程执行完毕。
感谢Walker-523103@UWA问答社区提供了回答
Rendering
Q:如图所示,在一个场景里两个TempBuffer,不是从C#脚本上创建产生的。场景没有使用后效,没有使用Grab Pass的Shader,场景摄像机都关掉了MSAA和HDR,仍然有这两个TempBuffer。请问如何完全去掉?
好像和这两个东西有关:
A1:设置一下这个试试:Camera.forceIntoRenderTexture = false;
这个选项会强制将相机渲染到TempBuffer上。在不使用后效时手动设置为false,开启后效会自动设为true。所以如果使用了后效,则TempBuffer是不可避免的了。
感谢范世青@UWA问答社区提供了回答
A2:屏蔽掉所有MonoBehavior的OnRenderImage(RenderTexture source, RenderTexture destination)函数,一般来说每个OnRenderImage(RenderTexture source, RenderTexture destination)函数都会产生一个TempBuffer。
感谢李星@UWA问答社区提供了回答
A3:Grab RenderTexture一般是Depth最小的相机的Clear Flags设置为Depth Only的时候会出现。
感谢Xuan@UWA问答社区提供了回答
Rendering
Q:在Unity 2019.3.0f6使用GL画线在Game视图下摄像机找不到,项目是属于HDRP工程。
A1:把你GL绘制的放到GLDraws()中,我在Unity 2020.2.2f1c1中,HDRP10.2.2环境下已经成功绘制出来效果:
protected void OnEnable() { if (GraphicsSettings.renderPipelineAsset != null) RenderPipelineManager.endFrameRendering += OnCameraRender; }
protected void OnDisable() { if (GraphicsSettings.renderPipelineAsset != null) RenderPipelineManager.endFrameRendering -= OnCameraRender; } protected void OnCameraRender(ScriptableRenderContext context, Camera[] cameraList) { foreach(var camera in cameraList) { if (CheckFilter(camera)) GLDraws(); } }
感谢pp@UWA问答社区提供了回答
Script
Q:从Unity WebCamTexture获取到的相机图片被旋转了,我看微信的扫一扫,画面都是对的,而且手机旋转的时候,画面也一直是正的,没有看到图片有旋转的痕迹。手机竖屏的时候是正常的,旋转到横屏,画面就不对了。
A:可以在屏幕旋转的时候按下面这样的方式调整一下用于显示的RawImage的旋转:
感谢羽飞@UWA问答社区提供了回答
封面图来源:Unity Lightcookie Caustic
https://lab.uwa4d.com/lab/5dcdc2858bab6aaf023555a2
今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)