本文章由cartzhang編寫,轉載請註明出處。 所有權利保留。
文章連結:http://blog.csdn.net/cartzhang/article/details/53013843
作者:cartzhang
上次我們只做了一個快速的實現,實現了一個可愛的Unity醬的Google盒子的安卓版本。
說明:圖片編號為了與github對應,所以保留了原來的編號。
圖片地址: https://github.com/cartzhang/UnitySay/tree/master/GooglVR_2/img
只將簡單的情境搭建和應用技巧,沒有任何分析,這不是耍流氓嗎。
當然是。
看代碼從開始入手呢?
先看情境上,我們只掛載了一個googleVR的預製體,那就從它開始。
圖1
這傢伙只有一個指令碼GvrViewer.cs,是不是讓你大喜過望啊。一個指令碼就搞定了,是不是很簡單呢,這說簡單也不簡單。
粗略瀏覽一下代碼,代碼不到550行。
不關心後面的50行左右的,編輯器操作和遊戲的暫停,退出等操作,還有500行,這個真不少啊。
那怎麼說呢。
我們先要從Unity的代碼執行順序開始,
Unity中代碼的執行順序:
官方地址:https://docs.unity3d.com/Manual/ExecutionOrder.html
我們的重點:
圖9.1
從Awake–>Start–>Update依次來講述。 一、 Awake 分析
程式碼分析
void Awake() { // 1.0 -- if (instance == null) { instance = this; } if (instance != this) { Debug.LogError("There must be only one GvrViewer object in a scene."); UnityEngine.Object.DestroyImmediate(this); return; } // 1.1 -- #if UNITY_IOS Application.targetFrameRate = 60;#endif // Prevent the screen from dimming / sleeping // 1.2 -- Screen.sleepTimeout = SleepTimeout.NeverSleep; // 1.3 -- InitDevice(); StereoScreen = null;// Set up stereo pre- and post-render stages only for:// - Unity without the GVR native integration// - In-editor emulator when the current platform is Android or iOS.// Since GVR is the only valid VR SDK on Android or iOS, this prevents it from// interfering with VR SDKs on other platforms. //1.4 -- #if !UNITY_HAS_GOOGLEVR || (UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS)) AddPrePostRenderStages();#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR
1.0 –
// 1.0 -- if (instance == null) { instance = this;}if (instance != this) { Debug.LogError("There must be only one GvrViewer object in a scene."); UnityEngine.Object.DestroyImmediate(this); return;}
初始化,此類是個單列。
1.1 –
// 1.1 -- #if UNITY_IOS Application.targetFrameRate = 60;#endif
宏定義,若有UNITY_IOS,則鎖幀在60幀。鎖幀就是為了讓遊戲穩定一些 穩定的幀數。
1.2 –
// 1.2 -- Screen.sleepTimeout = SleepTimeout.NeverSleep;
就是為了省電,螢幕長時間沒有觸發,就觸發睡眠模式。現在就是從不啟用睡眠模式。
1.3 –
// 1.3 -- InitDevice();
初始化裝置。這個是個函數,以後單說。
1.4 –
//1.4 -- #if !UNITY_HAS_GOOGLEVR || (UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS)) AddPrePostRenderStages();#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR
沒有預渲染,就添加預渲染。若沒有後渲染,就添加後渲染。然後分別發送訊息,Reset().最後設定他們各自的父節點。
設定當前對象為其父節點,代碼就一句:
go.transform.parent = transform;
圖2
圖3
稍微說下SendMessage 這個函數:
[ExcludeFromDocs]public void SendMessage(string methodName);
它的功能是調用當前對象上所有的Monobehaviour指令碼內的名字為methodName的函數。
這方法效率不高。但是可以用,少用為好。
詳細可以參考之前的博文:
http://blog.csdn.net/cartzhang/article/details/50686627
下面說初始化1.3 – 的初始化裝置這個函數。
代碼中給出了詳細注釋。
private void InitDevice() { // 初始化裝置 if (device != null) { device.Destroy(); } // 擷取裝置 device = BaseVRDevice.GetDevice(); // 裝置初始化,這是繼承類,其中override重新了Init。參考下圖 device.Init(); // 初始化UI List<string> diagnostics = new List<string>(); NativeUILayerSupported = device.SupportsNativeUILayer(diagnostics); if (diagnostics.Count > 0) { Debug.LogWarning("Built-in UI layer disabled. Causes: [" + String.Join("; ", diagnostics.ToArray()) + "]"); } if (DefaultDeviceProfile != null) { device.SetDefaultDeviceProfile(DefaultDeviceProfile); } device.SetNeckModelScale(neckModelScale); // 設定是否使用雙目渲染。即是否使用VR模式。#if !UNITY_HAS_GOOGLEVR || UNITY_EDITOR device.SetVRModeEnabled(vrModeEnabled);#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR // 更新螢幕資料 device.UpdateScreenData(); }
device.Init() 初始化的繼承與BaseVRDevice類。
圖7
圖4
是否使用雙目VR渲染,這個可以在即時修改其作用的。
圖5
圖6 二、 Start代碼
代碼只有一句,還在當前Unity 安卓模式和IOS模式下,Unity編輯器模式下才可用。
void Start() {// Set up stereo controller only for:// - Unity without the GVR native integration// - In-editor emulator when the current platform is Android or iOS.// Since GVR is the only valid VR SDK on Android or iOS, this prevents it from// interfering with VR SDKs on other platforms.#if !UNITY_HAS_GOOGLEVR || (UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS)) AddStereoControllerToCameras();#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR }
具體實現了什麼呢。
就是添加了手機的陀螺儀控制,可以用陀螺儀來控制相機。
上一講中的在會後打出來安卓的APK包,在手機中自動的就可以左右移動來看情境中我們可愛的蠻牛醬的跳動,就是這樣來控制和實現的。
#if !UNITY_HAS_GOOGLEVR || UNITY_EDITOR /// Add a StereoController to any camera that does not have a Render Texture (meaning it is /// rendering to the screen). public static void AddStereoControllerToCameras() { for (int i = 0; i < Camera.allCameras.Length; i++) { Camera camera = Camera.allCameras[i]; if (camera.targetTexture == null && camera.cullingMask != 0 && camera.GetComponent<StereoController>() == null && camera.GetComponent<GvrEye>() == null && camera.GetComponent<GvrPreRender>() == null && camera.GetComponent<GvrPostRender>() == null) { camera.gameObject.AddComponent<StereoController>(); } } }#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR
圖8
代碼也不多。通過搜尋,發現當前情境中總共有5個相機,如上圖 。功能就是遍曆所有相機,然後找到相機中,沒有StereoController,GvrEye,GvrPreRender,GvrPostRender的相機,然後給它添加控制StereoController組件。
這樣以來符合要的就只有MainCamera滿足調節了。
圖9 三、 在那裡更新畫面。
有沒有發現在GvrViewer檔案中,沒有我們常見的Update()函數,只有一個UpdaetState()函數。那遊戲畫面怎麼更新的呢。
注意是preRender()
待會的重點函數標註下:
圖9.2
看下與UpdateState相關的調用,除去Demo和Ui調用,發現跟上面的AddStereoControllerToCameras這個函數中提到的類相關。
圖10
1 .看下GvrEye.cs檔案:
發現裡面在渲染層次的函數:OnPreCull 和 OnPostRender。
其中,OnPostRender只有一句就是shder的某個關鍵字屏蔽。
看下OnPreCull的調用實現過程:
圖11
在調用之後,最終還是產生一個RenderTexture.
圖12
左右眼根據設定不同,矩陣參數有不同變化。但是結果都是一樣的,一個紋理而已。
這都是在為最後一步渲染出左右眼,給所渲染的網格設定材質做準備而已。
2.GvrPreRender.cs檔案
這個檔案,根據很明顯根據渲染順序是預渲染的處理內容。
只有一個OnPreCull這樣的渲染調用。
void OnPreCull() { // 更新裝置狀態 GvrViewer.Instance.UpdateState(); if (GvrViewer.Instance.ProfileChanged) { // 設定shader,各種矩陣 SetShaderGlobals(); } // 設定相機類型 cam.clearFlags = GvrViewer.Instance.VRModeEnabled ? CameraClearFlags.SolidColor : CameraClearFlags.Nothing; }
圖13
3.GvrPostRender.cs檔案
在渲染層次有兩個函數一個是OnPreCull,一個為OnRenderObject.
其中OnPreCull,實現了根據相機螢幕及其手機螢幕的設定來調節比例,最後得到的是一個相機透視投影的比例參數。
而OnRenderObject則是實現分屏渲染,實現GooleVR的關鍵一步,渲染出畫面。
圖14
4. 簡單說下 StereoControl.
主要功能就是建立左右眼,並設定其位置。
圖15
5. GvrHead.cs
圖16
與steroControl在同個相機下,
代碼沒有多少行:
void Update() { updated = false; // OK to recompute head pose. if (updateEarly) { UpdateHead(); } } // Normally, update head pose now. void LateUpdate() { UpdateHead(); }
很明顯,都調用了UpdateHead().
這個函數裡面也很容易看到。
看是否同步跟蹤旋轉,是否同步跟蹤位置,然後也是最後
有一個委託事件就是OnHeadUpdated。
這個就是在看玩家怎麼使用的啦,更新玩狀態就會通知的事件。
就不多說了。 四、一圖千言
圖18 五、流程圖下載
下載流程圖地址github:
https://github.com/cartzhang/UnitySay/blob/master/GooglVR_2/CodeAnylis.docx
這裡有所畫的流程圖,若有需要,可以自行下載。
若有問題,請隨時聯絡。。
非常感謝。。 六、參考
[1]
http://baike.baidu.com/link?url=ZdjIjIyvD_MlE57zVxe6PddyFhQqBXybShXg9NSi0R92EU8vkZHOYevvefg3zk7tVrD127vybwV-9b3HryYlCytg68J3DDmqG4R_YLqPZ53
[2]
https://docs.unity3d.com/Manual/ExecutionOrder.html
—————–THE—–END————————-