這次的參考影片是這個:
如果是用SRP (scriptable render pipeline),還沒打到5行程式碼就會卡住,原因是SRP 不支援
OnRenderImage這方法。
SRP又分成URP和HDRP, URP比較輕量,HDRP效果好但吃效能。
如影片內容,在原本的渲染系統上,只需簡單幾行就能做到:
void OnRenderImage(RenderTexture src, RenderTexture dst)
{
Graphics.Blit(src, dst, effectMaterial);
}
在camera結束render後,傳入畫面結果(src),進行操作後將結果傳給dst輸出。
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要除。
- OnRenderImage
- OnPostRender
- OnPreRender
- OnPreCull
而類似的作法是將方法註冊在RenderPipeline.beginCameraRendering 或 RenderPipeline.beginFrameRendering 事件上。 其中RenderPipeline已經是舊的語法,現在改為RenderPipelineManager。
《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;
}
雜談:SRP出來後,現在unity渲染系統都在內鬥,原本的Stander Surface Shader到了urp直接下去再見掰掰(阿不就好險我還沒學),還有一堆方法例如GrabPass等等...
不禁感嘆自己身在亂世
(?