2023年2月21日 星期二

Projected grid的方案(無限大海洋方案基礎模組-URP+SRP)

許多人可能直接拿一些水插件就直接套上專案,但在開發中後期可能會發生許多整合方面的問題,這時候花些時間理解其中組成的模組是必要的,甚至還可以達到客製化的目的,而projected grid就是無限大海水方案的基礎模組之一。

2023年2月10日 星期五

關於FairyGUI或GUI以StackingCamera受到RenderScale影響的解決方案

自從URP問世之後,ScaleRender便在Unity成為主流,他是優化行動裝置3D渲染的一個好方法,當然之前也是有不少人在默認管線下做過這類的應用…

後來URP也加入了類似默認管線疊合(Stacking)渲染的處理流程,但稍微有研究的人就會發現他會受RenderScale參數的影響,如果拿來畫UI的話,那有關字及ICON的顯示可能會是場災難。
有人說那就用Overlay模式來畫UI就好,但專案還是會有一些特殊的需求要用Camera來畫,另外像FairyGUI大部份都是用Camera來渲染的系統,就影響很大了,也總不能為了UI的品質來禁用RenderScale的參數。

之前沒使用過FairyGUI,因為工作關係接觸了之後,發現他與URP整合上有一些問題,主要是大部份都是用Camera來畫,這樣一來就得走StackingRender的流程,不像UGUI還有Overlay模式可用,於是開啟了FitRenderScaleURP之旅。

2023年1月9日 星期一

簡單的FragmentShader light culling forward plus(面向行動平台)

最近Forward plus成為比較熱門的渲染管線之一,連Unity在新版本也在開發中,他採用的方式是用Job來做culling,我自己實作的方式是用ComputeShader來做culling,相關連結如下:
AkilarLiao / ForwardPlusURP
但目前這些主流的做法,幾乎都會用到SSBO,另外內存的使用也比較大,想一想其實上帝視角Z值的疊合狀況不是那麼嚴重,所以在想有沒什麼簡單的方式,可以單純使用一個FragmentShader來處理像素等級的剃除,於是開啟了FragmentShader light culling forward plus之旅…

2022年12月31日 星期六

用MRT來優化SSAO在行動平台的性能

 對於行動平台使用深度貼圖,有經驗的人應該都知道Unity曾經不管三七二十一,只要是gles,一律走perDepthPass,而不走CopyDepth的流程,其實這個限制應該只是有在使用硬件MSAA的時候,才有這個問題,這曾經困擾了許多人,後來官方在新的版本做調整,讓大家鬆了口氣…

我在測試官方的ScreenSpaceAmbientOcclusion時,發現他的Depth Normals模式,不管是不是AfterOpaque,一律都走perDepthNormalPass,這對行動行台非常不友善,就跟perDepthPass是一樣的問題,雖然他有提供純Depth模式+AfterOpaque可以避免這個問題,但沒有normal效果就是比較差,所以便開啟了MRT + SSAO之旅(許多人把MRT跟延遲渲染畫上等號,但其實是可以應用在優化處理上)

2022年12月26日 星期一

VRM and QT初體驗(QT+VRM+UDP+Unity)

最近VTuber+VRM蠻紅的,想說也來把玩一下,另外很久沒有做embed 3d engine into native application,於是開啟了QT+VRM+UDP+Unity之旅,雖然之前是有開發過Ogre3D+MFC的工具,但embed Unity into QT還是第一次,由於Unity沒提供任何對外溝通訊息接口,在Google上找得到的解決方案,都是導向本機UDP訊息傳輸的做法,所以只好硬著頭皮做QT+VRM+UDP+Unity…

關於VRM整合的部份,請參考vrm-c / UniVRM,由於VRM1.0有整合自動撥放表情,所以就以整這個為主,但由於目前的版本只支持runTime parse的做法,所以這邊另外寫了一個可以輸出prefab的相關功能,並將相關的貼圖、mesh、材質保存出來(跟univrm插件差不多),這樣可以大大減少runTime parse的時間及達成資源共用的目標。

相關視頻結果如下:(可選擇右邊的QT button來切換動作撥放的狀態)


後記:之後再來看看動捕的部份…

Dream continues in...

2022年6月8日 星期三

關於超大地圖Recastnavigation尋路資料建立的做法

 由於專案有複雜超大地圖(unity單位15000*15000)的需求,在Recast資料建立上遇到了一些問題…

  1. 整塊大地建立不出來,發生了以下的錯誤…
    if (maxVertices >= 0xfffe)
    {
            ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices);
            return false;
    }
  2. 就算是分了區塊,但因為Recast底層建立的函式,無法並行建立,所以造成了建立時間過久的狀況(超過一天以上)
解決方案:
  1. 自行實作一個建立console工具程式,並用批次檔來運行多個執行檔,來達到並行建立區塊的目的。
  2. 最後將相關的區塊移到unity裡來進行彙整,並輸出跨區域尋路的整塊地圖。
利用美術的相關模型生成柱狀體檔格資料:(原本可以直接使用美術的mesh直接生成,但因為資料容易有不合法的問題及因為專案只需要2D的尋路,所以為了減少生成問題,使用了這個方式)




















利用外包計算(其實只是做格子的拜訪)的演算法,來算出各區塊的包覆範圍,分割地圖區塊:


將各個Console程式計算的區塊地圖彙整到unity,進行地圖合併及提供之後計算跨區域路線計算:



















計算跨區域路線,並存檔,完工…



















後記:實測建立時間可以節省2/3以上,目前覺得還要回來unity進行合併,多了一個步驟,不知道之後有沒辦法分塊,合併及路線計算能在一個步驟就完成,以下是相關的視頻:

2021年10月27日 星期三

關於GPUInstance與GPU VS CPU culling的恩怨情仇

大家應該都知道GPUInstance是拿來畫大量物件的重要利器,但他最大的問題,就是沒有處理Culling,當拿來畫同一種巨量草之類的,面數少的話,應該是沒什麼問題(同種類,只需傳送一次Mesh資料,數量多的話,因為面數少,所以vertex shader處理次數少,也還ok)。但當我們把鏡頭拉近的時候,其實剔除處理就變得很重要,否則有可能GPU instance會比一般用page culling的drawMesh API性能還來得差…


那我們如果幫GPUInstance也切page的話,情況就會變好嗎?其實不一定,在拉近的時候,太多數的情況是還蠻OK的,但如果有拉遠鏡頭的需求,會導致DrawInstance的API呼叫次數變多,進而導致mesh傳輸量增加,這種狀況下反而切page變成是一種負優化…

最近比較流行的是直接使用GPU+ComputeShader來做GPU culling,並搭配DrawMeshInstancedIndirect這個API來畫,聽起來似乎是蠻理想的方案,但他最大的問題,就是當鏡頭拉近的時候,如果種類非常多,由於數量是由GPU直接算出來的,CPU完全不知道,所以還是得直接呼叫DrawMeshInstancedIndirect這個API來畫,就算GPU算出來的數量是零,還是導致了把mesh傳輸到GPU,造成了負優化,尤其是當種類越多,這個問題會越嚴重…另外還有硬體支持度的問題…

所以種類物件越多的場景,如果想全場景GPU instance化來提升性能,目前可以想得到的方式就是使用CPU+JobSystem來處理剔除,整個處理流程如下:

  1. Page Culling,看是要用八元樹還是四元樹,請隨意
  2. 依CullingPageList,將其送到JobSystem來進行剔除處理
  3. 等Job IsCompleted後,將其資料拷貝到相關要畫的陣列中(動態蒐集陣列資料)
  4. 畫出所有instancer的物件(這時候只會畫真正在視野範圍內的物件)


試著在紅米三,種類高達127種,測試物件數量高達到30000個左右的正式場景,物件面數約幾百面到2000面左右,有搭配LOD來優化,鏡頭不論遠近,FPS幾乎都頂在60(在優化前,是使用一般的DrawMesh+PageCuling,性能從35~40提升到頂60),目前也支持跨硬體API的架構(也就是會視硬體狀況,自動切換DrawMeshInstancedProcedural、DrawMeshInstanced、DrawMesh API,而且Shader都是同一個,目前的狀況是會多了一個變體),以下的測試案例是100個種類,250000個物件,相關運作狀況的影片,請參考…