王者榮耀的實時陰影及其原理

該文章demo下載:http://www.demodashi.com/demo/11999.html

王者榮耀的實時陰影及其原理,關於unity3d通過投影來製造一個跟實時陰影一樣的影子,很多地方都有,但是基本都是利用了unity自帶的一個組件Projector,並且對於其原理其實很少有提到過。這裏就先從理論上解釋投影陰影的實現原理,然後將過程寫出來吧。原理部分就不涉及代碼了,混在一起可能更容易讓人混亂吧。

原理:可能有點複雜,爲了簡單些,轉化爲2d視角來分析。陰影的產生正如下圖所示


由上圖可知,陰影的a點與遮擋物的b點在光照方向的垂直面上其實映射的是同一個點d。這很容易讓我們聯想到MVP當中的投影變換。其實是一樣的。我們將於光照方向當做照相機的視線,而與光照方向垂直的面,就是投影變換最後的盒子的正面。這意味着我們可以製作一個正交照相機,使得它與光照方向一致,再將地面模型的各個頂點投影到該照相機上,這時候照相機的紋理UV座標範圍是0~1,地面投影到了照相機,也將其座標映射到0~1之間,由此與照相機的紋理一一對應,於是將照相機照出來的紋理疊加在地面上,就形成了陰影。

代碼如下:

using UnityEngine;
using System.Collections;

public class Shadow : MonoBehaviour {
    [SerializeField]
    protected Camera m_Cam; //產生陰影的照相機
    [SerializeField]
    protected Shader m_ShadowShader;
    [SerializeField]
    protected GameObject m_ShadowReceiveObj;    //陰影接受物

    private RenderTexture m_RT;

	// Use this for initialization
	void Start () {
        m_RT = new RenderTexture(256, 256,16);
        m_Cam.targetTexture = m_RT;
        Material mat = new Material(m_ShadowShader);
        mat.SetTexture("_MainTex", m_RT);
        mat.SetMatrix("_WorldToCameraMatrix", m_Cam.worldToCameraMatrix);
        mat.SetMatrix("_ProjectionMatrix", m_Cam.projectionMatrix);
        m_ShadowReceiveObj.GetComponent<Renderer>().material = mat;
	}
}

上面c#代碼需要用的shader

Shader "Hidden/Shadow"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
	}
		SubShader
	{
		Tags
	{
		"Queue" = "Transparent-100"
		"RenderType" = "Transparent"
	}
		Pass
	{
		Blend SrcAlpha OneMinusSrcAlpha
		CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"
		uniform float4x4 _WorldToCameraMatrix;
		uniform float4x4 _ProjectionMatrix;

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

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

		v2f vert(appdata v)
		{
			v2f o;
			o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);

			float4 worldCoord = mul(_Object2World, v.vertex);
			float4 cameraCoord = mul(_WorldToCameraMatrix, worldCoord);
			float4 projectionCoord = mul(_ProjectionMatrix, cameraCoord);
			o.uv = projectionCoord / projectionCoord.w;
			o.uv = 0.5f*o.uv + float2(0.5f, 0.5f);
			return o;
		}

		sampler2D _MainTex;

		fixed4 frag(v2f i) : SV_Target
		{
			float dis = distance(i.uv, float2(0.5f, 0.5f));
			fixed4 col = tex2D(_MainTex, i.uv);
			if(col.r > 0 || col.g > 0 || col.b > 0)
			{
				col.a = 1.0f;
			}
			col.rgb = 0;
			col.a = (col.a - dis*1.8f)*0.6f;
			if (i.uv.y < 0.0f || i.uv.y > 1.0f || i.uv.x < 0.0f || i.uv.x > 1.0f)
			{
				discard;
			}
			return col;
		}
			ENDCG
		}
	}
}


爲了加上影子淡化效果,以上shader代碼做了處理(col.a = (col.a - dis*1.8f)*0.6f;)效果如下:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章