Shader從入門到跑路:螢幕後處理效果
我們在第二篇文章用網格的uv座標來設定四邊形的顏色,那麼螢幕的uv座標是什麼呢?
正文
你可以將螢幕看成一個大的正方形,別噓我,底層的圖形API也是這麼看待螢幕的。
在第一章中我們提到了shader的計算流程,並且介紹到fragment shader會將計算好的顏色傳給顏色緩衝,並結束工作,因為之後的內容就是交由底層圖形API來將顏色緩衝內的資料內容以法向量的形式渲染到螢幕上,而這個過程將根據執行平臺的不同而選擇不同的圖形API,所以我沒有詳細說,想了解只要隨便找個圖形API比如openGL什麼的學一下就好了。
謝謝這位臨時演員幫助了我們理解螢幕渲染效果是怎麼一回事。圖形渲染的底層實現是由unity來決定的,當unity指定了執行平臺後,圖形API就可以開始噴射影像了,儲存在水槍裡面的都是以法向量存在的渲染資料,包含顏色、深度資訊等,只要影像API做一些中間處理,就可以將其射到螢幕上。
但是,在顏色緩衝區的內容真正被噴到螢幕上之前,我們仍然有機會更改其中的內容。而unity也為我們考慮到了這一點,因此它提供了一個叫OnRenderImage的函式,這是個monobehaviour事件。關於這個函式可移步Unity Doc:
https://docs.unity3d.com/Manual/ExecutionOrder.htmldocs.unity3d.com
Post-processing overviewdocs.unity3d.com1
這個函式有一個source渲染紋理作為輸入,這個輸入包含了顏色緩衝裡面所有的資料資訊,包括顏色、深度資訊等等。以及一個destination作為輸出,在這我們通常認為就是相機螢幕了。
場景準備(隨便搭一搭就好了):
為了展示接下來的效果,我先隨便建立了一個遊戲介面
接下來寫一個簡單的C#程式來了解它的用法:
- using UnityEngine;
- [ExecuteInEditMode]
- public class PostEffects : MonoBehaviour
- {
- public Material material;
- private void OnRenderImage(RenderTexture source, RenderTexture destination)
- {
- Graphics.Blit(source, destination, material);
- }
- }
首先,ExecuteInEditMode表示我們可以在Edit mode中觀察程式的執行。然後定義了一個材質,用來渲染螢幕,然後呼叫OnRenderImage這個函式,而重點則在於Graphics.Blit這個方法,它的意思大概是用這個material把這個source渲染到那個destination。
然後我會用第二節講到的shader:
- Shader "Custom/ShaderLearning"
- {
- SubShader
- {
- Tags
- {
- "Queue" = "Transparent"
- }
- Pass
- {
- Blend SrcAlpha OneMinusSrcAlpha
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- #include "UnityCG.cginc"
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv: TEXCOORD0;
- };
- struct v2f
- {
- float4 vertex : SV_POSITION;
- float2 uv: TEXCOORD1;
- };
- v2f vert(appdata v)
- {
- v2f o;
- o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
- o.uv = v.uv;
- return o;
- }
- float4 frag(v2f i) : SV_Target
- {
- float4 color = float4(i.uv.r,i.uv.g, 0, 1);
- return color;
- }
- ENDCG
- }
- }
- }
接下來把PostEffects拖給場景內的相機。並新建一個新的material,將上面的shader賦給新材質後,將材質賦值給PostEffects的材質引數
最終的效果如上圖所示。我們把整個螢幕的uv座標作為顏色引數輸出了,但這確實不是什麼好玩的東西,我們可以在shader中新建一個主紋理來接收在顏色緩衝中儲存的紋理(這裡就是螢幕),並將其輸出到螢幕上吧。
值得注意的是,Graphics.Blit方法會把source傳入的紋理賦值給mateiral中的主紋理。必須將shader中的主紋理命名為_MainTex才行,不然會報錯。
加入一個Properties區域,並且宣告一個_MainTex的二維屬性,以白色為預設顏色:
- Properties{
- _MainTex("Main Texture", 2D) = "white" {}
- }
在CGPROGRAM內加入宣告:
sampler2D _MainTex;
修改fragment shader,這次我們不僅輸出紋理本身,而且還要將它乘上uv座標:
- float4 frag(v2f i) : SV_Target
- {
- float4 color = tex2D(_MainTex, i.uv);
- color *= float4(i.uv.r, i.uv.g, 0, 1);
- return color;
- }
以顏色緩衝內的渲染紋理與uv座標想乘的渲染結果
那麼總算是做出一些比較有趣的渲染效果了,當然這可能也就是在你做些什麼嚇唬人的遊戲時才有些用處了。
自問自答
當我把紋理作為輸入傳給OnRenderImage時,我其實不過是在將整個要渲染到整個螢幕上的東西拿出來做處理而已,這些"要渲染的東西"就是顏色咯,我可不可以把紋理看作存有很多個顏色值的資料表呢?
為了更深刻地展示這個問題,我把我老婆的照片畫素化了
“一張紋理就是儲存了一個陣列,而裡面的資料就是顏色”這樣的想法是不完全對的。我們可以把任何資料內容儲存進紋理中,有些紋理在我們眼中是不符合現實的
一張看起來很奇怪的紋理
但對於我們的shader來說,他有可能是一張查詢表,有可能是一張高度圖,或者就是一些偽隨機的噪音引數,但無論它是什麼,對於shader都是有用的內容。
一張位移圖
舉個例子,看到這張圖你能想到什麼?要說“啊,是Minecraft裡面的磚塊材質!”的同學清先坐下。我想說的是,紅色的顏色代表的是在uv的x值上的位移,而綠色則是在uv的y值上的位移。最終的螢幕後處理效果能呈現一種空間被扭曲的感覺,我們下章來做它的實現。
相關閱讀:
Shader從入門到跑路:樸實無華的圖形學基礎
Shader從入門到跑路:自定義紋理輸入
作者:俊銘
專欄地址:https://zhuanlan.zhihu.com/p/85958322
相關文章
- Shader從入門到跑路:實作螢幕扭曲效果
- Shader從入門到跑路:自定義紋理輸入
- Shader從入門到跑路:顏色自定義輸出、紋理取樣
- babel從入門到跑路Babel
- Shader從入門到跑路:樸實無華的圖形學基礎
- Kotlin從入門到跑路(一)Kotlin
- Docker實戰-從入門到跑路Docker
- 直播app開發,螢幕效果與圖片的處理APP
- Vue入門到跑路---VuexVue
- 《Golang 從入門到跑路》之開發環境搭建Golang開發環境
- Linux Shell 從入門到刪除根目錄跑路指南Linux
- Java 異常處理專題,從入門到精通Java
- Spring Boot從入門到實戰(十):非同步處理Spring Boot非同步
- Flask框架從入門到精通之異常處理(十)Flask框架
- Unity Shader-後處理:Bloom全屏泛光UnityOOM
- Linux 從入門到跑路第二十一講 -- 字串擷取Linux字串
- MyBatis從入門到精通(十四):在MyBatis中使用型別處理器MyBatis型別
- Spring Boot2從入門到實戰:統一異常處理Spring Boot
- makefile從入門到入門
- scala 從入門到入門+
- LVGL庫入門教程01-移植到STM32(觸控式螢幕)
- 資料庫運維初入門-SQL Server入門到跑路002-初使用資料庫運維SQLServer
- kafka從入門到關門Kafka
- web3從入門到實戰-理論篇Web
- 從DDPM到DDIM(四) 預測噪聲與後處理
- PostgreSQL處理JSON入門SQLJSON
- 一個安卓螢幕錄製轉 GIF 的批處理安卓
- 2023nlp影片教程大全 NLP自然語言處理教程 自然語言處理NLP從入門到專案實戰自然語言處理
- MyBatis從入門到精通(一):MyBatis入門MyBatis
- SA:從入門到入土
- Python從入門到精通Python
- vim從入門到精通
- Jdbc從入門到入土JDBC
- Thymeleaf從入門到精通
- Eclipse從入門到精通Eclipse
- Shell從入門到精通
- Promise從入門到精通Promise
- LESS從入門到精通