天天看點

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

這篇文章是繼這篇文章的序章,更進一步學習及了解投影。

寫作思路:

1、簡述投影原理(包括剖析Unity的陰影投射原理)4張陰影貼圖、陰影貼圖采集

2、介紹什麼是bias、normalBias,以及為什麼會産生 投影瑕疵

3、引入兩個Unity的兩個對應bias和normalBias的shader内置函數

4、bias、normalBias在Shader中的簡單應用

1、簡述Unity陰影投射原理

正如上篇所說:

點A在相機的深度值設為 ZA ,點A在陰影紋理的深度值為ZB ,如果ZA >ZB ,則該點處于相機的可見範圍并且處于陰影之中,即該點看得到陰影

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

那Unity是如何獲得ZA 和ZB的呢?

在Unity中,ZB 其實是記錄在光照深度圖(陰影貼圖)中的; ZA 就是我們相機中看到的對象的深度! 先記住上面說的這兩個東西!

1、首先我們随機建立一個場景,裡面放置一些簡單的模型對象,并且放置一束平行光,如下圖

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

2、接下來打開Unity的Frame Debug并啟用,可以看到渲染的順序清單中先渲染了模型相關的深度圖,點選如下清單的位置,可以看到Game視窗出現第二幅圖,這就是模型相關的深度圖(也就是上圖 3球1方塊的深度圖)

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,
UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

3、選中下面第一張圖,可以看到Game視窗渲染了4張深度圖,這四張深度圖就是光照深度圖(陰影貼圖)

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,
UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

因為我們在Project Settings中設定了如下設定,最關鍵的就是 “Shadow Casades”我們設定了四個變量(具體内部怎麼實作不曉得,但是會根據這個數量增加光照深度圖的渲染數量!不重要!不影響我們了解),然後大多數情況下是看不到四張圖的,需要調整一下第二個紅框中的比例

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

4、Unity渲染原理描述: 在上述幾個步驟中,我們獲得了模型深度圖和光照深度圖,其中模型深度圖存儲的是 相機範圍内模型各個點的深度數值,光照深度圖存儲的是從場景平行光角度擷取的 所能照射到的各點的深度值(其實就是相當于從平行光的方向放置一個相機,相機螢幕所能照到的點各點的深度值),然後現在就回到了我們最上面的A,B兩點的問題, 如果模型深度圖裡的點的深度值 >光照深度圖的值,則該點就處于陰影之中,則該點顔色為黑

Unity增加陰影精準度的主要方式有以下幾種:

①增加光照深度圖數量:對應上面的shadow Cascades,即從不同的位置渲染多張光照深度圖,然後每次都與模型深度圖進行比對,以此增加精準度。但是每增加一張深度圖,就要把整個場景多渲染一遍,是以性能消耗也會逐漸增加。我們把shading Mode改成 Shadow Cascades 就能看到四張光照貼圖渲染的不同區域

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

②增加光照深度圖的分辨率:對應上面的Shadow Resolution,我們渲染光照深度圖的時候,實際上是給螢幕一個分辨率比如(1920*1080),然後Unity按照上面每個像素點一一擷取每個點的深度,是以增加分辨率就能增加精準度,同樣的性能消耗會增加

2、關于光照設定裡面的Bias、NormalBias

1、選中平行光,找到如下截屏的陰影設定,可以看到有Bias、NormalBias這兩個選項,我們通過調整這兩個屬性可以改變投影的“偏移”,這兩個屬性分别就是對應着UnityShader内置庫中的 “UnityApplyLinearShadowBias” 和 “UnityClipSpaceShadowCasterPos”這兩個函數

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

2、我們将設定裡面的投影資料為以下圖檔,并且把Bias和NormalBias都調整為“0”

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

我們會看到場景内的球體表面産生了一些投影,如下圖

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

我們再次調整投影設定,把Shadow Resolution調整為 High,可以看到,球體表面的投影并沒有消失,他隻是變得更密集了

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,
UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

上面這種情況我們稱之為“投影粉刺”(shadow acne)”,此時,我們隻要調整Bias和Normal的值為恰當值,這些表面投影就會消失

3、關于“投影粉刺”(shadow acne)的産生原因

我們在計算光照深度圖的時候,計算的是各個像素點所處螢幕位置的可照射深度值,這就可能會出現一種情況,我們計算得到的該點的像素點内包含多個三角片元,由于是處在同個像素點的,他們的光照深度圖中的深度是一緻的,但實際上片元的深度值是不同的,舉個栗子

PS這篇簡易草在投影中也有提到陰影粉刺的事

下面借用一下這個部落格老哥的圖

我們假設存在兩個片元A和B都處在像素點P上,像素P的深度值為0.5,A、B分别為0.49和0.51,那麼此時B就處在陰影當中,而A就是處在陰影外,但實際上B點應該也是處在陰影外的,是以我們利用Bias将A、B兩點的深度值都下移,這樣兩點都是處于陰影之外

UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,
UnityShader_再談陰影投射1、簡述Unity陰影投射原理2、關于光照設定裡面的Bias、NormalBias3、關于“投影粉刺”(shadow acne)的産生原因4、下面是Bias和NormalBias在Shader中的簡單應用,

4、下面是Bias和NormalBias在Shader中的簡單應用,

#if !defined(MY_SHADOWS_INCLUDED)
#define MY_SHADOWS_INCLUDED
#include "UnityCG.cginc"
struct appdata
{
    float4 vertex : POSITION;
    //float3 normal : NORMAL;
};
 
float4 MyShadowVertexProgram(appdata v):SV_POSITION
{   
    float4 pos = UnityObjectToClipPos(v.vertex);
    // 下面是normalBias
    // float4 pos = UnityClipSpaceShadowCasterPos(v.vertex,v.normal);
    return UnityApplyLinearShadowBias(pos);
}

half4 MyShadowFragmentProgram():SV_TARGET
{
    return 0;
}
#endif
           
Shader "Unlit/ShadowLearn"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            Tags { "RenderType"="Opaque" }
            LOD 100

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
        Pass
        {
            Tags
	        {
		        "LightMode" = "ShadowCaster"
	        }
            CGPROGRAM
            #include "MyShadows.cginc"
            #pragma vertex MyShadowVertexProgram
            #pragma fragment MyShadowFragmentProgram
            ENDCG
        }
    }
}

           

下一篇會利用上述陰影投射的原理,不使用Unity自帶的陰影計算庫,實作陰影投射

人有多少個一年,每個禮拜一晃眼就過去了,一年也就52個禮拜,别讓自己太放松了