US3S10L3——屏幕后处理基本实现原理
US3S10L3——屏幕后处理基本实现原理
Unity中屏幕后期处理效果的基本实现原理
从上文可以知道,想要完成屏幕后期处理效果,最关键的问题在于:
- 如何获取游戏画面渲染完毕后的画面信息
- 如何为获取到的画面信息添加自定义效果
只要搞清楚这两点,自然就明白了基本实现原理:
-
如何获取游戏画面渲染完毕后的画面信息
之前在学习 渲染目标纹理 时学习过,在 Unity 中获取渲染纹理的常用方法有三种:
RenderTexture(渲染纹理)、GrabPass(Shader 内使用)、OnRenderImage
我们在处理屏幕后期处理效果时会使用OnRenderImage
函数来获取 游戏画面渲染完毕后的画面信息 -
如何为获取到的画面信息添加自定义效果
主要思路是将获取到的游戏画面作为 自定义Shader 的主纹理
通过 自定义Shader 利用捕获的画面来实现自定义效果
捕获画面的关键 —— OnRenderImage函数
OnRenderImage()
是在继承了 MonoBehaviour 的脚本中能够被自动调用的函数(类似生命周期函数)
它会在图像的渲染操作完成后调用,它的固定写法是:
1 | void OnRenderImage(RenderTexture source, RenderTexture destination) { } |
- 第一个参数
source
:源渲染纹理,当前渲染得到的屏幕图像存储在该参数当中 - 第二个参数
destination
:目标渲染纹理,将经过处理后的图像写入到目标纹理中用于最终的显示
通过该函数我们便可以得到当前渲染的游戏画面,并在该函数中对画面对应的渲染纹理进行处理后用于最终显示
一般来说,实现屏幕后处理的脚本都是挂载在摄像机上的
注意!
该函数得到的源纹理默认是在所有的不透明和透明的
Pass
执行完毕后调用的,
基于该源纹理进行修改会对游戏场景中所有游戏对象产生影响,如果你想要在不透明的
Pass
执行完毕后就调用该函数,只需要在该函数前加上特性[ImageEffectOpaque]
,这样就不会对透明物体产生影响
1
2 [ ]
private void OnRenderImage(RenderTexture source, RenderTexture destination) { }
实现效果的关键 —— Graphics.Blit函数
Graphics.Blit()
用于将一个图像从一个纹理复制到另一个纹理,同时可以在这个过程中用着色器对图像进行处理
它有很多重载,我们主要讲解几个常用的:
-
将源纹理直接复制到目标纹理
1
Graphics.Blit(Texture source, RenderTexture dest)
使用示例:
1
2
3
4private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(source, destination); // 将原纹理直接赋值到目标纹理
} -
将源纹理复制到目标纹理并应用一个材质
1
Graphics.Blit(Texture source, RenderTexture dest, Material mat, int pass = -1);
-
source
源纹理参数会被传递给mat
材质中Shader
中名为_MainTex
的纹理属性用于进行处理 -
pass
参数默认值为-1
,表示会依次调用 Shader 内的所有Pass
进行处理,否则,只会调用给定索引的Pass
source
源纹理在经过mat
材质中Shader
处理后,最终会将 Shader 输出的颜色渲染到dest
上,改变屏幕显示内容使用示例:
1
2
3
4
5
6
7
8
9
10
11using UnityEngine;
public class Lesson100 : MonoBehaviour
{
public Material material;
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(source, destination, material);
}
}将此脚本挂载到主摄像机上,然后使用之前实现的棋盘格程序纹理 Shader 的材质,这个材质会直接渲染棋盘格颜色
Shader 代码详见:US3S8L11——Shader代码动态生成程序纹理
显示效果:
可见,虽然这个材质内没有使用
source
屏幕内容纹理,
但是因为材质会直接输出棋盘格颜色,并渲染到 destination
目标纹理内了,因此整个屏幕都变成了棋盘格样式的也就是说,如果能够合理的在 Shader 内传入的
source
屏幕内容纹理,就可以对屏幕显示内容作出修改 -