王者荣耀的实时阴影及其原理

该文章demo下载:http://www.demodashi.com/demo/11999.html

王者荣耀的实时阴影及其原理,关于unity3d通过投影来制造一个跟实时阴影一样的影子,很多地方都有,但是基本都是利用了unity自带的一个组件Projector,并且对于其原理其实很少有提到过。这里就先从理论上解释投影阴影的实现原理,然后将过程写出来吧。原理部分就不涉及代码了,混在一起可能更容易让人混乱吧。

原理:可能有点复杂,为了简单些,转化为2d视角来分析。阴影的产生正如下图所示

王者荣耀的实时阴影及其原理_第1张图片

由上图可知,阴影的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().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;)效果如下:

王者荣耀的实时阴影及其原理_第2张图片

你可能感兴趣的:(unity)