前提:美術很隨意得使用貼圖、材質,大量的材質雖然名稱不同,但是實際上材質屬性是相同的。
於是,在匯出時,在依次處理材質時,應該將新的材質屬性與已經收集到的材質進行對比,如果是相同的,則使用已存在的材質。
同時,雖然mesh中的submesh其實是根據MatID來作劃分,但是一般情況下,mesh中的submesh的vertex decl通常是完全相同的。
那麼其實可以將所有相同的vertex decl的submesh合併在同一個geometry(VB)中,submesh使用不同的index buffer來繪製,減少繪製時的VB切換。
於是,就有了shared geometry的共用,如果submesh的vertex decl與之不同(例如ABC是diffuseMap,DE是diffuseMap + specularMap,FGH是diffuseMap + specularMap + normalMap),則自己使用獨立的geometry來繪製。
另外,還要對於mesh中所有的submesh所使用的material進行排序,以減少不必要的state切換。
而且還有一個好處是,material的數量、mesh的大小都會減少,意味著減少了磁碟IO和檔案解析所需要的時間。
接下來,就是本文的重點出現了。
問題總有2個:
1. 想象中優化後的場景目錄的檔案數量和大小,都應該會相應減少。但實際中發現,的確大多數模型資料都減少了十幾K到幾十K不等,但是少數模型的mesh尺寸變大了。
這個現象很奇怪,為了分析原因,我使用了工具對兩者進行了二進位制對比。
有意思的是,變大的檔案,例如之前的十六進位制資料為: AB CD EF GH,變大的資料變成AB CD 00 00 EF GH 00 00。
經驗告訴我,肯定是某些原先使用16bits描述的數值,現在變成32bits了。
相信朋友們已經猜到了原因,即合併submesh之前,每一個geometry大小都是65535以內,於是16bits IB就夠了
合併之後,vertex數量超過了65535,於是我的匯出外掛自動切換為32bits IB來描述了
通過搜尋資料,瞭解到10年前的GPU對於32bits IB的處理,除了頻寬上略有影響之外,並不會有額外的效能懲罰
而隨之優化帶來的batch減少以及VB等state切換所帶來的FPS提升,我的結論是這樣的優化是值得的
進一步的優化思考是,我目前是使用的triangle list儲存的IB,即一個face使用3個index;如果改為triangle trip,那麼IB是很有可能控制在65535之內的
2. 美術不一定會將同一個物體的多個子物體合併(Attach),例如手機:顯示螢幕、外殼、電池、天線,是分開為多個mesh存在,然後合成一個group。
這樣子並不會影響實際使用中的操作,因為畢竟scene中還是有一個叫“手機”的node。
但是理論上,我們還是希望這幾個物體合併在一起,甚至想到說,既然上述的material和geometry的優化,那為什麼不把整個場景都在匯出時自動merge到一起呢?
然後我想當然得寫了一個maxscript,在匯出之前會自動將場景中所有的mesh合併在一起。
但是實際情況是,雖然感覺上應該會更流暢,單個scene在觀察時也會有些許提升,但是當畫面是由多個scene分塊構成時,camera frustum的cull就廢掉了。
哪怕只有scene A的一棵小草被看到,整個scene都會被繪製出來,反而會影響到渲染效率。
優化無止境,同學需努力。