如果你只做能力范围之内的事,你就永远不会有进步!|

陈侠云

园龄:2年10个月粉丝:1关注:1

Unity的阴影初步了解

起因:

最近学习了Unity内的实时阴影的计算,所以这里总结收录一下,加深一下印象。下面分别介绍ShadowMap和屏幕空间阴影和联级阴影的计算流程。
image

阴影计算流程:

  1. 首先获得当前摄像机观察到深度纹理。在延迟渲染中,这张深度图Unity已经帮忙计算好了,前向渲染中,我们则需要等待场景都被渲染了一遍,把深度渲染到深度图中。
  2. 在从“光源处”出发得到从该光源处观察到的深度纹理,也被称为这个光源的ShadowMap。
  3. 在屏幕空间中做一次阴影收集计算(Shadow Collector),得到一张屏幕空间的阴影纹理。
  4. 在为正常物体渲染阴影时,只需要在片元着色器中对步骤3得到的屏幕空间阴影采样即可。

详细介绍:

下面详细介绍下各个步骤的过程。

shader代码

我们先简单写一个仅会产生阴影的Shadow

Shader "Unlit/PhongJian"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
			#pragma multi_compile_fwdbase
			#include "UnityCG.cginc"
			#include "AutoLight.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                SHADOW_COORDS(1)    // 声明一个用于阴影纹理采样的坐标
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                TRANSFER_SHADOW(o);         // 用于计算上一步申明的阴影纹理坐标
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                half shadow = SHADOW_ATTENUATION(i);
                return fixed4(shadow.xxx, 1);
            }
            ENDCG
        }
    }
    
    Fallback "Diffuse" 
}

其中注意,必须在末尾写一个带有ShaowCaster实现的shader,不然我们就需要自己实现了;appdata输入的顶点必须叫vertex;v2f输出的顶点必须名为pos,不然TRANSFER_SHADOW宏编译会报错

传统实时阴影

因为旨在了解传统实时阴影的生成流程,我们先将Unity内置的联级阴影给关掉。
image
将阴影距离调整到10,这样阴影看的更清楚
image
将摄像机调整到前向渲染,也是默认的渲染模式
image
我们可以看到,它经历了名为ShaowCaster,输出了光源处的阴影贴图,此时你旋转平行光,会发现这张贴图也会改变,原理是因为是在光源处对物体进行观察得到的ShadowMap
image
此时我们可以看到,在绘制Mesh时,它传入了上一步得到的阴影,最终将它们绘制到屏幕上去
image

屏幕空间阴影

先在Project Settings/Graphics打开联级阴影的设置
image
然后在Project Settings/Quality中取消联级阴影
image
我们可以看到它首先绘制了一张摄像机视角下的深度图
image
然后绘制一张从光源处出发的深度图
image
然后在屏幕空间做一次阴影收集计算(Shadows Collector),这里把每个像素根据它在摄像机深度纹理中的深度值得到世界空间坐标,再把坐标从世界空间转化到光源空间中,和光源空间中的ShadowMap里的深度值做对比,如果大于ShadowMap中的深度距离,说明光源无法照射到
image
最后在绘制Mesh,它传入上一步得到的屏幕空间阴影,最终混合并绘制到屏幕上去
image

联级阴影

打开联级阴影的设置
image
联级阴影流程可以认为是在屏幕空间阴影上做了优化,流程基本大同小异,除了会随着观察距离的远近,生成多张光源处贴图,我们看到移动到特定角度,生成了3张贴图
image
打开Shadows Cascades,我们确实观察到此时处于绿色范围内
image
最终输出效果也更加柔和
image

资料参考:

  1. https://www.zhihu.com/question/52718833/answer/132200901?utm_campaign=shareopn&utm_medium=social&utm_psn=1760936896992014336&utm_source=wechat_session

本文作者:陈侠云

本文链接:https://www.cnblogs.com/chenxiayun/p/18123065

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   陈侠云  阅读(123)  评论(0编辑  收藏  举报
//雪花飘落效果
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起