国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于UNITY三維虛擬仿真的內存優(yōu)化研究

2022-08-22 13:40汪華健汪志鋒
計算機仿真 2022年7期
關鍵詞:攝像機視野內存

汪華健,汪志鋒

(上海第二工業(yè)大學工學部,上海 201209)

1 引言

Unity引擎由Unity Technologies 開發(fā),是一個能夠多平臺開發(fā)的綜合型專業(yè)游戲引擎。其從2005年發(fā)布到今天的十幾年的時間里,Unity 游戲引擎已經(jīng)演變成一個方便易用的、可跨平臺的高度集成開發(fā)環(huán)境,成為游戲市場的主流的開發(fā)引擎之一[1]。隨著Unity愈發(fā)火熱,Unity引擎在三維視頻游戲、建筑可視化、實時三維動畫、仿真系統(tǒng)開發(fā)等各個方面都有著廣泛的應用。

隨著Unity應用越來越廣泛,Unity在進行開發(fā)時也發(fā)現(xiàn)一些問題,如使用Unity引擎對大型三維場景進行處理時,經(jīng)常出現(xiàn)卡頓、內存不足等問題;針對這些問題,學者們也開始針對Unity內存管理機制中進行一些研究,并提出了在編程方式、三維模型管理以及動態(tài)內存加載機制等幾個方面的優(yōu)化方法[2]。而在三維模型動態(tài)調度方面最典型的應用是將四叉樹算法運用到地形加載中[3],此外,還有基于Docker容器的調度優(yōu)化策略等[4]。

本文主要通過資源動態(tài)調度來完成使用Unity進行虛擬仿真系統(tǒng)開發(fā)中內存問題的優(yōu)化,通過引入四叉樹算法,并對當前算法中的一些問題進行優(yōu)化,實驗證明,優(yōu)化后的算法在Unity內存占用上產(chǎn)生了良好的反饋,使應用在不損失效果的情況下將內存的消耗更低。

2 Unity內存機制

Unity3D 引擎使用的內存類型共有三種:程序代碼段、托管堆( Managed Heap) 以及本機堆(Native Heap)[2]?!按a段”存儲可執(zhí)行文件的指令;也有可能包含一些運行的依賴庫文件等?!氨緳C堆”是Unity指的是對本地資源進行申請和操作,其中資源指的是音效、圖片和三維模型等一些文件?!巴泄芏选笔且欢蝺却?,由項目腳本運行時(Mono或IL2CPP)的內存管理器自動管理。

Unity官方說明中明確指出內存全部都是由系統(tǒng)托管,其內存管理機制的基本理念是:如果某個場景(scenes)里需要某個資源(Resources),那么在運行時加載到內存。而將資源加載至場景中有多種調用方式,且不同的調用方式在內存的占用過程也不一致;其中加載預設的方式有三種,第一種是聲明公有變量,其中變量的值可通過在Inspector中修改;二是采用Resources.Load()方法加載;三是采用AssetBundle.Load()方法;三種加載方式在加載后都需要然后在相應腳本中用Instantiate()方法實例化。其中第三種加載方式在加載過程中會直接加載預設全部依賴資源,在實例化過程中只是進行克隆操作。

而在Unity資源的卸載和銷毀過程中,Destory()函數(shù)釋放資源有限,只對資源的引用或復制,不釋放已加載至內存的紋理、材質等資源。UnloadAsset()釋放區(qū)域中指定的資源。此外還有UnloadUnusedAssets()方法能夠卸載當前所有沒有被占用的資源。

通過上述分析可知在虛擬仿真時采用AssetBundle()加載方式能同時加載預設的紋理、材質信息,此方法能夠避免加載和卸載中掉幀的現(xiàn)象。卸載時使用Destory()函數(shù)銷毀物體對象后,在資源卸載完成后調用UnloadUnusedAssets()函數(shù)將未被占用的紋理、貼圖資源徹底卸載以實現(xiàn)內存回收。

3 四叉樹算法

3.1 基本思想

四叉樹算法的基本思想是將空間遞歸劃分為不同層次的樹結構。如圖2所示它將已知范圍的空間分成四個子空間,如此遞歸下去,遞歸的次數(shù)稱為四叉樹的層數(shù),直至樹的層數(shù)達到一定深度后停止分割。

圖2 四叉樹結構

四叉樹算法的應用方向很多,常見的如:稀疏數(shù)據(jù)、圖像處理、空間數(shù)據(jù)索引以及物體碰撞檢測等,而將其運用到虛擬仿真中進行動態(tài)調度是屬于空間數(shù)據(jù)索引方面的一個應用;四叉樹算法的結構比較簡單,并且當空間數(shù)據(jù)對象分布比較均勻時,具有比較高的查詢效率和空間數(shù)據(jù)插入,因此四叉樹算法也是常用的空間索引算法之一。

3.2 四叉樹在unity中的建立

假設虛擬仿真場景如圖3所示,整個空間內(矩形內)存在三維模型a-j。

圖3 Unity場景內三維模型分布

首先對空間區(qū)域(類別)進行劃分,然后給每一個子節(jié)點都編號,那么每個子節(jié)點會繼承父節(jié)點的編號為前綴,并在此基礎上有相對其兄弟節(jié)點的獨特編號。如果給左上、右上、左下、右下四個子節(jié)點分別編號為1、2、3、4,那么1節(jié)點內的左上、右上、左下、右下四個子節(jié)點分別編號為11、12、13、14.以此類推,當節(jié)點內模型資源較少時,可以不劃分;則可得到如圖4所示的區(qū)域劃分圖。

圖4 區(qū)域劃分圖

對應上述三維模型進行區(qū)域劃分后,將四叉樹中所有的三維模型對象都存儲在各個最底層的子節(jié)點上,如圖5所示,此時,如果2節(jié)點有劃分,則c、f三維模型不能存儲在2上,應該存儲在對應的子節(jié)點上,該模型也稱為滿四叉樹。

圖5 四叉樹示意圖

3.3 非滿四叉樹

滿四叉樹結構是自父節(jié)點(根)向下逐步劃分的一種樹狀的層次結構,每次索引的深度將隨著四叉樹的層數(shù)大大的增多,但隨著四叉樹的層數(shù)會不斷地加深,三維模型資源不斷的增加,四叉樹索引的缺點也更加明顯,首先,索引查詢的時候效率會比較低下;其次存儲空間的浪費;最后樹的結構會變得不平衡。

而針對滿四叉樹結構的不足,也有相應的改進:將數(shù)據(jù)信息可以存儲在它的每一個節(jié)點中,如圖6所示,并且將同時存在于兩個節(jié)點的三維模型存儲到這兩個節(jié)點的父節(jié)點;如12和14節(jié)點都有三維模型b,將其存儲到1節(jié)點,每個三維模型資源只在樹中存儲一次,通過改進可以加快插入的速度,并且不存在一個三維模型資源存儲在多個節(jié)點的現(xiàn)象,這種結構為非滿四叉樹結構。

圖6 非滿四叉樹

非滿四叉樹為每個節(jié)點(包括父節(jié)點)需要添加一個“容量”的屬性,在四叉樹初始化時只有一個父節(jié)點,并且該根節(jié)點也可以存儲,在插入數(shù)據(jù)時,如果一個節(jié)點內的數(shù)據(jù)量大于了節(jié)點“容量”,再將節(jié)點進行分裂。在查詢時,只有找到了位置對應的節(jié)點,那么節(jié)點下的所有點都會是此位置的附近點,更小的“容量”意味著每個節(jié)點內點越少,也就意味著查詢的精度會越高。并且可以保證每個節(jié)點內都存儲著數(shù)據(jù),避免了內存空間的浪費。

4 實驗驗證

4.1 實驗方法

實驗中將場景中的攝像機和Player綁定,使得攝像機始終處于中心位置,而周圍仿真模型始終隨著攝像機視野移動而實時進行動態(tài)調度。而針對Unity內存管理機制,通過對三維模型進行預設實例化和預設銷毀完成相應的內存管理。設計了如圖7所示的流程的動態(tài)調度方法。

圖7 實驗流程圖

1)程序初始化時將資源建立四叉樹,并根據(jù)攝像機初始位置加載初始視野內的仿真模型,并將載入的模型資源存入列表CurrentList(保存當前已加載三維模型)。

2)Unity生命周期表到達Update幀刷新階段,判斷攝像機位置是否改變,若未發(fā)生變化則不處理,否則進入三維模型動態(tài)調度。

3)運用四叉樹算法通過變化后攝像機位置來計算視野內三維模型資源,將其存入列表RefreshList(保存幀更新后三維模型)。

4)根據(jù)每一幀幀更新前后的三維模型列表差值(CurrentList和RefreshList的差值)計算出需要加載和卸載的三維模型。

5)完成調度后,將RefreshList賦值給CurrentList,即更新當前仿真模型資源列表。

結合圖7知,列表RefreshList比CurrentList的多出來的三維模型則代表需要加載的三維模型,而CurrentList比RefreshList的多出來的三維模型則代表需要卸載的三維模型。完成地形塊的動態(tài)加載和卸載之后,執(zhí)行UnloadUnusedAssets()函數(shù)釋放其它紋理、材質等內存三維模型,并更新當前列表后進入下一幀循環(huán),由此則完成整個場景中三維模型的動態(tài)調度過程。在整個幀循環(huán)過程中,內存中只需要加載攝像機視野中的三維模型從而占用更少的內存。

4.2 方法改進

實驗中三維模型需要通過四叉樹查找攝像機(Player)周圍的編碼塊不斷刷新,但是加載視野周圍的資源時需要搜索周圍資源是否在范圍內,若范圍內某個點周圍的資源都加載的話,還是會占用大量的內存空間,并且現(xiàn)率提升不明顯。而啟發(fā)式搜索就是在狀態(tài)空間中的搜索對每一個搜索的位置進行評估,得到最好的位置,再從這個位置進行搜索直到目標。這樣可以省略大量無謂的搜索路徑,從而進一步提升效率。用于評價節(jié)點重要性的函數(shù)稱為估價函數(shù),其一般形式為

f(n)=g(n)+h(n)

在該算法中,根據(jù)估價函數(shù)值,按由小到大的次序對Open表(被考慮視野內有效資源的位置集合)中的節(jié)點進行重新排序,此時的Open表是一個按節(jié)點的啟發(fā)估價函數(shù)值的大小為序排列的一個優(yōu)先隊。

該算法首先需要將初始攝像機節(jié)點S0放入Open表中;如果Open表為空,則退出,當其不為空,把Open表的第一個節(jié)點取出,放入到Closed表(不被考慮視野內模型資源的位置集合)中,并把該資源節(jié)點記為節(jié)點n;如果節(jié)點n是視野邊緣節(jié)點,則搜索成功,求得一個解,退出;再對節(jié)點n進行拓展,生成一組子節(jié)點,對不在Open表和Closed表中的資源節(jié)點計算出相應的估價函數(shù)值;再把節(jié)點n的子節(jié)點放到Open表中并進行排序;最后重復步驟直到退出。

實驗中在四叉樹的基礎上引入A*算法,A*算法一般用于最佳路徑問題,而用于此處主要作用找出攝像機當前位置所需要加載的最佳模型組合;由于四叉樹已經(jīng)將地圖分割,主要考慮通過估價函數(shù)找出最佳的三維模型資源組合,稱之為可采納性。A*算法是一個可采納的最好優(yōu)先算法。A*算法的估價函數(shù)為:

f′(n)=g′(n)+h′(n)

式中:g′ (x)為從攝像機節(jié)點到視野內節(jié)點x的最佳資源組合所付出的代價;h′ (x)是從視野內節(jié)點x到邊緣節(jié)點的最佳資源組合所付出的代價;f′ (x)是從初始節(jié)點開始一直加載節(jié)點x到達邊緣節(jié)點的最佳路徑的總代價。

對于每個節(jié)點的資源,都有自己的g′ (x)、h′ (x)、f′ (x)。其中g(x)是對g*(x)的估計,且g(x)>0;h(x)是h*(x)的下界,即對任意節(jié)點x均有h(x)≤h*(x)

A星算法并不去遍歷整個場景,而是只遍歷了視野內的點和其周圍的點,所以得到的是一種近似最優(yōu)解的集合。

4.3 實驗步驟

實驗中電腦的配置如表1。

表1 電腦配置表

由于攝像機的視野為四棱錐狀,首先在Unity中創(chuàng)建一個矩形空間,并在矩形空間中預設一定量的三維模型文件,建立場景如圖8所示。

圖8 Unity場景

研究中將三維空間降為二維研究,則三維模型資源可理想化為點集,如圖9所示,圖中O點為攝像機,三角形OAB為俯視視圖中攝像機的視野,為更加直觀看出四叉樹的視覺效果,在Untiy空間中使用Gizmos.DrawWireCube()來繪制四叉樹劃分的區(qū)域。

圖9 Unity中建立四叉樹

4.3 代碼實現(xiàn)

在整個場景中攝像機綁定在玩家Player上,可通過鍵盤鼠標控制Player移動,即鍵盤上WASD控制Player前后左右移動、空格跳躍以及鼠標控制攝像機的上下左右旋轉;其實現(xiàn)方法為在Update()方法中通過判斷Input.GetKey() 獲取按鍵信息,并使用進行攝像機的移動(WASD控制攝像機移動),部分代碼如下:

void Update () {

if(Input.GetKey (KeyCode.W)){

transform.Translate(Vector3.forward * Time.deltaTime * Speed);}}

在加載過程中完成四叉樹的創(chuàng)建,主要通過一下代碼(部分)完成四叉樹的創(chuàng)建,如果還可以擁有下一層子節(jié)點且未創(chuàng)建,則創(chuàng)建下一層子節(jié)點,且只有一個子節(jié)點時則可以包含該物體,即該物體屬于子節(jié)點:

public void InsertObj(ObjData obj){

Node node=null;

bool bChild=false;

if(depth < belongTree.maxDepth && childList==null) {

CerateChild();}

if(childList!=null){

for (int i=0; i < childList.Length;++i)

Node item=childList[i];

if (item==null){

break;}}}

if (bChild){

node.InsertObj(obj);}

else{

objList.Add(obj);}}}}

通過A*尋找邊緣節(jié)點代碼如下

while (openList.Count > 0) {

AStarNode curNode=openList [0];

for (int i=0; i < openList.Count; i++) {

if (openList [i].CostF < curNode.CostF && openList [i].costH < curNode.costH) {

curNode=openList [i];}}

openList.Remove (curNode);

closeList.Add (curNode);

已經(jīng)找到邊緣節(jié)點后獲取當前點的周圍點,

if (curNode==end) {

Debug.Log (″>>″);

GetPathWithPos (startPos,endPos);

return;}

List nodeItemGroup= aStarMap.GetAroundNodes(curNode);

最后遍歷當前點周圍的NodeItem 對其進行過濾并且計算f(n)、g(n)、h (n)并進行賦值。

foreach (AStarNode nodeCell in nodeItemGroup) {

if (nodeCell.isWall || closeList.Contains (nodeCell)) {

continue;}

if (newCostg <=nodeCell.costG

||!openList.Contains (nodeCell)) {

nodeCell.costG=newCostg;

nodeCell.costH=GetDistance (nodeCell,end);

nodeCell.parentNode=curNode;

if (!openList.Contains (nodeCell)) {

openList.Add (nodeCell); }}

在實驗中將建立不同層數(shù)的四叉樹來進行實驗對比驗證,在Unity中設定層數(shù)后,通過Unity Profile性能分析工具來觀察Unity中各種參數(shù)的變化,如圖10所示,由性能分析器的內存占用曲線可以看出,在進行動態(tài)調度時,仿真模型的加載和卸載過程占用時間很短,而且內存始終維持在穩(wěn)定水平。

圖10 性能分析工具

4.4 實驗結果

實驗中三維模型中的部分包含PNG格式貼圖,模型的預制體為24個,地形文件1個,在加載時隨機實例化預制體,使得場景中模型數(shù)量到10000,運行場景后隨機運動Player不斷刷新場景,將場景的幀數(shù)、內存占用以及首次加載時間進行數(shù)據(jù)記錄,主要控制的變量為四叉樹深度,根據(jù)改變深度得到的數(shù)據(jù)來判斷應用四叉樹算法后的效果,通過多次實驗并整理得到的數(shù)據(jù)如表2所示。

表2 實驗數(shù)據(jù)

由上表可見,本實驗中采用四叉樹進行動態(tài)調度之后,程序中的內存占用均大大降低,而且?guī)室灿兴嵘?。但是隨著四叉樹的深度的增大,該算法的引入仍然具有優(yōu)勢,但優(yōu)化效率卻會下降,優(yōu)化并不理想并且會增加加載時間;實驗表明,四叉樹深度在4-7為最佳(其它自變量不變時)優(yōu)化效率(幀數(shù))可達38.21%。

5 結束語

虛擬仿真的相關引擎極大地方便了虛擬仿真的相關開發(fā),而Unity其強大的功能特性、跨平臺支持等優(yōu)勢更是受到無數(shù)開發(fā)者的青睞,而本研究針對使用Unity進行開發(fā)中的內存在用問題,

引入四叉樹算法進行動態(tài)調度,本文的研究具有以下特點:

1)從資源加載的角度進行優(yōu)化內存占用,在大場景漫游過程能避免一次性加載、卸載過多導致的一些問題,并保持瀏覽流暢度的同時降低計算機性能消耗。

2)詳細分析了在Unity中的仿真模型的加載和卸載過程,對于控制仿真對象的三維模型占用和優(yōu)化有重要作用

3)通過實驗證明該算法的引入能夠顯著提升Unity在虛擬仿真時的幀率;同時,能維持內存消耗在較低水平。

4)四叉樹節(jié)點的分裂與合并比較頻繁,如果直接 new、delete,相對比較慢;簡單的實例化一些對象,并組成一個對象池的話,內存碎片會比較嚴重,在后續(xù)研究中需要時,每次預先分配一大塊內存。再在大塊內存上,切出一個個對象地址,這樣可以比較有效的減緩內存碎片現(xiàn)象。

猜你喜歡
攝像機視野內存
筆記本內存已經(jīng)在漲價了,但幅度不大,升級擴容無須等待
“春夏秋冬”的內存
用迷你攝像機代替眼球
內存搭配DDR4、DDR3L還是DDR3?
視野
真相
視野
上網(wǎng)本為什么只有1GB?
高清新陣營
品牌視野
富平县| 大悟县| 柘城县| 丹阳市| 陆川县| 丰台区| 密山市| 资源县| 高陵县| 合川市| 陆丰市| 峨眉山市| 侯马市| 江城| 温泉县| 北京市| 广河县| 丹棱县| 吴川市| 茶陵县| 屯留县| 正定县| 甘孜县| 罗山县| 集安市| 大埔区| 衢州市| 西昌市| 昌平区| 长泰县| 丹巴县| 梧州市| 米脂县| 牟定县| 襄垣县| 广饶县| 潮州市| 依兰县| 剑河县| 定远县| 梨树县|