Unity:ECS的核心概念

來(lái)源:Unity官方平臺(tái)
作者:鄭洪智
時(shí)間:2020-12-21
5501
ECS架構(gòu)的核心是數(shù)據(jù),這也是為什么Unity會(huì)將這一套技術(shù)棧命名為DOTS。System會(huì)讀取entity上面的component的數(shù)據(jù)流,并處理數(shù)據(jù)。實(shí)體在這里其實(shí)更像是索引,它本身并不包含任何數(shù)據(jù)和邏輯。

ECS架構(gòu)的核心是數(shù)據(jù),這也是為什么Unity會(huì)將這一套技術(shù)棧命名為DOTS。System會(huì)讀取entity上面的component的數(shù)據(jù)流,并處理數(shù)據(jù)。實(shí)體在這里其實(shí)更像是索引,它本身并不包含任何數(shù)據(jù)和邏輯。

ECS包含三個(gè)部分:實(shí)體(entities)、數(shù)據(jù)(components)、行為(system)。具體看下圖:

ia_4300000008.jpg

這個(gè)圖中,System讀取了多個(gè)實(shí)體的Translation和Rotation組件,然后經(jīng)過(guò)計(jì)算處理,將結(jié)果更新到LocalToWorld組件中。

從圖中你可以看到,實(shí)體A和B還有Renderer組件,但是C并沒(méi)有。不過(guò)這并不會(huì)影響System的計(jì)算邏輯,因?yàn)檫@個(gè)系統(tǒng)不關(guān)心Renderer組件。

你還可以寫一個(gè)系統(tǒng),需要處理Renderer組件,這樣系統(tǒng)就會(huì)忽略實(shí)體C。你還可以寫一個(gè)系統(tǒng)排除包含Renderer組件的實(shí)體,這樣系統(tǒng)就會(huì)忽略實(shí)體A和B。

下面對(duì)ECS中比較重要的幾個(gè)核心概念做一個(gè)梳理:

原型 Archetypes

多個(gè)組件的組合叫做一個(gè)原型。

比如一個(gè)3D物體可能會(huì)包含用于transform的組件,包括移動(dòng)、旋轉(zhuǎn)、渲染,每個(gè)3D物體對(duì)應(yīng)一個(gè)實(shí)體,但是他們都有同樣的組件,所以ECS會(huì)把他們分類成是一類原型。

ia_4300000009.jpg

在上圖中,實(shí)體A和B的原型都是M,實(shí)體C的原型是N。

你也可以通過(guò)在運(yùn)行時(shí)添加或者移除component來(lái)改變一個(gè)實(shí)體的原型。例如:如果將實(shí)體B的Renderer組件移除,實(shí)體B的原型就會(huì)變成N。

內(nèi)存塊 Memory Chunks

為什么要先講原型的概念呢,因?yàn)橐粋€(gè)實(shí)體的原型是什么,決定了ECS會(huì)將實(shí)體的components也就是數(shù)據(jù)存在什么地方。ECS按塊分配內(nèi)存,每塊用一個(gè)ArchetypeChunk對(duì)象表示。

一個(gè)塊只包含一種原型,可以包含的多個(gè)實(shí)體的數(shù)據(jù)。如果一個(gè)塊的內(nèi)存滿了,ECS會(huì)分配一個(gè)新的塊來(lái)存儲(chǔ)新的實(shí)體的components。

如果你修改了實(shí)體的組件,那就相當(dāng)于修改了實(shí)體的原型,這時(shí)候ECS會(huì)將實(shí)體的組件數(shù)據(jù)移到另外一個(gè)塊中。

ia_4300000010.jpg

原型和內(nèi)存塊的關(guān)系是一對(duì)多的關(guān)系。這就意味著,如果想查詢給定的一組component類型的所有實(shí)體,只需要在這些原型中搜索即可。這樣會(huì)比在所有的實(shí)體中查找效率高很多。

ECS在存儲(chǔ)實(shí)體到內(nèi)存塊中沒(méi)有特殊的排序,當(dāng)創(chuàng)建一個(gè)實(shí)體或者實(shí)體的原型發(fā)生變化時(shí),ECS會(huì)將它放到對(duì)應(yīng)原型的第一個(gè)還有空間的內(nèi)存塊中。內(nèi)存塊中的數(shù)據(jù)會(huì)緊密排列。如果一個(gè)實(shí)體要被移出當(dāng)前原型的內(nèi)存塊,這時(shí)候會(huì)有個(gè)空位,ECS會(huì)把這個(gè)內(nèi)存塊最后的實(shí)體數(shù)據(jù)移動(dòng)到這個(gè)空位中。

注意:原型中的共享組件(后面會(huì)具體說(shuō)這是個(gè)什么東東)的數(shù)據(jù)也會(huì)影響實(shí)體會(huì)被存在哪個(gè)內(nèi)存塊。同一個(gè)內(nèi)存塊中的所有實(shí)體的共享組件中的數(shù)據(jù)值都是相同的。如果你修改了共享組件中的數(shù)據(jù),這個(gè)實(shí)體會(huì)被移到另外一個(gè)塊中,有點(diǎn)類似修改了實(shí)體的原型。

將共享組件的實(shí)體分到一個(gè)內(nèi)存塊中會(huì)提高處理他們的速度。比如Hybird Renderer(混合渲染)定義了RenderMesh組件來(lái)達(dá)成這個(gè)目的。

實(shí)體查詢

一個(gè)System根據(jù)什么來(lái)決定處理哪些實(shí)體呢?這時(shí)候會(huì)用到一個(gè)叫實(shí)體查詢(Entity Query)的東西。實(shí)體查詢首先需要一些組件類型,然后根據(jù)你傳入的組件類型的組合,在包含這些組件的原型中查詢符合要求的實(shí)體。查詢時(shí)可以指定下面三種類型:

All 必須包含All中所有的組件類型

Any 必須包含Any中至少一個(gè)組件類型

None 不能包含None中任意一個(gè)組件類型

一次實(shí)體查詢的結(jié)果會(huì)返回所有符合查詢要求的內(nèi)存塊,你可以使用IJobChunk來(lái)迭代遍歷所有的組件。(IJobChunk后面會(huì)講。)

Jobs 作業(yè)

之前說(shuō)過(guò),ECS配合Job使用才能發(fā)揮多線程的威力。ECS提供了SystemBase類,其中包含Entities.ForEach方法,還包含了IJobChunk的Schedule()和ScheduleParallel()方法,可以在子線程中處理數(shù)據(jù)。Entities.ForEach是最簡(jiǎn)單的方法,只需要幾行代碼就能實(shí)現(xiàn)。IJobChunk可以用來(lái)處理比較復(fù)雜的情況。

ECS會(huì)在主線程調(diào)度Job,根據(jù)System的順序。當(dāng)job調(diào)度后,ECS會(huì)追蹤哪些job在讀寫哪些組件。需要讀權(quán)限的job需要等待前面寫權(quán)限的job執(zhí)行完,反之亦然。Job調(diào)度器會(huì)使用job依賴來(lái)決定哪些job可以并行,哪些必須串行。

System的組織

ECS通過(guò)World和group來(lái)組織system。默認(rèn)情況下,ECS會(huì)創(chuàng)建一個(gè)默認(rèn)的World,包含一些預(yù)定義的group組。它會(huì)找到工程中所有的System,實(shí)例化他們,并添加到預(yù)定義的group中。

你可以指定同一個(gè)group中system的Update的執(zhí)行順序。Group也是一種system,所以你可以將一個(gè)group添加到另外一個(gè)group中。如果你沒(méi)有指定順序,system的執(zhí)行順序會(huì)不太確定,并不會(huì)按照它們創(chuàng)建的順序。不過(guò),同一個(gè)group中的所有system都會(huì)比下一個(gè)group中的system先執(zhí)行。

System的Update是在主線程中執(zhí)行的,不過(guò)可以使用Job將工作分配到子線程中。

ECS世界的可視化創(chuàng)建(authoring)

在Unity中沒(méi)辦法直接可視化地創(chuàng)建DOTS世界,但是,可以先用GameOjbect和MonoBehaviour來(lái)創(chuàng)建,然后通過(guò)轉(zhuǎn)換系統(tǒng)將GameObject轉(zhuǎn)換成實(shí)體和組件。這個(gè)我們后面也會(huì)細(xì)講。

來(lái)源:Unity官方平臺(tái)

原文:https://mp.weixin.qq.com/s/Tvtqz51Np7vWeYwKcQtHdQ

立即登錄,閱讀全文
原文鏈接:點(diǎn)擊前往 >
文章來(lái)源:Unity官方平臺(tái)
版權(quán)說(shuō)明:本文內(nèi)容來(lái)自于Unity官方平臺(tái),本站不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。文章內(nèi)容系作者個(gè)人觀點(diǎn),不代表快出海對(duì)觀點(diǎn)贊同或支持。如有侵權(quán),請(qǐng)聯(lián)系管理員(zzx@kchuhai.com)刪除!
掃碼關(guān)注
獲取更多出海資訊的相關(guān)信息
優(yōu)質(zhì)服務(wù)商推薦
更多
掃碼登錄
打開(kāi)掃一掃, 關(guān)注公眾號(hào)后即可登錄/注冊(cè)
加載中
二維碼已失效 請(qǐng)重試
刷新
賬號(hào)登錄/注冊(cè)
個(gè)人VIP
小程序
快出海小程序
公眾號(hào)
快出海公眾號(hào)
商務(wù)合作
商務(wù)合作
投稿采訪
投稿采訪
出海管家
出海管家