1)非2的冪次的ASTC紋理格式尺寸對帶寬的影響
2)C#端如何處理xLua在執行DoString時候死循環
3)如何制定美術規範或者各個模塊的指標
4)如何處理Lua的io.open出現中文路徑
這是第348篇UWA技術知識分享的推送,精選了UWA社區的熱門話題,涵蓋了UWA問答、社區帖子等技術知識點,助力大家更全面地掌握和學習。
UWA社區主頁:community.uwa4d.com
UWA QQ羣:465082844
Texture
Q:有一張UI紋理尺寸1200x554,紋理格式ASTC 4x4,顯示佔用內存0.6MB,將MaxSize改為1024,佔用內存476KB。
除了內存的降低外,想請問下對帶寬或其他性能的影響大麼?
紋理類型是Default,Advanced -> Non-Power of 2 -> ToNearest/... 選項,但是UI沒有,UI是否也有必要自己實現ToNearest?
A:題主可以參考一下知乎的這個回答:
https://www.zhihu.com/question/376921536<br/>
也可以參考:
https://gamedev.stackexchange.com/questions/26187/why-are-tex...<br/>
簡單來説有如下幾個信息:
- GPU的尋址是按塊進行的,ASTC紋理的壓縮也是按照塊進行壓縮的,因此貼圖尺寸最好符合這個設定;
- 不滿足的貼圖通過補充額外空間來滿足對應的需求,這裏會有部分的空間浪費。<br/>
具體到題主的問題:
- 將MaxSize設置為1024,其實是減少了貼圖尺寸,內存/顯存佔用變少是肯定的;
- 貼圖尺寸降低,肯定是會減少帶寬消耗,也有可能提升顯存的採樣命中率,包括加載方面因為文件大小變小都會有提升,但這些“好處”未必那麼好量化,比較明顯的應該是帶寬降低。
- UI的貼圖通常會做合圖的操作,因此很多UI自身是不需要做尺寸上的要求的,但是如果不合圖的話,整體上還是建議按照power of 2的尺寸在做設計,這種規範比較簡潔清晰,容易執行。
感謝賈偉昊@UWA問答社區提供了回答
Script
Q:我使用xLua作為遊戲的內嵌腳本語言,允許玩家自定義腳本。
現在有個玩家在腳本里面寫了一個死循環,當我用DoString去加載這個腳本時候會直接卡死,於是我在外面加入了一個Task:
var isSucceed = false;
var task = Task.Run(() => {
isSucceed = sandbox.DoString(xxxx)//這裏簡化一下.核心就是加載這個腳本執行DoString
});
bool isCompletedSuccessfully = task.Wait(TimeSpan.FromMilliseconds(1500)); //1.5s timeout
if (!isCompletedSuccessfully)
{
CELog.LogError("加載腳本超時");
isSucceed = false;
luaEnv.Dispose(); //Kill掉當前的Evn
return; //不再加載後續腳本
}
現在是隻要調用‘luaEnv.Dispose()’編輯器就直接閃退,無論是這裏Timeout了調用,還是等幾秒以後。
我感覺是因為Task的Timeout只是在超時後回調,但是此時Lua還在死鎖中,所以我無法Dispose。
官方的FAQ提了一句:
調用LuaEnv.Dispose崩潰。
很可能是這個Dispose操作是由Lua那驅動執行,相當於在Lua執行的過程中把Lua虛擬機給釋放了,改為只由C#執行即可。
感覺和我這個情況是一樣的,這種情況我應該怎麼處理?
A:在外部結束Lua虛擬機肯定是有很大崩潰風險的,我覺得有兩個思路供參考:<br/>
- 建立一個完整的沙盒環境,類似Dock,這個環境內運行邏輯,外部可以把這個環境銷燬掉,不會對外部造成任何影響,這個在Unity下可能難度比較大,要做邏輯和表現的分離,然後構建一個純邏輯層的運行環境。<br/>
- 在Lua虛擬機內部監測死循環的情況,然後自主中斷,拋出Error。這個是我們現在在用的方式,改造Lua虛擬機,監測一定時間內一直在執行某些字節碼超過一定閾值就認為自己是在死循環把自己結束掉。當然還有一些別的條件,比如棧深度檢測等等。這種自主中斷並且拋錯的方式其實更加完美。具體實現可以參考這個文章的思路:
https://ld246.com/article/1522147783147<br/>個人是比較推薦第二種方案的,也是很多項目驗證過的,對於UGC類型的遊戲,檢測並能提醒用户編輯出來了死循環非常重要。
感謝賈偉昊@UWA問答社區提供了回答
Performance
Q:在UWA問答上看到了《項目初期如何確定美術規範》這個問題的回答,感覺還是不太理解,好像這個問題是不是隻能憑經驗,或者通過工具不斷地去趨近那個指標,並沒有一個指定規範,像是從面數什麼之類的來計算?比如,我同屏10人,角色面數5000,渲染模塊耗時不超過12ms之類的,有沒有一定的公式去量化到美術的一個指標?感覺大部分好像不是根據經驗來去做這個樣的一個規範,或者是參考競品之類,UWA給的項目測量好像也沒有具體的計算方式,我感覺應該是定一個基準機型,然後再去做項目的各個模塊的參考,然後才得出美術或者其他的指標。問下有沒有更好的辦法,最近看到有根據能耗來計算然後得到各個模塊的指標,有大佬有了解過這方面的知識嗎?
A:具體的信息在題主引用的問答裏面已經有很多的討論了,從我個人的經驗來看,還沒有什麼更好的辦法,主要原因在於性能結果受到的各個方面的影響因素特別多。
比如,同樣機型上跑40w面的畫面,Shader的複雜度差異就可能讓一個GPU滿負載而另外一個還有很大的空餘量;再舉一個例子,同樣的一個畫面,如果你的CPU很閒,也許你就可以用一些OC算法大大降低最終畫面渲染的消耗,當然,GPU有富裕也可以用GPU-Driven這樣的思路來做更加高效的剔除。
因此,不同的遊戲類型,不同的人來做,都可能達到完全不同的性能結果。我們定義一個機型,給定一個經驗值或者參考競品的美術資產規範,往往是保證在使用相同引擎相似技術的情況下能夠保證性能的底線。這個基於經驗或者參考設定的規範和指標最大的意義在於告訴你可行性,如果最終遊戲的性能沒有達成到預期幀率,你可以參考其他遊戲或者常規的優化方式來儘量接近可行結果,當然,你也可以通過修改引擎或者渲染管線,抑或其他Trick的方式來超越這個規範,這就取決於團隊能力了。除此之外,規範也是要不斷根據項目的實際情況進行調整的,而非完全的一成不變。
因此想根據一個公式,可以直接量化出一個規範,這個想法可能有些過於理想,這個公式裏要考慮的因素太多,每個因素之間又有互相的影響,最終我們做性能優化的時候,也常常是在這些因素之前進行平衡——比如GPU Bound了就看看是否可以拿CPU換一些計算量出來,CPU Bound了是否可以用內存來換?
至於基於能耗來計算指標,我們往往是反向的,就是當一個優化做好之後,或者上了一個新Feature之後,我們會通過控制其他變量,單獨開關這個Feature來查看它帶來的能耗變化(我們的統計方式是基於電流表的,理論上比接口採集的數據更加符合實際情況)。而且在這個過程中能耗是波動的,不是穩定的,所以基本無法測量出增加一個面有多少能耗的增加,增加一個DrawCall有多少能耗的增加,更何況影響能耗最多的往往是帶寬。
所以,整體上基於已有的經驗來看,非常準確地量化消耗或者能耗,是一件很難的事情,不同設備可能會有不同,不同項目也可能會有不同,我個人是持悲觀的觀點。在實際工作中,主要基於經驗和參考來制定一個大致的規範,然後在正式的資源與功能不斷完成之後去迭代和完善這個規範。
如果題主探索出了可量化的路徑,也歡迎分享~~
感謝賈偉昊@UWA問答社區提供了回答
Script
Q:關於Lua的io.open出現中文路徑,有辦法處理嗎?
如以下的代碼,不同版本Lua有不一樣的結果,我的Lua 5.1會出現Invalid Argument,用5.4創建了一個亂碼文件,因為有時候避免不了中文目錄,像Windows平台下有人用了中文用户名,就會出現“C:/User/中文用户/AppData”之類的路徑。
local path = "C:\\新建文件夾\\test.txt"
local file, error_msg = io.open(path, "w")
if file then
file:write("這是一個示例文本文件。\n")
file:close()
print("文件創建成功。")
else
print("無法創建文件。", error_msg)
end
A:網上搜到一篇文章,僅供參考:
https://juejin.cn/s/lua%20io.open%20%E4%B8%AD%E6%96%87%E8%B7%...另外就是如果文件內容並不是一定要在Lua中處理的,也可以讓C#去做對應的文件操作。
感謝賈偉昊@UWA問答社區提供了回答
封面圖來源於網絡
今天的分享就到這裏。生有涯而知無涯,在漫漫的開發週期中,我們遇到的問題只是冰山一角,UWA社區願伴你同行,一起探索分享。歡迎更多的開發者加入UWA社區。
UWA官網:www.uwa4d.com
UWA社區:community.uwa4d.com
UWA學堂:edu.uwa4d.com
官方技術QQ羣:465082844