国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

【Unity3D】利用Shader以及更改Mesh實現2D游戲的動態陰影效果

2019-11-14 13:57:55
字體:
來源:轉載
供稿:網友

最近看到一個非常有趣的益智小游戲,是一個盜賊進入房子偷東西的,

其實這種游戲市面上已經很多了,吸引我的是那個類似手電筒的效果,

主角走到哪里,光就到哪里,被擋住的地方還有陰影。有點類似策略游戲里的戰爭迷霧。

絞盡腦汁想了一天,終于實現類似的效果,這就給大家分享下。

實現這個效果用到的技術:

1.Shader實現攝影機透明穿透效果(光照的實現)

2.代碼里動態改變mesh(陰影形狀的實現)

廢話不多說,動手。

 

--------------------------------------------------------------------------------------------

 

仔細觀察可以看出,沒被光照到的地方是灰色的,照到的地方是彩色的,而且被光照到的地方,

不僅能顯示出被光照到后的效果(彩色地面),還能顯示出一些物品,比如鑰匙,敵人等。

由此可推測,這場景應該是兩個層組成的,一個層在下,是彩色地面以及敵人等要隱藏的物品,

另一個層在上,是沒有被照亮的時候的地圖,然后根據光線進行裁剪,光線能到達的地方,就把

上層該地方裁剪掉,露出底下部分,從而實現“照亮”的效果。

因此我們先按照這種思路搭載場景:

1.題目說的是2D游戲,我這里弄成3D的,其實都所謂,最終的視覺是俯視的,其實也跟2D一樣,這里弄成這個角度是方便大家識別我的層次。

Up就是上層,其實什么都沒有,就只有一張沒被光照的時候的貼圖(我這里偷懶直接用一片灰色代替了)

Down就是下層,這里把幾乎所有元素都放滿了,玩家,敵人,墻等

 

2.接下來將各種類型的對象放到相應的層里去,方便相機篩選(這里的層跟上面提到的層不一樣,這里的層是Unity里的定義)

 

這里我為了方便大家識別,為一種類型的對象設置一個層,實際操作肯定不會這樣繁瑣的操作的,沒必要。

 

3.創建兩個相機,讓它們分別顯示對于的層。

(先無視Mask,這個待會再講)

如果設置正確,你的顯示應該跟我上圖是一樣的,并且把Up相機的Depth級別設置高點,讓它顯示在Down相機之前。

 

4.遮擋上層,顯示下層。

就是這么個原理

具體至于要怎么遮擋?我一開始想到的是UGUI的Mask組件,后來想想,這個Mask是固定的一張圖片,那么只能顯示固定的遮擋(雖然可以動態更改,但較麻煩),

后來想,那么就通過網格遮擋,畢竟網格動態改變形狀很容易,而且可以通過Shader輕易地實現遮擋效果。

具體如下,先寫這么一個Shader:

Shader "Masked/Mask" {    SubShader {        // Render the mask after regular geometry, but before masked geometry and        // transparent things.        Tags {"Queue" = "Geometry+10" }        // Don't draw in the RGBA channels; just the depth buffer        ColorMask 0        ZWrite On        // Do nothing specific in the pass:        Pass {}    }}

如果你懂Shader那么一眼就可以看懂它,不懂也無所謂,直接Copy進去。

它其實就是讓你的網格變成一個遮擋物,攝影機一看到這個網格,就會直接穿透過去,直接看到背景。

然后添加一個GameObject,并添加MeshFilter以及MeshRender組件,并且賦予這個Shader,作為Mask。

如果你這個Mask當前的Mesh不為空的話,你可以很直觀地看到它所在的地方都不會被攝影機渲染出來,

直接變成一個穿透的洞:

它不僅是透明的,還是異次元洞,就算它身后的東西也顯示不出來,直接就看到背景了。

竟然它直接穿透到背景,那么看到看不到底層,那么我們要它何用呢?

對,它只是將當期攝影機穿透到背景,所以我們將當期攝影機的Clear Flags設置為“Depth Only",這樣第一個攝影機

的背景將顯示第二個攝影機的內容。這樣就可以輕易達到我們想要的穿透。

 

5.遮擋實現了,那么該如何實現動態光照變化呢?

我這里使用的是RayCast,以主角為原點,向四周輻射一定量的射線,這樣可以模擬光照,

然后根據射線探測到的點組合成上面提到的遮擋物的網格。最終就達到我們想要的效果。

using UnityEngine;public class FOVMesh : MonoBehaviour{    // 玩家    public GameObject playerGameObject;    // 光照半徑    public float range = 3;    // 光照質量,數值越低,向四周輻射的射線越多,效果越好,但性能越低    public int levelOfDetails = 1;            // 接受光照產生陰影的對象    public LayerMask[] layerMask;                    PRivate Vector3 direction;    private int index = 0;    private int triIndex = 0;    private int lod = 1;    private float width;    private GameObject go;    private GameObject pGo;    private Mesh mesh;    private Vector3 worldPos;            private Vector3[] verts;    private int[] tris;    private Vector2[] uvs;    private GameObject didHit;    private int mask;                    // Code that runs on entering the state.    public void Start ()    {        go = gameObject;        pGo = playerGameObject;                    mesh = new Mesh ();        go.GetComponent<MeshFilter> ().mesh = mesh;                    lod = levelOfDetails;        width = range;                    // 若loa為1,則共發射360條射線作為光線,則有360個頂點加個圓心        verts = new Vector3[(360 / lod) + 1];        // 每兩個頂點跟圓心組成一個三角形,所以三角形的個數為定點數乘3        tris = new int[(360 / lod) * 3];                    uvs = new Vector2[verts.Length];        for (int i = 0; i < layerMask.Length; ++i) {            mask |= layerMask [i];        }    }            // Code that runs every frame.    public void Update ()    {        index = 0;        triIndex = 0;                    worldPos = pGo.transform.position;                    verts [index] = worldPos;                    index++;                    for (var a=0; a<360; a += lod) {            var direction = new Vector3 (Mathf.Sin (Mathf.Deg2Rad * a), 0, Mathf.Cos (Mathf.Deg2Rad * a));                            direction = direction * width;                            RaycastHit hit;                            if (Physics.Raycast (worldPos, direction, out hit, width, mask)) {                // 如果被射線探中,則將探測到的點作為網格的頂點                verts [index] = new Vector3 (hit.point.x, hit.point.y, hit.point.z);                                } else {                // 否則將射線的末端作為網格的頂點                verts [index] = new Vector3 (direction.x + worldPos.x, worldPos.y, direction.z + worldPos.z);            }                            index++;        }                    // 根據網格頂點組合三角形        for (var i=1; i<(360/lod); i++) {            tris [triIndex] = 0;            tris [triIndex + 1] = i;            tris [triIndex + 2] = i + 1;            triIndex += 3;                        }                    tris [((360 / lod) * 3) - 3] = 0;        tris [((360 / lod) * 3) - 2] = 360 / lod;        tris [((360 / lod) * 3) - 1] = 1;                    // 網格貼圖        int j = 0;        while (j < uvs.Length) {            uvs [j] = new Vector2 (verts [j].x, verts [j].z);            j++;        }                                // 重新組合網格        mesh.Clear ();        mesh.vertices = verts;        mesh.triangles = tris;        mesh.uv = uvs;        mesh.RecalculateNormals ();    }        }

 

 

最終效果如圖:

 

源碼

點我下載,歡迎轉載,轉載請注明出處

 

好吧,就在我寫完這個帖子后的一個小時,我百度了下2D偽陰影。。。然后發現了一個神物。。。

原來早就有類似的插件了,而且效果很強大,實現方法跟我這個類似,但那個還能實現光影的強弱,

遠處較暗近處較亮。

http://www.narkii.com/club/thread-358505-1.html

 

還有一個很屌的外國人寫的:

http://blog.jobbole.com/89193/

 

2016.1.15 更新

剛剛在YouTube上看到一篇教程,也是做這個的,跟我這個很像:

https://www.youtube.com/watch?v=rQG9aUWarwE

該項目資源文件

該項目GitHub源碼


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 西林县| 格尔木市| 海口市| 冀州市| 呼图壁县| 盘锦市| 四子王旗| 靖边县| 涪陵区| 嵊泗县| 清水河县| 蓝山县| 金昌市| 崇信县| 宁蒗| 石阡县| 浮梁县| 响水县| 万荣县| 安康市| 东台市| 宜良县| 应城市| 盘锦市| 海安县| 师宗县| 达尔| 宜宾县| 乌苏市| 北宁市| 西乌| 金寨县| 昌乐县| 高州市| 济宁市| 乐山市| 屏东县| 大同县| 卫辉市| 宁远县| 浦北县|