2019年7月3日 星期三

關於Unity Project Decal的做法分析

Project Decal蠻常用來處理彈孔、魔法陣(AE範圍)、圓圓影…等貼花效果,在Unity下目前提供的方案是Projector,但目前這個方式使用MultiPass的做法,會造成畫二次(三角面暴增)及打斷Batching的問題。

未使用Projector的狀況:


使用Projector的狀況:



很明顯的,使用過Projector後,Draw Batches從39提升到56,而Tris從29.3K提升到42.1K

有沒有其他的做法呢?目前主流的做法是用一個Volume範圍(通常是用Box)加上深度貼圖來處理,在腳本運行的時候,時時計算這個投射矩陣,並帶入Shader,之後利用深度貼圖來計算投影的UV,最後只要把這個Volumle畫就來就行。其實這個概念跟Unity的Original Projector是差不多的,差別是在前者利用深度圖貼來計算投影UV,而後者則是利用多畫一次自己,再用自己的位置資料來當深度。

使用Volume Projector的狀況如下:


結果Draw Batches是40,只有增加1,而Tris只有多畫一個Box,所以看不出任何提升。

另外還有一種做法,是Polygon Projector,他是採用碰撞處理的方式,動態取得鄰近的三角面,並攤提UV的做法,這樣的方式最大的好處是比較不會發生投影超過二次以上的狀況(比方上下疊層),但缺點就是要算碰撞,如果碰撞引擎性能很好的話,其實效能也不錯,這是我當時在Ogre+Bullet引擎的實作,目前還沒實作出Unity的版本,相關影片如下…

2019年5月28日 星期二

如何使用Flow Map quads來實現互動水波

由於之前實現的水波系統,無法實現在無限大的水體,而且覺得目前美術使用特效的方式來處理航行特效,感覺非常生硬,完全跟水沒有互動感。最近看了flow map蠻流行的,看看有沒有實現的可能性,於是開啟了如何使用Flow Map quads來實現互動水波之路。

以下是大概的執行流程:
  1. 使用GPUInstance或Partilce system,時時噴射noise animation flow map quads,並處理好相關的alpha消失及scale漸漸變大的部份。
  2. 渲染到一張screen space的flow map。
  3. 在water渲染時,參考flow map,並依照flow方向及alpha權重,影響normal及泡沫的比重
結果如下:

2019年5月21日 星期二

Unity一些相關Shader Texture參數大坑及渲染過濾相關整理

Unity的shader Texture參數大坑相關整理:

  1. Blit時要將Input Texture Name改成"_MainTex",並切記在Properties加上
    _MainTex("Albedo", 2D) = "white" {},否則input會帶不進來…
  2. 用在非Blit,比方DrawMesh,切記不用使用_MainTex,否則會造成texture參數帶不進
    來,從LWRP的final pass的blit用的參數叫"_BlitTex",還有LWRP也把相關的Shader參數
    從"_MainTex"改成"_BaseMap"就可以略知一二…
Unity的渲染過濾相關整理:

  1. LayerMask:
    通常用在camera及physic的過濾,算是物件層級。
  2. RenderingLayerMask(SRP之後才支持):
    在物件過濾層級之後(Camera過濾),依渲染需求的不同,再過濾一次,比方可以用在
    即使用相同層級的LayerMask,也可以用程式動態設定RenderingLayerMask,來控制是否
    要進行渲染。 
  3. LightMode Tag(SRP之後開放給使用,之前是內部使用):用在渲染物件時挑方法來進
    行渲染,比方畫陰影挑ShadowCaster Pass、正常渲染則挑Forward Pass、畫額外時時光時
    挑Add Pass、畫Decal挑Decal Pass之類的,所以通常一個物件在同一個frame,有可能會
    被畫二次以上。
後記:話說Unity到目前還是不開放Camera剔除處理,雖然有人說在Camera做完之後用
RenderLayerMask再做自己的剔除,但我覺得這樣沒什麼用,因為他的Camera剔除處理早就已
經花了性能,還不如在他之前先把Renderer的enable設成false,但這樣其實他還是跑了
Renderer.enable != false的迴圈檢查,還是不好。

Dream continues in...

2019年5月7日 星期二

關於在2019LWRP下處理反射的問題

目前LWRP2019的release版,在處理Reflection時(自帶Relfection Camera,並有設定過Camera.targetTexture),且Depth Texture的flag也有打勾的話,會造成顯示不正常且一直噴Error log,後來使用不自帶RenderTarget的方式,並安插了一個在final pass之前拷貝渲染結果的pass,才把問題解決。目前這樣做,其實應該可以不用final pass,加個flag來判斷要不要做,如果還要走動態切換ScriptableRenderer的正式流程,覺得太麻煩,xd. 相關處理結果如下:

2019年5月3日 星期五

阿基拉的Unity世界大冒險之 VS ScriptableRenderer章 後記(相關SetRenderTaget的修改)

之前阿基拉曾經說對ScriptableRenderer動大刀,但實際的情況是沒這麼嚴重,算是做了一點小手術,不過由於已經不是原來的LWRP,所以還是得自行重新建立一份跟LWRP很像的海埔新生地(新大陸)到新的地方。

目前大概是做了這些手術:

  1. ScriptableRenderPass.cs:

    //add by akilar, append a flag for check need set render target
    public virtual bool IsSetRenderTarget() { return true; }
  2. ScriptableRenderer.cs:
    //add by akilar
    void ExecuteRenderPass(ScriptableRenderContext context, ScriptableRenderPass renderPass,
        ref RenderingData renderingData)
    {
        //add by akilar
        if (!renderPass.IsSetRenderTarget())
        {
            renderPass.Execute(context, ref renderingData);
            return;
        }
        ...
        //modify by akilar, disalbe first check setting, only check need reset render target
        /*if (passColorAttachment == m_CameraColorTarget &&
               !m_FirstCameraRenderPassExecuted)
        {
            m_FirstCameraRenderPassExecuted = true;
            ...
        }
        // Only setup render target if current render pass attachments are different from the active
            ones
        else*/

        if (passColorAttachment != m_ActiveColorAttachment || passDepthAttachment !=
            m_ActiveDepthAttachment)
        {
            SetRenderTarget(cmd, passColorAttachment, passDepthAttachment, renderPass.clearFlag,
                renderPass.clearColor);
        }
        ...
    }
狀況如下…


跟LWRP的恩怨情仇持續中…讓我們繼續看下去…

2019年4月30日 星期二

阿基拉的Unity世界大冒險之 VS ScriptableRenderer章最終回

雖然阿基拉已經讓ScriptableRenderer放下心房,讓出了可以調整SetRenderTarget的地方…但是後來深入到設定SetRenderTarget的地方,才發現ScriptableRenderer其實還留下了一道最後的防線,就是m_FirstCameraRenderPassExecuted並搭配GetCameraClearFlag的機關,等於之前做過任何的努力都會被這道機關清除,而且最致命的是這道機關完全沒辦法被調整…

後來阿基拉決定放棄以最小的變動調整這個堅持,打算直接對ScriptableRenderer動大刀了…不再讓它這麼囂張,打掉他對於SetRenderTarget的控制,但這樣一來整個LWRP這塊大陸都得重新移位到新的海域,為了跟之前的大陸有所區隔,只好重新建立一份跟LWRP很像的海埔新生地(新大陸),把原先的LWRP拷貝過來…真是一大工程…

也許這樣很難跟組織交待,但目前也只能這麼做了,誰叫LWRP這麼機車,又臭又硬,完全動不了…

跟ScriptableRenderer的恩怨情仇結束中…讓我們繼續看下去…

2019年4月27日 星期六

阿基拉的Unity世界大冒險之 VS ScriptableRenderer章初回

阿基拉,橫渡過FFT projected grid ocean的技術宅,這次被組織奉命調查Untiy世界發生了SRP板塊突然從海底升起的事件,尤其是LWRP這一塊,被要求以最小的變動在上面搭建渲染基地

然而在上面有一個叫ScriptableRenderer的魔獸,他擁有著堅硬無比的外殼駐紮在中間,完全無法觸碰到需要調整SetRenderTarget的地方,但好在附近有一個MainLightShadowCasterPass,他有機會可以跟ScriptableRenderer溝通,於是阿基拉靈機一動,想透過MainLightShadowCasterPass來告訴ScriptableRenderer不用擔心SetRenderTarget,因為沒人設過,但又被ScriptableRenderer的Configure防護給識破…

後來阿基拉決定跟MainLightShadowCasterPass勾結,開inteface這個後門來欺騙ScriptableRenderer,讓他誤以為阿基拉跟MainLightShadowCasterPass是同伙,於是才破解ScriptableRenderer的心防,讓出了可以調整SetRenderTarget的地方…

冒險持續中…讓我們繼續看下去…