1. 程式人生 > >Unity筆試題【20181025】

Unity筆試題【20181025】

1、簡述delegate和event關鍵字
答:delegate 委託,是C#的一種型別,持有對某個方法的引用的類,能夠擁有一個簽名,引用只能與簽名方法相匹配。實現:1、宣告一個委託物件,與傳遞方法具有相同引數列表和返回值型別。2、建立委託物件,將要傳遞的函式作為引數傳入。3、在實現非同步呼叫地方,通過上一步建立物件呼叫方法。event 事件,在類中宣告且生成,通過使用同一個類或其他類的委託與事件處理程式關聯。包含事件的類用於釋出事件,稱為釋出器(publisher)類;接受該事件的類稱為訂閱器(subscriber)類。事件使用釋出-訂閱模型。兩者的區別:1、委託允許直接訪問相應處理函式,事件只能通過公佈的回撥函式去呼叫。2、事件只能通過“+=”、“-=”方式註冊和取消處理函式,委託除此之外還可以“=”直接賦值處理函式。

2、請列舉Unity3D指令碼生命週期的幾個重要方法
答:Awake(){} 指令碼喚醒,系統執行的第一個方法,用於指令碼初始化,只執行一次。Start(){} 在Awake之後、Update之前執行,只執行一次。Update(){} 用於邏輯正常更新,每幀由系統自動呼叫一次。FixedUpdate(){} 固定更新。LateUpdate(){} 推遲更新,每幀呼叫,在Update之後呼叫。OnGUI(){} 繪製介面,每幀呼叫。OnDestroy(){} 當前指令碼銷燬時呼叫。

3、什麼是AssetBundle?談談對AssetBundle記憶體分配情況的理解
答:可以把多個遊戲物件或資源二進位制檔案封裝到AssetBundle中,提供封裝與解包的方法使用很方便。
在這裡插入圖片描述


載入資源三個步驟:
1、www/LoadFromFile/LoadFromMemory等介面載入AssetBundle本身
2、AssetBundle.LoadAsset()等介面從AssetBundle中載入資源
3、對於GameObject類資源,需要通過GameObject.Instantiate()建立Clone

黑色區域:www類本身佔用記憶體,還保留了一份對WebStream資料的引用。使用www = null或www.dispose()釋放。前者等待GC,後者立即釋放。釋放後WebStream引用計數會減一。

橙色區域:WebStream資料,資料真正的儲存區域。AssetBundle被載入進來後,這部分記憶體就被分配了。包含三個內容:1、壓縮後的AssetBundle本身。2、解壓後的資源。3、一個解壓緩衝區。www或AssetBundle物件都只是有一個結構指向了WebStream資料,從而對外部提供操作真正資源資料的方法。當WebStream資料引用為0時,系統會自動釋放。為了不頻繁的開闢和銷燬解壓Buffer,綠色Decompression解壓緩衝區Unity會至少保留一份。

粉色區域:AssetBundle物件,引用WebStream資料部分,提供從WebStream資料中載入資源的介面。AssetBundle.Unload(bool unloadAllLoadedObjects)釋放資源。AssetBundle.Unload(false)釋放AssetBundle物件本身,可能引起WebStream釋放,導致無法通過介面或依賴關係從該AssetBundle載入資源,但已載入資源可以正常使用。AssetBundle(true)不僅釋放WebStream部分,所有被加載出來的資源將被釋放。

紅色部分:通過Instantiate()建立的GameObject所包含的資源。這些資源根據型別與AssetBundle原始資源(WebStream資源部分)有不同關係。如Texture、shader資源,通常只是使用,不會做出改動,所以僅僅是引用關係;每個GameObject是特殊的,所以是完全複製一份;Mesh和Material,則是引用+複製的關係。

4、什麼是DrawCall,有什麼方法可以減少DrawCall
答:CPU通過呼叫繪製命令來告訴GPU開始進行一個渲染過程(一次DrawCall)。
CPU方面減少DrawCall:
1、使用Draw Call Batching 、Dynamic Batching動態批處理
2、紋理打包成圖集減少材質使用
3、少用反光、陰影
4、設定一個合適的Fixed Timestep
5、不要使用網格碰撞器(Mesh Collider)
6、大量或頻繁的字串連線操作一定要用StringBuilder
7、某些可能情況,使用結構體代替類
8、使用物件池重複利用空間
9、儘量不要用foreach,用for
10、不要直接訪問GameObjcet的tag屬性
11、不要頻繁使用GetComponent,訪問一次後保留其引用
12、使用OnBecameVisible()和OnBecameInVisible(),控制物體update()函式的執行減少開銷
13、使用內建陣列,如Vector3.zero而不是new Vector3(0,0,0)
14、使用ref關鍵字對方法的引數進行優化
15、關閉所有update中的log操作
16、不在update中呼叫GetComponent、SendMessage、FindWithTag等方法
17、不在update中使用臨時變數

GPU方面減少DrawCall:
1、使用紋理圖集代替一系列單獨小貼圖
2、保持材質數目儘可能少
3、如果使用紋理圖集和共享材質,用Renderer.sharedMaterial代替Renderer.material
4、使用光照紋理(lightmap)而非實時燈光
5、使用LOD
6、使用mobile版的shader
7、儘可能減少頂點數、背面刪減
8、壓縮圖片,減少視訊記憶體頻寬壓力

5、談談你對u3d渲染管線的理解
答:渲染管線(Rendering Pipeline)就是GPU渲染。流程:頂點處理、面處理、光柵化、畫素處理。頂點處理:通過一系列座標系轉換將模型頂點在攝像機前位移,最終投影到攝像機螢幕上(本地 - 世界 - 觀察 - 投影)。包括頂點座標變化、逐頂點霧化、材質屬性和光照屬性處理。面處理:面的組裝、擷取、剔除。光柵化:消除遮擋面;Texture Operation,根據畫素紋理座標查詢對應紋理值;Blending,根據已經畫好顏色與正在計算的顏色alpha值混合形成新顏色;Filtering,將正在計算的顏色經過某種濾鏡後輸出,該階段後像素的顏色值被寫入幀快取中。畫素處理:對每個畫素區域著色,對畫素貼上貼圖形成最終畫面。

6、什麼是material,什麼是shader,二者有什麼關係
答:材質系統定義瞭如何渲染物件表面資訊。shader裡面使用材質資訊加自身操作,最終呈現物體渲染。shader是material一部分,是根據計算即時演算生成貼圖的程式,叫著色器。常用處理無法用固定貼圖表現的模型。material是模型的材質,包含貼圖、shader、頂點、凹凸等資訊。

7、簡述單例模式和觀察者模式,並用虛擬碼實現其中之一
答:單例模式:

public class Singleton{
	private static Singleton instance;
	private static readonly object locker = new object();
	private Singleton(){}
	public static Singleton GetInstance{
		get{
			if(instance == null){
				lock(locker){
					if(instance == null){
						instance = new Singleton();
					}
				}
			}
			return instance;
		}
	}
}

觀察者模式:

public class Observer{
	public delegate void ObserverDelegate();
	public event Observer ObserverEvent;
	public void Function(){
		ObserverEvent();//呼叫所有註冊物件
	}	
}

public class Test{
	public void Show(){
		Console.WriteLine("Test");
	}
}

public class Display{
	public static void ShowMsg(){
		Console.WriteLine("Display");
	}
}

static void Main(string[] args){
	Observer ob = new Observer();
	Test alarm = new Test();
	ob.ObserverEvent += Test.Show;//註冊方法
	ob.ObserverEvent += (new Test()).Show;//註冊匿名物件的方法
	ob.ObserverEvent += Display.ShowMsg;//註冊靜態方法
	ob.Function();//自動呼叫註冊過的物件的方法
}