主題

【Shader 學習筆記:畫面模糊特效】 關於OnRenderImage 無法在SRP上被呼叫的替代作法

%%鼠 拒收病婿 | 2020-12-26 20:30:39 | 巴幣 120 | 人氣 962

這次的參考影片是這個:

如果是用SRP (scriptable render pipeline),還沒打到5行程式碼就會卡住,原因是SRP 不支援 OnRenderImage這方法。
SRP又分成URP和HDRP, URP比較輕量,HDRP效果好但吃效能。

如影片內容,在原本的渲染系統上,只需簡單幾行就能做到:


void OnRenderImage(RenderTexture src, RenderTexture dst)
    {
        Graphics.Blit(src, dst, effectMaterial);  
    }

OnRenderImage(RenderTexture src , RenderTexture dst )
在camera結束render後,傳入畫面結果(src),進行操作後將結果傳給dst輸出。

Graphics.Blit(Texture src, RenderTexture dest, Material mat)
Blit sets dest as the render target, sets source _MainTex property on the material, and draws a full-screen quad.  (把src設成mat的mainTexture,並套用在dest上,然後畫成full-screen quad。)

想要簡單弄個後製效果所以選了URP,但又想額外打些shader,就不得不想個辦法取得螢幕結果。


最終結果:



問題來了,URP少了OnRenderImage,那要如何後製整個畫面的結果?

我一開始參考了這個影片和這串討論:

但不是我想要的,這些作法是將特定圖層的物件shader用別的取代上去,而非後製整個螢幕結果。

比較類似的是這部教學,但進入影片中的官方repo時發現腳本都不同了,且單包抓下來又一堆error要除。

後來爬到這篇,裡面說了以下這些srp都不再支援:

  • OnRenderImage
  • OnPostRender
  • OnPreRender
  • OnPreCull

而類似的作法是將方法註冊在RenderPipeline.beginCameraRendering 或 RenderPipeline.beginFrameRendering 事件上。 其中RenderPipeline已經是舊的語法,現在改為RenderPipelineManager。
在官方blit的文件上也有提到:
《If you are using a Scriptable Render Pipeline (like HDRP or Universal RP), to blit to the screen backbuffer using Graphics.Blit, you have to call Graphics.Blit from inside a method that you register as the RenderPipelineManager.endFrameRendering callback.》

我的作法有些粗暴,在main camera下面放另一個camera,當成原本OnRenderImage方法的src,負責傳入當前的畫面Texture。

程式只貼重要的:
    RenderTexture render_Tex;
    public Material effectMaterial;
    public Camera renderProviderCamera;
    public Camera mainCamera;
    public int facter = 4;

    public float magnitude = 0.25f;
    readonly string _magnitude_name = "_Magnitude";

void OnEnable()
    {
        mainCamera = Camera.main;
        render_Tex = new RenderTexture(mainCamera.pixelWidth >> facter, mainCamera.pixelHeight >> facter, 16);
        renderProviderCamera.targetTexture = render_Tex;
        effectMaterial.mainTexture = render_Tex;

        Shader.SetGlobalFloat(_magnitude_name, magnitude);
        RenderPipelineManager.endCameraRendering += EndCameraRendering;
    }

void EndCameraRendering(ScriptableRenderContext context, Camera camera)
    {
        if (camera == mainCamera)
        {
            Graphics.Blit(render_Tex, mainCamera.targetTexture, effectMaterial);
        }
    }

官方文件是建議掛在 void EndFrameRendering(ScriptableRenderContext context, Camera[] cameras)事件下,但這方法會把所有camera都覆蓋掉,所以我改在EndCameraRendering操作。

意思是把renderProviderCamera 的輸出目標設成render_Tex並down res做南部畫質特效,(位移符號可以看上篇)。最後用Blit,將render_Tex套用effectMaterial材質 給mainCamera輸出。


*補充,在update裡面Blit是無用的,必須等camera結束render再取texture才是有意義的。


影片中的shader
fixed4 frag (v2f i) : SV_Target
            {
                float2 dis=tex2D(_DisplaceTexture , i.uv + _Time.x ).xy;
                dis=((dis*2)-1  ) * _Magnitude;  //(*2-1) -> 把uv範圍[0,1] 改成 [-1,1]
                fixed4 col = tex2D(_MainTex, i.uv + dis );
                return col;
            }

備註: 影片不小心用到_SinTime,正確應該是_Time就好。 (shader time簡介)


雜談:
SRP出來後,現在unity渲染系統都在內鬥,原本的Stander Surface Shader到了urp直接下去再見掰掰(阿不就好險我還沒學),還有一堆方法例如GrabPass等等...
不禁感嘆自己身在亂世(?
送禮物贊助創作者 !
0
留言

創作回應

⊰⊱求出處學術用⊰⊱
我在做桌面寵物 剛好 看到 想優化 結果 限制禎數gpu 使用率下降比較多
2021-05-20 08:44:19
%%鼠 拒收病婿
用Unity做桌面寵物嗎? 有點好奇[e32] [e32] [e32]
2021-05-23 05:11:47
⊰⊱求出處學術用⊰⊱
https://truth.bahamut.com.tw/s01/202105/d2b2187d7655dbfed86a12af9f5457a3.JPG
目前這樣 放桌面上 定在那 還不能移動 縮小
2021-05-23 08:09:46
⊰⊱求出處學術用⊰⊱
https://imgur.com/XWZCW92.jpg 右邊是別人做的
2021-05-24 09:27:26
%%鼠 拒收病婿
哇!! Unity有辦法做到桌寵?! 請問是怎麼讓單就那個物件覆蓋在桌面上的?
2021-05-25 00:25:57
⊰⊱求出處學術用⊰⊱
要用windows api camera 把原本skybox選成黑色 它就會把背景剔除
2021-05-25 07:31:23
%%鼠 拒收病婿
這樣還能點到螢幕的東西嗎?
2021-05-25 12:02:11
⊰⊱求出處學術用⊰⊱
可以
2021-05-25 12:44:52
追蹤 創作集

作者相關創作

更多創作