• 模仿王者荣耀的实时阴影


    概述

    该demo是模仿王者荣耀的实时阴影,读者可以从中理解到实时阴影的实现原理。

    详细

    一、准备工作

    解压ShadowDemo.zip压缩包,用Unity 5.3.7f1 (64-bit)及以上版本打开项目,打开Demo场景,就可以测试了。以下为压缩包的结构:

    QQ截图20171127135218.png

    二、实现原理

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

    20170227143031726.png

    由上图可知,阴影的a点与遮挡物的b点在光照方向的垂直面上其实映射的是同一个点d。这很容易让我们联想到MVP当中的投影变换。其实是一样的。我们将于光照方向当做照相机的视线,而与光照方向垂直的面,就是投影变换最后的盒子的正面。这意味着我们可以制作一个正交照相机,使得它与光照方向一致,再将地面模型的各个顶点投影到该照相机上,这时候照相机的纹理UV坐标范围是0~1,地面投影到了照相机,也将其坐标映射到0~1之间,由此与照相机的纹理一一对应,于是将照相机照出来的纹理叠加在地面上,就形成了阴影。

    三、程序实现

    using UnityEngine;
    using System.Collections;
    
    public class Shadow : MonoBehaviour {
        public Camera m_ShadowCamera;
        private RenderTexture m_RT;
        public Material m_Mat;
        
        void Start()
        {
        //创建一个纹理,用来捕获照相机的看到的(该纹理既为我们需要的影子的源纹理)
            m_RT = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32);
            m_RT.anisoLevel = 8;
            m_ShadowCamera.targetTexture = m_RT;
            //将上面的纹理传入材质球中,用来将它处理为影子
            m_Mat.SetTexture("_MainTex", m_RT);
        }
    
        void Update()
        {
        //实时将生成影子需要的纹理的照相机的矩阵传入材质球,这两个矩阵在下面的着色器代码中使用
            m_Mat.SetMatrix("_WorldToCameraMatrix", m_ShadowCamera.worldToCameraMatrix);
            m_Mat.SetMatrix("_ProjectionMatrix", m_ShadowCamera.projectionMatrix);
        }
    }

    上面c#代码需要用的shader

    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    
    // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    
    Shader "Hidden/Shadow"
    {
    	Properties
    	{
    		_MainTex("Texture", 2D) = "white" {}
    	}
    		SubShader
    	{
    		Tags
    	{
    		"Queue" = "Transparent+100"
    	}
    	zwrite off
    		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 = (i.uv.x - 0.5f)*(i.uv.x - 0.5f) + (i.uv.y - 0.5f)*(i.uv.y - 0.5f);
    			fixed4 col = tex2D(_MainTex, i.uv);
    			if(col.r + col.g + col.b + col.a > 0)
    			{
    				col.a = 1.0f;
    			}
    			col.rgb = 0;
    			//这里将纹理沿着边缘虚幻处理
    			col.a = (col.a - dis*4.0f)*0.3f;
    			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
    		}
    	}
    }

    王者荣耀的阴影做了一个细节上的处理,所以我在这里也做了同样的处理,既阴影往边界虚化的效果。

    三、运行效果

    QQ截图20171127142334.pngQQ截图20171127142341.png

    四、项目截图

    3r.jpg

    注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

  • 相关阅读:
    WPF Caliburn 学习笔记(五)HelloCaliburn
    MSDN 教程短片 WPF 20(绑定3ObjectDataProvider)
    MSDN 教程短片 WPF 23(3D动画)
    比赛总结一
    HDU3686 Traffic Real Time Query System
    HDU3954 Level up
    EOJ382 Match Maker
    UESTC1565 Smart Typist
    HDU3578 Greedy Tino
    ZOJ1975 The Sierpinski Fractal
  • 原文地址:https://www.cnblogs.com/demodashi/p/8491137.html
Copyright © 2020-2023  润新知