【UnityShader】屏幕空间全息扫描效果

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/mobilebbki399/article/details/78379758

前段时间刚玩《使命召唤11》的时候发现里面新增了一种很高科技的扫描手榴弹,可以产生一圈类似全息效果的扫描圈,并显示出墙后的敌人,类似这样:



最近打算实现一个用在第三人称中类似的效果,如下:



实现方案:

1.根据_CameraDepthTexture计算屏幕空间像素点的世界坐标

2.将扫描发起位置的世界坐标传入shader

3.计算屏幕空间世界坐标到扫描发起位置世界坐标的距离

4.根据相关参数渲染出扫描区域


1._CameraDepthTexture中记录了投影空间的深度信息,通过如下方式可以得到世界坐标:

fixed depth = tex2D(_CameraDepthTexture, i.uv).r;
fixed4 projPos = fixed4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, -depth * 2 + 1, 1);
worldPos = mul(internalCameraToWorld, worldPos);
worldPos /= worldPos.w;


2.计算传入的初始位置和屏幕空间世界坐标距离:

fixed dis = length(internalCentPos.xyz - worldPos.xyz);
 
fixed a = 1 - saturate((abs(dis - internalArg.x) - internalArg.y) / internalArg.z);
a = a * internalFade.x + c * internalFade.y;
最终可以得到如下效果:

3.保存上一步的渲染结果,使用CommandBuffer,将需要标记为持续显示的目标(例如敌人)也渲染到该纹理,注意需要判断目标是否在摄像机内,效果如下:


public static void CallRender(Vector3 worldPosition, Renderer[] renderer)
    {
        if (!IsInitialized())
            return;
        if (instance.m_IsShowingEffect)
        {
            if (renderer == null)
                return;
            Vector3 pjpos = instance.m_Camera.worldToCameraMatrix.MultiplyPoint(worldPosition);
            pjpos = instance.m_Camera.projectionMatrix.MultiplyPoint(pjpos);
            if (pjpos.x < -1 || pjpos.x > 1 || pjpos.y < -1 || pjpos.y > 1 || pjpos.z < -1 || pjpos.z > 1)
                return;
            for (int i = 0; i < renderer.Length; i++)
            {
                instance.m_CommandBuffer.DrawRenderer(renderer[i], instance.m_ReplaceMaterial);
            }
        }
    }


4.根据屏幕uv信息将屏幕uv栅格化,并计算每个格子中采样到的颜色值,可以得到如下结果:



float2 fl = floor(i.uv * _EffectScale);
float dp = tex2D(_PreTex, (fl + float2(0.5, 0.5)) / _EffectScale);
                 
float4 led = tex2D(_EffectTex, i.uv * _EffectScale - fl);
                 
col.rgb += led.rgb*dp;

5.同样根据刚刚栅格的结果,可以计算出每一小格的uv,根据该uv来采样用于作为全息扫描效果的纹理,得到如下结果:



6.叠加最终结果:



Git地址请点击博客原文


猜你喜欢

转载自blog.csdn.net/mobilebbki399/article/details/78379758