摘要:Q:我們的遊戲參考了UWA Blog上的那篇《GPU Skinning加速骨骼動畫》(https://blog.uwa4d.com/archives/Sparkle_GPUSkinning.html),發現真機環境幀數提升不是很明顯,連上Profiler發現開啓/關閉GPU Skinning總批次居然沒啥變化,SetPass Calls倒是變化明顯,在編輯器切到Android平臺我測試過總批次會提升100+,有點奇怪爲什麼到了Android真機裏沒什麼變化。使用GPU Skinning方案後,紅米Note2上的50個模型時的Camera.Render耗時情況。

1)使用GPU Instancing屏幕花屏問題
2)如何優化AssetBundle大小
3)如何使用GPU Skinning提升性能
4)iOS上Shader裏tex2D採樣偏移的問題
5)如何管理銷燬拍攝的內置深度圖

這是第184篇UWA技術知識分享的推送。今天我們繼續爲大家精選了若干和開發、優化相關的問題,建議閱讀時間10分鐘,認真讀完必有收穫。

UWA 問答社區:answer.uwa4d.com
UWA QQ羣2:793972859(原羣已滿員)


GPU Instancing

Q:機器:魅族MX5
Unity版本:2019.1.5f1
渲染設置:OpenGL ES3,Dynamic Batching,GPU Instancing

問題表現:場景有時候會突然花屏隨機閃爍, 通過排除法發現是在渲染其中一個樹的時候導致的(樹的材質勾選了GPU Instancing,只要不渲染這個樹就不閃爍)。

使用GPU Instancing屏幕花屏問題

嘗試改變渲染設置:僅關閉動態批處理或者GPU Instancing就都不花屏了, 兩者同時存在就會花屏。

不知道這是Unity的Bug還是魅族機器有問題。
附件:Demo工程(請戳原問答鏈接查看)

A:根據題主提供的信息,我們做了以下嘗試。
測試機:魅族5;對比測試機:小米6
測試場景:客戶提供

測試現象
魅族5開啓了Dynamic和Instancing,會花屏,UBO數組長度爲2,有Log報錯。

小米6和OPPO K1均不花屏,UBO數組長度均爲128,無Log報錯。

魅族5在RenderDoc的數據
當開啓GPU Instancing的時候,在Vertex Shader裏面會有2個UBO(Uniform Buffer Object)。

使用GPU Instancing屏幕花屏問題

它們的內容分別如下:

使用GPU Instancing屏幕花屏問題

使用GPU Instancing屏幕花屏問題

第一個記錄的是SH函數的係數,第二個是每個Instance的變換矩陣。

在魅族5上面數組長度爲2,可以理解爲魅族5不支持Instance。而在小米6和OPPO K1,是支持128個Instance的,如下圖所示:

使用GPU Instancing屏幕花屏問題

使用GPU Instancing屏幕花屏問題

使用GPU Instancing屏幕花屏問題

說明它們是支持Instancing的。

在移動平臺上,一個Buffer的大小上限是16KB,一個Instance需要記錄ObjectToWorld和WorldToObject的矩陣,總共是16x4x2=128 Byte,所以總的Instance上限數量是16x1024 Byte/128 Byte = 128。

從RenderDoc上的信息裏面可以看到確實是長度爲128的數組,而在魅族5上面只有2。

而且在魅族5上面運行測試場景的時候,通過Logcat可以看到會有報錯的Log:
GLSL: unexpected struct parameter 'unity_Builtins2Array1.unity_SHCArray’
GLSL:unexpected struct parameter 'unity_Builtins0Array1.hlslcc_mtx4x4unity_WorldToObjectArray[

這兩個正是Instancing需要的UBO裏面的數據。

還有一點需要說明的是,在測試場景中,使用的是239個三角形的那個Mesh,在魅族5上面同樣會花屏。不論有沒有開啓Dynamic Batching,都會有上面的報錯,所以本質上是魅族5不支持Instancing導致的

創建了一個場景,場景中有3棵相同的樹,而且開始了Instancing,可以看到OpenGL使用的接口是glDrawElements。

使用GPU Instancing屏幕花屏問題

在小米6上調用的接口是glDrawElementsInstannced,如下圖:

使用GPU Instancing屏幕花屏問題

沒有對模擬器進行測試,理論上是一樣的情況。

該回答由UWA提供,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5dce374d14ec712eefaf01ae


Asset

Q:我們AssetBundle超過3.8G了,也做了分類,但是資源太多導致總大小超過3.8G,很多玩家安裝不上。有沒有相關解決思路?

A1:隨着硬件的發展,玩家對畫質要求的提高,基本上包體越來越大是必然的,關鍵還是看大的是否合理,基本上可以順着幾個點去檢查下。

(1)首先使用UWA的資源檢測工具看下是否AssetBundle內重複資源過多,如果有,可以根據檢測結果調整,並定期提交UWA測試。

(2)配合一些資源分析的工具在編輯器內人工的工程內部資源大致過一遍,看看是否有冗餘的資源。這點還是很常見的,隨着遊戲開發版本不斷迭代,經常會出現之前做的一些東西被推翻了或者大改了(策劃或美術需要),這時候就會產生一些資源可能沒有被用到但是仍然留在工程中,如果打包時沒有相應地去掉,就會有無用的資源進版。

(3)檢查資源導入是否合理。比如:貼圖是否使用了正確的壓縮格式,動畫文件是否進行了合理的壓縮,打圖集是否合理,圖集裏是否有大量的浪費等等。

(4)如果經過檢查仍然沒有什麼進展,那隻能說你們的項目真的需要這麼大的資源包,爲了讓用戶能有較好的遊戲體驗,可以根據偉昊說的,規劃一部分資源在啓動後下載。這塊可以結合產品需要,做成啓動後一次性下載完或者根據遊戲進程一部分一部分下載。
感謝範君@UWA問答社區提供了回答

A2:說一個資源重複可能有些人沒注意到的點,就是同一份資源經常被改名放到不同的地方被不同的資源引用,經過實際檢測,這個重複量大過了我的預測,大家可以自測一下自己的項目。

感謝noah@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5dc0ea627307ec2f0f99a0e7


動畫

Q:我們的遊戲參考了UWA Blog上的那篇《GPU Skinning加速骨骼動畫》(https://blog.uwa4d.com/archives/Sparkle_GPUSkinning.html),發現真機環境幀數提升不是很明顯,連上Profiler發現開啓/關閉GPU Skinning總批次居然沒啥變化,SetPass Calls倒是變化明顯,在編輯器切到Android平臺我測試過總批次會提升100+,有點奇怪爲什麼到了Android真機裏沒什麼變化?

PS:原來角色動畫Animator + SkinMeshRenderer,使用GPU Skinning後換成了MeshRenderer同時把Animator勾去掉的。

A:可汗文章中單純的GPU Skinning並不是去降低渲染Draw Call的,只有結合GPU Instancing纔會降低Draw Call。GPU Skinning最主要降低的是Animators.Update和MeshSkinning.Update的耗時,如果在使用後,你發現這兩個值沒有變化或者優化不大,那麼十有八九是用法不對。

下圖是我們在UWA DAY 2019《如何根據UWA制定技術選型》(https://edu.uwa4d.com/course-intro/1/95)時做的具體的性能測試,裏面講解了多種不同方法所能達到的收益和限制,題主有興趣可以詳細查看。

使用GPU Instancing屏幕花屏問題

同時,我們將之前做過的一些定量測試放在這裏,希望大家對於GPU Skinning帶來的性能改變有更爲定量的理解。

——————————————

通過GPU Skinning方式

使用GPU Instancing屏幕花屏問題

該方法是完全摒棄Unity引擎的MeshSkinning和Animator模塊,自行對蒙皮網格進行採樣,將骨骼結點的矩陣信息以紋理的方式進行儲存,然後在GPU中完成頂點計算並直接進行渲染。優點在於極大地降低SkinnedMesh.Update和Animator.Update的CPU佔用。將骨骼結點信息通過紋理來進行儲存,因而數據量較之方案兒會大爲降低。

開源庫下載鏈接:
https://lab.uwa4d.com/lab/5bc6f85504617c5805d4eb0a

測試場景:
創建相同案例,場景模型數量分別爲50和200,各自測試1000幀,播放Walk動畫。

結果:
該方案測試效率如下圖所示,除Camera.Render外,MeshSkinning.Update和Animator.Update已經消失,但增加了GPUSkinning.Start和GPUSkinning.Update函數。通過分析可知,在紅米Note2設備上,開啓多線程渲染功能,測試幀數總計1000幀,50個模型的CPU平均耗時0.6ms;200個模型的CPU平均耗時1.6ms。

使用GPU Instancing屏幕花屏問題

圖1:使用GPU Skinning方案後,紅米Note2上的Top10 CPU佔用情況

使用GPU Skinning方案後,紅米Note2上的Camera.Render耗時情況。

使用GPU Instancing屏幕花屏問題

圖2:50個模型

使用GPU Instancing屏幕花屏問題

圖3:200個模型

使用GPU Skinning方案後,紅米Note2上的50個模型時的Camera.Render耗時情況。

使用GPU Instancing屏幕花屏問題

圖4

同時,GPU Skinning.Start和GPU Skinning.Update耗時在遊戲運行過程中很小,如圖5所示。

使用GPU Instancing屏幕花屏問題

使用GPU Instancing屏幕花屏問題

圖5:GPU Skinning.Start和GPU Skinning.Update耗時在遊戲運行過程中的CPU耗時

總結:
(1)該方案可以大幅降低Animators.Update和MeshSkinning.Update的CPU耗時,同時內存佔用較小小。以r_gunman模型爲例,其所有動畫文件時長8秒,如果採樣率爲30fps時,通過紋理來進行記錄,只需要128x128的紋理即可得到更爲精細的動畫數據;
(2)該方案對於GPU的壓力更大,需要研發團隊對GPU方面的壓力進行進一步權衡。

該回答由UWA提供,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5dccb9137307ec2f0f99a1ca


Render

Q:我是用世界座標去採樣一張Filter Mode爲Point的紋理,PC和Android真機上採樣是正確的,Mac和iPhone7/7Plus上採樣結果產生了偏移。

PC上的截圖(分別爲輸出UV和輸出採樣結果):

使用GPU Instancing屏幕花屏問題

使用GPU Instancing屏幕花屏問題

Mac上的截圖:

使用GPU Instancing屏幕花屏問題

使用GPU Instancing屏幕花屏問題

注意看網格線的對比,Mac上的採樣圖出現了偏移,但UV是正確的(爲了方便觀察,UV進行了縮放,採樣是用未縮放的UV)。

使用GPU Instancing屏幕花屏問題

有人碰到過類似的問題嗎?怎麼處理的?

A1:問題根源並沒有找到,目前採用了一個取巧的方案繞過該問題。

原本需求就是用世界座標採樣一張Filter Mode 爲Point 的紋理,因此直接在Shader中棋盤化採樣點,僞代碼:

float2 uv = floor(worldPos.xz / rectSize) / texSize.xy + 1.0 / (3.0 * texSize.xy);

(rectSize 爲棋盤格子的大小;texSize 爲採樣圖的大小)

最後加的那個值(1.0 / (3.0 * texSize.xy))是測試發現如果沒有該值,PC採樣結果和Mac下會有偏差,因此加上了三分之一個單位的偏移。
感謝珂@UWA問答社區提供了回答

A2:應該和這個問題類似吧,不過half pixel offset好像是bilinear filter纔會有的,point可能也有不同平臺採樣結果不一樣的問題。

https://docs.microsoft.com/zh-cn/windows/win32/direct3d9/nearest-point-sampling

https://docs.microsoft.com/zh-cn/windows/win32/direct3d9/bilinear-texture-filtering?redirectedfrom=MSDN

可以看看上面兩個鏈接有沒有幫助。

感謝noah@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5dd3539130e0542f29cd5b96


RenderTexture

Q:在同一個場景我先後使用不同的攝像機不同的角度拍攝深度,那麼應該得到多張不同的深度圖,我想了解Unity對這多張深度圖是怎麼管理的?比如:我只保留其中一張,其它的深度圖都不需要了,我該怎麼處理?

A:Unity默認渲染管線是多相機共享RenderTexture的方式,即多個相機逐一使用公共的CameraDepthRenderTexture繪製,每個相機繪製完是否Clear,取決於你下一個相機的ClearMode。至於RenderTexture的內存分配和管理,與你所有的相機是否開啓繪製深度有關,全部關掉繪製深度底層會釋放掉RenderTexture。如果要保留一張給下一幀使用,那麼建議拷貝出來,這樣不會影響下一幀其它相機使用。

感謝Wangtao@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5dce59497307ec2f0f99a224

封面圖來源:Unity GPU Instancing
GPU Instancing + Boids + Animation Texture Baker


今天的分享就到這裏。當然,生有涯而知無涯。在漫漫的開發週期中,您看到的這些問題也許都只是冰山一角,我們早已在UWA問答網站上準備了更多的技術話題等你一起來探索和分享。歡迎熱愛進步的你加入,也許你的方法恰能解別人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官網:www.uwa4d.com
官方技術博客:blog.uwa4d.com
官方問答社區:answer.uwa4d.com
UWA學堂:edu.uwa4d.com
官方技術QQ羣:793972859(原羣已滿員)

相關文章