這是第226篇UWA技術知識分享的推送。今天我們繼續為大家精選了若干和開發、優化相關的問題,建議閱讀時間10分鐘,認真讀完必有收獲,
UWA 問答社區:answer.uwa4d.com
UWA QQ群2:793972859(原群已滿員)
本期目錄:
關于_CameraDepthTexture的疑惑
貼圖Alpha通道對圖片大小的影響
URP如何實現GrabPass的效果
如何獲取AssetDatabase加載失敗的Asset的Instance ID
如何判斷Bundle檔案加載進記憶體的時機
Rendering
Q:一個關于_CameraDepthTexture的疑問。
如果開啟_CameraDepthTexture,Camera就需要渲染一遍場景內所有帶有ShadowCaster的可見物體的Pass來實現深度圖。
但是場景中的物體在開啟ZWrite的時候就把深度寫進了Depth Buffer中了,直接獲得這個Depth Buffer是不是比近乎DrawCall翻倍的方式更有效率呢?還是Unity在這方面有什么考慮?
另外,問一個更實際的問題:
我們的專案需要渲染場景的中湖水的深度效果,所有不透明的場景物體的材質都是關聯同樣一個Shader,這個Shader是帶有ShadowCaster的,但是只有個別插入水中的物體需要去渲染ShadowCaster的Pass,有沒有方法在不增加Shader的情況下,讓沒有插入水里的物體不渲染Shadow Caster Pass呢?我們用的是Built-in的渲染管線,
A:第一個問題,可以參考這個問題中Unity官方人員的回復,
里面講了兩個原因,第一是對于非全屏渲染的情況,本來是想拿對應相機渲染的深度,但是Depth Buffer是全屏的。第二個原因是因為很多平臺不支持直接拿Depth Buffer的資料。
參考網頁:
https:http://forum.unity.com/threads/poor-performance-of-updatedepthtexture-why-is-it-even-needed.197455/
另外查FrameBufferFetch相關問題的時候看到Unity論壇上另外一個貼子里面的回答。里面說到Unity支持了FrameBufferFetch,但是不支持DepthBuffer的獲取。
參考網頁:
https:http://forum.unity.com/threads/pixel-local-storage-and-frame-buffer-fetch-on-mobile-devices.604186/
第二個問題,如果不增加Shader,目前沒想到其他好的方法。
如果可以增加Shader,可以將原來的Shader復制一份,只在ShadowCaster的部分加一個“NeedDepth”這樣的Tag,將水下的物體的材質球換成這個Shader,另外做一個只有ShadowCaster并帶有“NeedDepth”這個Tag的Shader,這個Shader用來做Replace操作。
額外增加一個Camera,這個Camera跟隨主相機,或者作為主相機的子節點,創建一個RT,讓這個Camera渲染到這個RT,在Update里面使用ReplaceShader去畫一下,那么只有有那個Tag的ShadowCaster會進行深度渲染,后續可以對這個RT進行編碼等操作,這個RT記錄的就是水下物體的深度。整個過程看上去沒有特別多的額外工作,覺得可以一試(我沒有做過測驗,但理論上是可行的),
感謝Xuan@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https:http://answer.uwa4d.com/question/5fa4f888dc477370c2c1f07f
Texture
Q:在UWA的這篇文章中,描述了圖片含有Alpha通道會對記憶體有影響。
通過以下的測驗資源配置:
Tga_Alpha – 含有Alpha通道
Tga_NoAlpha – 不含有Alpha通道
Png_Trans – 含有透明的圖片
進入到Unity中的Format,全部代碼設定為TextureImporterFormat.ASTC_6x6
測驗結果:
三張圖片Unity全部Format為下圖格式
三張圖片顯示的記憶體大小全部一樣
Texture Importer的Alpha Source設定為None,對測驗結果無影響
問題:圖片是否含有Alpha通道,對于同一個Format格式,記憶體大小都是一樣的嗎?
(Demo可戳原問答獲取,)
A:原文中的優化建議是去除無意義的Alpha通道(原文中的定義為Alpha值全部為1的貼圖),這個確實是對記憶體優化有幫助的,
題主的測驗用例中,無論是png格式還是tga格式,進入引擎后,都會被引擎轉為內部的格式(RGBA、ETC、ASTC等),設想一下,以ETC2為例,如果沒有Alpha通道,在壓縮質量可以接受的情況下,就可以選用RGB_Compressed_ETC2_4bits,而如果添加了這個無意義的Alpha通道,那么我們在批量匯入設定時,都會自動選擇RGBA_Compressed_ETC2_8bits,這樣記憶體就相差了一倍,
而問題中關于ASTC的情況,在Unity編輯器原始碼中的Texture匯入格式(http:http://dwz.date/dfDB)的定義有這樣一句注釋:http:// ASTC uses 128bit block of varying sizes (we use only square blocks). It does not distinguish RGB/RGBA,即與是否包含Alpha通道無關,關于ASTC格式的介紹,這里推薦你閱讀一下Github上的ASTC Format Overview(https:http://github.com/ARM-software/astc-encoder/blob/master/Docs/FormatOverview.md)。
而關于你樓上回復中提到的Unity新版本的問題,可以看下Unity論壇上的這個問題:
https:http://forum.unity.com/threads/is-astc-rgb-encode-gone.660622
可能有人覺得對于專案的貼圖格式都是ASTC來說,去除Alpha的意義不是很大,其實不能一概而論,雖然大小相同,但根據(https:http://zhuanlan.zhihu.com/p/158740249)中的測驗,是否有Alpha通道會一定程度上影響壓縮質量,所以還是要在專案中合理使用,
感謝范君@UWA問答社區提供了回答
A2:游戲運行時Texture的Alpha通道要看匯入后的情況,不能看源檔案的情況,UWA本地資源檢測對于Texture的Alpha通道檢測的就是匯入后的結果。
圖片源檔案的格式,圖形硬體是不支持的,Unity也不直接接管,匯入圖片后,會按照Import Settings中的設定對圖片進行處理,將圖片匯入成硬體支持的格式(在引擎中的格式),而在運行中使用的資源也是匯入后的。
題主將Alpha Source設定為None,那么匯入時就不對源檔案的Alpha通道進行匯入,而壓縮格式為ASTC_6x6,這個格式是包含Alpha通道的。這樣匯入后三個資源都會默認生成一個全為1的Alpha通道,占用記憶體大小自然一樣。
感謝Prin@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https:http://answer.uwa4d.com/question/5fa25e7cdc477370c2c1f015
Rendering
Q:URP如何實現GrabPass的效果?URP管線已經去掉了原先GrabPass的功能,現在有一個扭曲特效的功能,類似熱擾動那種,雖然URP能夠直接獲取到物體圖做扭曲效果,但是像是半透明物體(比如:水、其他特效等)也需要被扭曲就做不到,
A:題主想要完全實現GrabPass估計不行,但是可以有替代方案:
GrabPass的意思就是先繪制a物件,然后繪制b物件的時候影響a,繪制c物件的時候影響ab。注意,這最重要的是b物件的擾動影響不了c物件,因為b物件是比c物件先繪制的,
但是如果你能夠接受b物件和c物件的擾動同時影響abc,那么就簡單了,先用一個RT將扭曲的資訊存下來(其實就是UV偏移),然后在Uber Shader中將偏移應用在畫面上。這樣扭曲資訊就擾動了所有物件(不管是不透明還是半透明)。
雖然不知道URP怎么實現的,但是我們自己改的SRP,就是這么實現的。
感謝王爍@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https:http://answer.uwa4d.com/question/5fa5040fdc477370c2c1f080
Editor
Q:現在有一個繼承于ScriptableObject的Asset,無論出于什么原因,引用腳本的GUID錯了,那么通過一定的編輯器腳本能找到這個Asset的Path,但是如何在ProjectView內選中它?
經測驗,使用Selection.instanceID是可以選中的,而Instance ID一般需要通過Object來獲取,但是因為腳本引用錯誤了,所以AssetDatabase是無法載入這個Object的。有什么辦法或者API能獲取到這個Instance ID呢?
A:通過查看公開原始碼,找到了一個可用的方法:
http://assetPath : 某個找不到對應腳本的Asset實體路徑
HierarchyProperty property = new HierarchyProperty(assetPath);
Selection.activeInstanceID = property.GetInstanceIDIfImported();
這樣可以在ProjectView內正確選中了。
感謝題主黃程@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https:http://answer.uwa4d.com/question/5f9fc6fadc477370c2c1efd9
Addressable
Q:當下載好所有的資源后,在一個測驗腳本中呼叫LoadAssetAsync函式,如下圖:
在AssetBundleProvider這里是第一個疑惑:
既然Addressables全部采用快取機制來存放AssetBundle包,那此處的File.Exists不是總會為False嗎?
第二個疑惑在于:
Addressables在WebRequest完成下載后,如何把握把Bundle加載進記憶體的時機?也可能是我的思路有問題,但是在后面的堆疊追蹤里面沒有發現有類似于LoadFromFile這樣的呼叫,
A:這兒的File.Exists并不是檢查快取,而是檢查檔案在不在StreamingAssets里面,而所有下載的資源則是通過快取來獲取的,若快取里沒有則下載,而Load這部分已經被封裝在了UnityWebRequestAssetBundle內了,
https:http://answer.uwa4d.com/question/5fa0d4f1dc477370c2c1effc
封面圖來源于網路
今天的分享就到這里,當然,生有涯而知無涯。在漫漫的開發周期中,您看到的這些問題也許都只是冰山一角,我們早已在UWA問答網站上準備了更多的技術話題等你一起來探索和分享。歡迎熱愛進步的你加入,也許你的方法恰能解別人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官網:www.uwa4d.com
官方技術部落格:blog.uwa4d.com
官方問答社區:answer.uwa4d.com
UWA學堂:edu.uwa4d.com