unity3d中如何使用屏幕空间改善shadowmap漏光

这篇文章主要介绍了unity3d中如何使用屏幕空间改善shadowmap漏光,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

前因

自从实时阴影发展到了shadowmap时代,漏光和 Shadow Acne就形影不离。除非你可以无脑极大提升shadowmap精度 或可以做到很短距离的实时阴影 否则并不好解决这常见问题。如下图

unity3d中如何使用屏幕空间改善shadowmap漏光

 
bias调大就漏光 ,bias调小就自阴影出错

动态bias方案

我早年在网易引擎部面试的时候 总监大佬问过我这问题。我当年很得意,告诉他我自创并实现过demo的做法,计算shadowmap 不仅写入深度 也写入 投影表面的世界法线(或投影表面的SV_PrimitiveID 这个更省空间),这样绘制阴影的时候就能根据自己表面的世界法线 是否与投影表面接近来判断 是否自己投影给自己 如果是bias算的大些 否则算的小些。因为既然bias 固定数值都不行,那就实现动态bias,这样逻辑上就成立。大佬冷静的说,shadowmap本身就精度不足 你同尺寸数据也不能提升太多。(实际测试确实提升不太大),他接着小心翼翼地问道:你就不能在屏幕空间想想办法?当年的我除了ssao模仿的实现一次 根本没灵活掌握各种其他SS技巧而且也没经验,于是答不出来。但是看得出他的小心翼翼 仿佛再问一句就会泄露做法一般,我就印象深刻的记下:这个点可能很容易想出来有时间了就去尝试。现在刚好是时候了。

屏幕空间改善漏光方案

我想到屏幕空间上一个像素可以根据深度图去检查,他往光线方向上短距离内是否有遮挡物,如果有那么应该有阴影。于是我选择把bias调大,如上图左图,然后想办法去把漏的光补上。没有选自阴影出错然后 把阴影消去是因为,投影者不一定就在附近所以不能简单的消去阴影。但是 漏光处如果有投影一定是在附近所以更好查询。先看效果很不错。

unity3d中如何使用屏幕空间改善shadowmap漏光

 

 
屏幕空间优化后 比2个bias最好效果结合一起还好  


这么大的提升 代码量居然只要6句 采样的也是已有的深度图性能基本没问题.代码直接带详细说明。简单测试函数就写在了 LightingMyStandard_GI 内,根据实际项目可放屏幕阴影计算shader,任何地方只要能获取世界坐标就可以

void LightingMyStandard_GI( SurfaceOutputStandard s, UnityGIInput data,inout UnityGI gi)    {              //当前位置 往光线方向移动0.1米 定位虚拟投影物 看看那里是否真有物体 如果有就算遮挡      float4 casterWpos =float4( data.worldPos +  data.light.dir * 0.1f,1);       //转到裁剪空间      float4 casterNdc = mul(UNITY_MATRIX_VP, casterWpos);                        //转到ndc空间      casterNdc /= casterNdc.w;                       //转到采样坐标去看看这里实际屏幕深度多少      float2 samplePos = casterNdc.xy * 0.5 + 0.5;                        //获得虚拟投影物位置实际深度      float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, samplePos);             // 如果虚拟投影物 被遮挡 就算真有遮挡物 阴影为黑色 //实际项目 最好转到 Linear01Depth(depth) * _ProjectionParams.z 比较真实距离 和 有效范围内才算遮挡                              if (depth > casterNdc.z) data.atten = 0;                           //以下为函数原内容                         #if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS         gi = UnityGlobalIllumination(data, s.Occlusion, s.Normal);                        #else      Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(s.Smoothness, data.worldViewDir, s.Normal, lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo, s.Metallic));        gi = UnityGlobalIllumination(data, s.Occlusion, s.Normal, g);                        #endif          }

如果虚拟投影物 被遮挡 就算真有遮挡物 阴影为黑色 ,实际项目 最好转到 Linear01Depth(depth) * _ProjectionParams.z 比较真实距离 和 有效范围内才算遮挡

感谢你能够认真阅读完这篇文章,希望小编分享的“unity3d中如何使用屏幕空间改善shadowmap漏光”这篇文章对大家有帮助,同时也希望大家多多支持编程之家,关注编程之家行业资讯频道,更多相关知识等着你来学习!

相关文章

这篇文章将为大家详细讲解有关Unity3D中如何通过Animator动画...
这篇文章主要介绍了Unity3D如何播放游戏视频,具有一定借鉴价...
这篇文章给大家分享的是有关Unity3D各平台路径是什么的内容。...
小编给大家分享一下Unity3D如何实现移动平台上的角色阴影,希...
如何解析基于Unity3D的平坦四叉树地形与Virtual Texture的分...
这篇文章主要介绍Unity3D如何实现动态分辨率降低渲染开销,文...