模仿王者荣耀的实时阴影

概述

该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之间,由此与照相机的纹理一一对应,于是将照相机照出来的纹理叠加在地面上,就形成了阴影。

 

三、程序实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 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大师发表,拒绝转载,转载需要作者授权

posted on   demo例子集  阅读(795)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示