平面陰影

前言:

陰影的實(shí)現(xiàn)方式之一是平面陰影壕鹉,也就是假陰影,這種陰影適合應(yīng)用到平面上你踩,不適合不規(guī)則物體上(會(huì)穿幫)歉闰。但是這種陰影效率更高,因?yàn)楦静恍枰?jì)算真實(shí)的光照與陰影信息,也是目前多數(shù)手游公司采用的一種陰影方案之一(王者榮耀等一大批)。

原理:

  • 因?yàn)橐谄矫嫔夏M物體陰影,所以如果將投影光源與目標(biāo)物體變換到平面坐標(biāo)系中萌朱,然后根據(jù)相似三角形定理得到目標(biāo)物體投影到平面的模型坐標(biāo)空間中,并把目標(biāo)的y軸壓扁在平面坐標(biāo)系中呆贿,然后給要投影的物體一個(gè)陰影顏色嚷兔,就可以得到類似陰影的效果。
  • 這種計(jì)算方法同時(shí)適合點(diǎn)光源與平行光做入,因?yàn)橐谄矫婵臻g中應(yīng)用三角形相似原理進(jìn)行計(jì)算物體的投影點(diǎn)冒晰,所以需要兩個(gè)uniform矩陣float4x4 WorldToGround與float4x4 GroundToWorld矩陣。這兩個(gè)矩陣顧名思義分別將目標(biāo)物體從世界坐標(biāo)系轉(zhuǎn)換到平面(地面)坐標(biāo)系與從平面(地面)坐標(biāo)系轉(zhuǎn)換到世界坐標(biāo)系竟块。從外部應(yīng)用GetCompent<Renderer>()獲取相應(yīng)矩陣傳入shader即可壶运。
  • 在頂點(diǎn)著色器中將光線與物體頂點(diǎn)坐標(biāo)變換到平面坐標(biāo)空間,然后根據(jù)三角形相似定理得到平面頂點(diǎn)坐標(biāo)值浪秘,然后將坐標(biāo)值的y值指定為0蒋情,以點(diǎn)光源為例,相關(guān)計(jì)算代碼如下:
//點(diǎn)光源
                float4 pointLightGroundPos = mul(World2Ground,pointLightWorldPos);
                float3 lightDir;
                float4 vt;
                vt = mul(unity_ObjectToWorld,v.vertex);
                vt = mul(World2Ground,vt);
                lightDir = normalize((vt-pointLightGroundPos).xyz);
                vt.xz = vt.xz - (lightDir.xz * vt.y)/lightDir.y;
                vt.y = 0;
  • 將目標(biāo)物體從平面坐標(biāo)系中變換到世界坐標(biāo)系耸携,然后再用unity_WorldToObject變換到自身的模型坐標(biāo)系中棵癣,最后用UnityObjectToClipPos(v.vertex)得到在裁剪標(biāo)準(zhǔn)坐標(biāo)系中。
  • 這樣得到的結(jié)果有點(diǎn)問題就是精度造成的Z-fighting夺衍,用Offset -1狈谊,0給一個(gè)小的偏移即可;或者另外一種方式為最后渲染陰影并關(guān)閉深度測試ztest off沟沙。
  • 另外河劝,為了保證陰影一直在平面上,而不會(huì)出現(xiàn)在平面外部矛紫,可以使用stencil狀態(tài)指令赎瞎,在地面渲染像素的區(qū)域內(nèi)才通過模板測試,當(dāng)然需要在渲染地面的shader中給地面渲染過的像素對應(yīng)的模板緩存值更改為1颊咬,如下:
地面:
Stencil {
        Ref 1
            Comp always
        Pass replace
}
目標(biāo)物體:
Stencil{
    Ref 1
    Comp equal
}
  • 陰影一般有透明效果务甥,可以使用blend狀態(tài)實(shí)現(xiàn)牡辽。
  • 最終代碼:
Shader "FFD/MyPlanerShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderQueue" = "Transparent"}
        LOD 100

        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "unitycg.cginc"
            #include "lighting.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };

            v2f vert(appdata_base v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                o.normal = mul(v.normal,(float3x3)unity_WorldToObject);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex,i.uv);
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                float3 normal = normalize(i.normal);
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.xyz * saturate(dot(normal,lightDir));

                return fixed4(col.xyz*(ambient+diffuse),1);
            }

            ENDCG
        }


        Pass
        {
            Tags{"LightMode" = "ForwardBase" }
            Blend SrcAlpha OneMinusSrcAlpha 
            Offset -1,0
            Stencil{
                Ref 1
                Comp equal
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
        
            
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            uniform float4x4 World2Ground;
            uniform float4x4 Ground2World;
            uniform float4 MainColor;
            uniform float4 pointLightWorldPos;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                //平行光
//              float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//              lightDir = mul((float3x3)World2Ground,lightDir);
//              lightDir = normalize(lightDir);

                //點(diǎn)光源
                float4 pointLightGroundPos = mul(World2Ground,pointLightWorldPos);
                float3 lightDir;
                float4 vt;
                vt = mul(unity_ObjectToWorld,v.vertex);
                vt = mul(World2Ground,vt);
                lightDir = normalize((vt-pointLightGroundPos).xyz);
                vt.xz = vt.xz - (lightDir.xz * vt.y)/lightDir.y;
                vt.y = 0;
                o.vertex = mul(Ground2World,vt);
                o.vertex = mul(unity_WorldToObject,o.vertex);
                o.vertex = UnityObjectToClipPos(o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                col = fixed4(0.3,0.3,0.3,0.3);
                return col;
            }
            ENDCG
        }
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市敞临,隨后出現(xiàn)的幾起案子催享,更是在濱河造成了極大的恐慌,老刑警劉巖哟绊,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異痰憎,居然都是意外死亡票髓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門铣耘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洽沟,“玉大人,你說我怎么就攤上這事蜗细●刹伲” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵炉媒,是天一觀的道長踪区。 經(jīng)常有香客問我,道長吊骤,這世上最難降的妖魔是什么缎岗? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮白粉,結(jié)果婚禮上传泊,老公的妹妹穿的比我還像新娘。我一直安慰自己鸭巴,他們只是感情好眷细,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鹃祖,像睡著了一般溪椎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惯豆,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天池磁,我揣著相機(jī)與錄音,去河邊找鬼楷兽。 笑死地熄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芯杀。 我是一名探鬼主播端考,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼雅潭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了却特?” 一聲冷哼從身側(cè)響起扶供,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎裂明,沒想到半個(gè)月后椿浓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闽晦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年扳碍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仙蛉。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡笋敞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荠瘪,到底是詐尸還是另有隱情夯巷,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布哀墓,位于F島的核電站趁餐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏篮绰。R本人自食惡果不足惜澎怒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阶牍。 院中可真熱鬧喷面,春花似錦、人聲如沸走孽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磕瓷。三九已至盒齿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間困食,已是汗流浹背边翁。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留硕盹,地道東北人符匾。 一個(gè)月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像瘩例,于是被迫代替她去往敵國和親啊胶。 傳聞我的和親對象是個(gè)殘疾皇子甸各,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容