天天看点

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个礼拜,别让自己太放松了