最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

用Unity DOTS制作4萬飛劍的太極劍陣!

2021-05-21 15:52 作者:皮皮關(guān)做游戲  | 我要投稿

(本文作者 @對(duì)馬騎馬使用炎拳 )

大家好,我是炎拳。

Unity DOTS從發(fā)布到現(xiàn)在已經(jīng)過去兩年了,雖然距離發(fā)布正式版依舊遙遙無期,但官方放出的幾個(gè)案例所展現(xiàn)出的性能仍然令人神往,然而DOTS 相關(guān)package不同版本變動(dòng)很大,許多老的教程也已經(jīng)過時(shí),給想要探索的小伙伴制造了不少麻煩。

于是我便嘗試上手最新的DOTS,制作了這樣一個(gè)由42804把飛劍組成的炫酷劍陣,每次點(diǎn)擊地板,都會(huì)有10000把飛劍飛出大陣攻擊目標(biāo)點(diǎn)后返回。算是致敬了古龍小說中的“劍氣縱橫三萬里 ,一劍光寒十九洲”的光景(笑)。并將制作過程和學(xué)習(xí)經(jīng)歷分享出來,希望能給同樣探索DOTS的小伙伴一些參考。



文章較長(zhǎng),對(duì)準(zhǔn)備工作沒興趣的小伙伴直接跳到5~

1.創(chuàng)建工程

首先我們下載好 Unity 2020.3.3f1,選擇 Universal Render Pipeline 創(chuàng)建工程。

DOTs的相關(guān)package并未發(fā)布,也無法在 Package Manager中搜索到,我們需要手動(dòng)去下載這幾個(gè)包。

2.下載Dots相關(guān)包

打開上方菜單欄,點(diǎn)擊在左上角+號(hào)圖標(biāo)選擇Add package from git URL,依次輸入:

  • com.unity.entities

  • com.unity.rendering.hybrid

  • com.unity.physics

等待一會(huì)兒包就下載好了,但我們的準(zhǔn)備工作還沒做完。

3.動(dòng)態(tài)合批設(shè)置

由于我們將要生成大量相同材質(zhì)的飛劍,所以將他們合批處理降低Drawcall是有必要的。

首先點(diǎn)擊Edit >ProjectSetting>Quality>查看當(dāng)前使用的Rendering設(shè)置文件,關(guān)閉SRP Batcher:

再新建一個(gè)材質(zhì),勾選Enable GPU Instancing。

你就會(huì)發(fā)現(xiàn)Unity將擁有同一此材質(zhì)的物體合批渲染了:

值得一提的是,本工程中的飛劍已經(jīng)被我用Blender手動(dòng)將頂點(diǎn)數(shù)降低到105個(gè)了,因?yàn)槲易詈蟠笾乱?萬把飛劍,原本的飛劍模型有上千個(gè)頂點(diǎn),龐大的定點(diǎn)數(shù)會(huì)導(dǎo)致我的場(chǎng)景近乎卡死,最后測(cè)試我的電腦能頂住的最大頂點(diǎn)數(shù)大概是10M左右。

4. 制作飛劍發(fā)光效果

我希望每把飛劍都有一個(gè)發(fā)出淡淡光暈的效果,在2020.3.3版本的URP工程中,Unity已將Post Processing Package默認(rèn)置入,所以我們無需像老版本一樣去自己下載Post-Processing package包。直接使用就可以了。

首先新建一個(gè)材質(zhì)球,勾選了Emission后扔給飛劍,并在場(chǎng)景中右鍵新建一個(gè)Global Volume,這:

同時(shí)點(diǎn)擊主相機(jī),勾選solider color,選擇一個(gè)偏黑色的顏色,再將Post processing勾選上

我們的場(chǎng)景中不需要天空盒,所以點(diǎn)擊Window>Rendering>Lighting>Environment,將天空盒材質(zhì)設(shè)置為None

最后我希望后處理效果只對(duì)指定層級(jí)的物體起作用,這里需要Global volume和物體設(shè)置為相同層級(jí),并且在主相機(jī)中指定該層級(jí):

最后新建一個(gè)配置文件,點(diǎn)擊Add Override,并添加bloom效果即可。



準(zhǔn)備工作做完了,終于要進(jìn)入實(shí)踐環(huán)節(jié)了,本文就不贅述DOTS相關(guān)的概念了,網(wǎng)上關(guān)于DOTS介紹的文章很多,官方文檔對(duì)于DOTS闡述也算是詳盡,這里我放個(gè)鏈接,對(duì)DOTS不了解的小伙伴可以先理解了這些概念后再來實(shí)踐:

官方文檔:

Entity Component Systemdocs.unity3d.com

5.生成太極圖案的飛劍群實(shí)體

首先找到一張?zhí)珮O八卦陣的圖案,然后掐太極法?。「吆艨谠E:

天地?zé)o極,乾坤借法!

太乙天尊,急急如律令!

然后就發(fā)現(xiàn)圖片白色部分都變成透明的了!

接下來我們需要獲取圖片中每個(gè)像素點(diǎn)的位置,然后等比轉(zhuǎn)換到unity空間中去,讓飛劍去填充這些位置。所以圖片也不能太大,這里我們導(dǎo)入的時(shí)候在Unity中設(shè)置就好了:

代碼如下:



位置拿到了,接下來需要根據(jù)位置生成大量飛劍,并將飛劍轉(zhuǎn)換為Entity,我們可以選擇給飛劍的預(yù)制體添加Convert To Entity 腳本的方法進(jìn)行轉(zhuǎn)換:

但點(diǎn)開Convert To Entity查看,發(fā)現(xiàn)它也是繼承了MonoBehaviour,很明顯它不會(huì)自己在編輯器中轉(zhuǎn)換好,所以我們需要在運(yùn)行的過程中將飛劍的預(yù)制體轉(zhuǎn)換為Entity,代碼如下:



再按位置生成飛劍Entity,順便打印出來飛劍的數(shù)量:


?


然后運(yùn)行場(chǎng)景按W,在默認(rèn)BurstCompliler和Job threads開啟的情況下,可以看到飛劍迅速生成到了場(chǎng)景中央,并且沒有一點(diǎn)卡頓:

6.調(diào)試Entity

每個(gè)Entity是無法顯示在Hierarchy視窗中進(jìn)行調(diào)試的,Unity提供了一個(gè)工具用來分析,依次點(diǎn)擊:Window>Analysis>Entity Debugger,就可以在Entity Debugger中查看每個(gè)Entity具體包含的Component,以及對(duì)應(yīng)屬性值的變化:

圖中我們可以看到,列表長(zhǎng)度為42802,但Entity的數(shù)量生成了2倍多,這是因?yàn)轱w劍的預(yù)制體中包含一個(gè)子物體,轉(zhuǎn)換過程中EntityManager會(huì)將物體的子物體一同轉(zhuǎn)換為Entity。

你也可以點(diǎn)擊filter,通過篩選Component的方式來尋找想要查看的Entity,左邊的系統(tǒng)列表顯示了項(xiàng)目中的系統(tǒng)以及系統(tǒng)運(yùn)行每個(gè)框架所花費(fèi)的時(shí)間。你可以使用為每個(gè)系統(tǒng)提供的復(fù)選框從列表中打開和關(guān)閉系統(tǒng),來進(jìn)行調(diào)試。

7.劍陣圍繞中心旋轉(zhuǎn)

飛劍已經(jīng)生成了,接下來就需要?jiǎng)?chuàng)建一個(gè)System來更新這些Entity,讓他們旋轉(zhuǎn)起來。

首先定義一個(gè)Component添加到預(yù)制體上,這個(gè)Component的作用是一個(gè)標(biāo)簽:



然后新建一個(gè)System,繼承SystemBase基類,需要注意的是JobComponentSystem和ComponentSystem這兩個(gè)基類將會(huì)被摒棄,(Entities 0.17.0 package文檔中官方明確已經(jīng)明確表示),SystemBase將會(huì)是System唯一的基類,所以建議盡量使用SystemBase。

接著實(shí)現(xiàn)System接口,通過Entitie.ForEach方法篩選出Sword Entity,并更新位置 :



Unity ECS會(huì)自動(dòng)在系統(tǒng)中發(fā)現(xiàn)系統(tǒng)類,點(diǎn)擊運(yùn)行場(chǎng)景,飛劍此時(shí)已經(jīng)可以沿中心點(diǎn)旋轉(zhuǎn)了:

8.飛劍出陣和歸陣

接下來是整個(gè)劍陣最核心的功能,在實(shí)現(xiàn)的過程中我也實(shí)踐了兩種思路:

第一種思路是:

點(diǎn)擊下方廣場(chǎng),獲取射線與廣場(chǎng)碰撞點(diǎn)的位置,創(chuàng)建Tag2組件如下



創(chuàng)建 System1,在System1中遍歷不帶Tag2的飛劍,抽取10000把飛劍,添加Tag2,同時(shí)創(chuàng)建10000個(gè)TempEntity替代其繼續(xù)旋轉(zhuǎn)。Tag2存取位置和對(duì)應(yīng)Tempentity信息。 創(chuàng)建System2 ,在System2中遍歷所有帶Tag2的飛劍,令其出陣飛向目標(biāo)點(diǎn)。 在System2中遍歷所有帶Tag2的飛劍,當(dāng)System2中的飛劍非常接近目標(biāo)點(diǎn),則移除Tag2,添加Tag3。 創(chuàng)建System3,在System3中遍歷所有帶Tag3的飛劍歸陣,追趕上自己對(duì)應(yīng)的Tempentity,之后銷毀掉對(duì)應(yīng)的Tempentity。

這個(gè)方案有這樣2個(gè)問題:

1.System之間執(zhí)行順序問題

所有繼承SystemBase,實(shí)現(xiàn)的OnUpdate()方法的System都是在主線程上跑的,因此我們可以很方便的規(guī)劃System1,2,3的執(zhí)行順序,代碼如下:



2.EntityCommandBuffer時(shí)序問題

在ECS中,所有的Entity都是按塊(Chunk)存儲(chǔ)的,一個(gè)塊里的所有實(shí)體必定擁有相同數(shù)量和類型的組件,一旦某個(gè)實(shí)體的組件數(shù)量或類型改變了,它就不屬于當(dāng)前的塊,它會(huì)被移到其他塊里,這個(gè)操作在主線程中運(yùn)行并沒有什么問題。

但我希望能發(fā)揮cpu全部的性能來運(yùn)行這個(gè)劍陣,所以需要去分配一些任務(wù)到子線程中執(zhí)行,JobSystem幫我們解決了這個(gè)問題,它屏蔽了直接對(duì)線程的操作,而是把異步邏輯封裝成一個(gè)個(gè)“Job”,由引擎來調(diào)度和分配給合適的線程去執(zhí)行,官方實(shí)例代碼在這:

https://docs.unity3d.com/ScriptReference/Unity.Jobs.IJob.html

除了上面的方法使用JobSystem,ECS提供SystemBase類 中常用的Entities.ForEach方法也可以將數(shù)據(jù)轉(zhuǎn)換到子線程處理,我們可以使用Schedule()或者ScheduleParallel()來執(zhí)行Job的lambda方法:



這時(shí)候,假設(shè)Job1中刪除了某個(gè)實(shí)體的組件,該實(shí)體被移到其他chunk,而它并行的Job2也在對(duì)這個(gè)實(shí)體進(jìn)行操作,就會(huì)產(chǎn)生沖突(操作不存在的組件或者操作了錯(cuò)誤塊里的實(shí)體),所以Job2必須等待Job1讀寫數(shù)據(jù)完畢,這就是硬性同步點(diǎn)(Sync points)。

以下導(dǎo)致結(jié)構(gòu)變化的操作,都會(huì)產(chǎn)生硬性的同步點(diǎn):

  • 創(chuàng)建實(shí)體

  • 刪除實(shí)體

  • 向?qū)嶓w添加組件

  • 從實(shí)體中刪除組件

  • 更改共享組件中的值

每個(gè)同步點(diǎn)都會(huì)都會(huì)造成停頓,等待當(dāng)前World中所有先前安排的作業(yè)完成。過多的同步點(diǎn)會(huì)讓效率大大降低,但以上的操作還是無法避免的,為了解決這種問題,Unity提供了EntityCommandBuffer(實(shí)體命令緩沖區(qū),簡(jiǎn)稱ECB)來解決這個(gè)問題。

ECB可以將導(dǎo)致結(jié)構(gòu)性更改的命令排入隊(duì)列,存儲(chǔ)在ECB中的命令可以在一幀中晚些時(shí)候回放執(zhí)行。當(dāng)回放ECB時(shí),這會(huì)將跨幀分布的多個(gè)同步點(diǎn)減少到單個(gè)同步點(diǎn)。下面這個(gè)案例是使用系統(tǒng)自帶的ECB,這樣可以最大程度的減少同步點(diǎn):



這樣,飛劍添加Component,創(chuàng)建臨時(shí)的entity的操作好像都沒啥問題了,但實(shí)際運(yùn)行起來時(shí)會(huì)發(fā)現(xiàn)飛劍并沒有飛回原定的位置,明顯比原先劍陣慢了一幀:

前面也說到了,EntityCommandBuffer中的命令不會(huì)立即執(zhí)行,而是會(huì)在下一幀被EntityCommandBufferSystem使用,有一幀延遲。我們生成替代出陣飛劍的entity,在下一幀才會(huì)真正的生成并跟隨劍陣旋轉(zhuǎn),所以飛劍最后和entity同步的位置也自然是慢了一幀。目前的解決辦法是多計(jì)算一幀的距離,但這樣做既麻煩又有誤差,所以我們換一種簡(jiǎn)單的思路。

對(duì)與EntityCommandBuffer時(shí)序問題有疑惑的小伙伴可以看這篇文章:

https://zhuanlan.zhihu.com/p/328218005


思路2:

生成TempEntity 和飛劍在八卦陣中,為飛劍添加Tag1組件,記錄相同位置的TempEntity


創(chuàng)建System1,遍歷所有TempEntity,使它們沿中心旋轉(zhuǎn)。 創(chuàng)建System2,遍歷所有無Tag2組件的飛劍,并且每幀和對(duì)應(yīng)TempEntity位置同步。 (System2中執(zhí)行)若發(fā)生點(diǎn)擊事件,則抽取10000把飛劍添加Tag2,Tag2記錄目標(biāo)點(diǎn)位置。


創(chuàng)建System3,遍歷所有帶Tag2的飛劍,使其前往目標(biāo)點(diǎn)。 (System3中執(zhí)行)接近目標(biāo)點(diǎn)時(shí),將飛劍對(duì)應(yīng)的TempEntity的位置作為新目標(biāo)位置,飛劍開始返回陣中。 (System3中執(zhí)行)在非常接近TempEntity時(shí),刪除Tag2,飛劍和對(duì)應(yīng)的TempEntity位置同步,歸陣完畢。

主要代碼如下:

System1:


System2:


System3:


然后在主線程中生成飛劍和TempEntity就可以了,需要注意的是,場(chǎng)景中的地面也需要轉(zhuǎn)換為Entity,并且添加上Physic相關(guān)組件。其他的代碼就不放了,感興趣的小伙伴可以下載工程玩下,我放在文章末尾了。最后我們來看下俯視角效果:

我的電腦是i5-7500四核+GTX1050,場(chǎng)景中有12萬8千個(gè)實(shí)體,正常運(yùn)行能跑85fps,一萬把飛劍出陣也能保持在60左右:

文章到這就結(jié)束了,回顧下來,踩的坑非常多,希望這篇文章能給小伙伴提供幫助,也期待大佬指正!

對(duì)于GameObject轉(zhuǎn)換為Entity流程感興趣的同學(xué),可以移步這篇文章:

https://zhuanlan.zhihu.com/p/157919373

官方文檔鏈接:https://docs.unity3d.com/Packages/com.unity.entities@0.1/manual/index.html

工程地址:

https://github.com/ydwj/Unity-ECS-TaiJi-Swords-Array



歡迎加入游戲開發(fā)群歡樂攪基:1082025059

對(duì)游戲開發(fā)感興趣的童鞋可戳這里進(jìn)一步了解:http://www.levelpp.com/

我們的公眾號(hào):“皮皮關(guān)"

B站:“皮皮關(guān)做游戲”




用Unity DOTS制作4萬飛劍的太極劍陣!的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
上虞市| 洪雅县| 合江县| 灵璧县| 高青县| 崇文区| 英吉沙县| 阜新市| 天气| 宜良县| 温泉县| 万山特区| 尼玛县| 镇原县| 冷水江市| 称多县| 陆河县| 仁化县| 桂阳县| 增城市| 略阳县| 青海省| 读书| 定州市| 黄梅县| 星子县| 多伦县| 来宾市| 高密市| 娄烦县| 蕲春县| 宜都市| 孙吴县| 和硕县| 榆林市| 韩城市| 郎溪县| 民乐县| 平谷区| 抚远县| 余庆县|