后处理简介
感觉写得挺差的,还是建议直接看《Unity Shader入门精要》吧。
屏幕后处理,是指渲染出图像后,对整个图像进行二次处理得到更好的结果,场景的后处理如调节亮度、对比度、模糊、bloom等等。
我们也可以在渲染一部分后中止,进行后处理操作,再渲染剩下的部分。例如我们要做一个后处理描边效果,但不想对透明物体进行描边,就可以先渲染不透明物体,直接进行描边,再去渲染透明物体。
Unity提供了一个接口OnRenderImage(RenderTexture src,RenderTexture dest) 来方便我们制作各种效果。他的使用框架大概是这样的。
using UnityEngine;
using System.Collections;
//PostEffectsBase是我们自己写的一个基类,含有一些检测平台是否支持后处理的辅助函数
public class MyPostEffectsBase : PostEffectsBase {
public Shader shader;
private Material myMaterial;
public Material material {
get {
//如果material和shader对应则返回,否则创建一个新的
myMaterial = CheckShaderAndCreateMaterial(shader, myMaterial);
return myMaterial;
}
}
//一些参数
void OnRenderImage(RenderTexture src, RenderTexture dest) {
if (material != null) {
//....传参
//调用后处理的material
Graphics.Blit(src, dest, material);
} else {
Graphics.Blit(src, dest);
}
}
}
我们需要把这个脚本挂在摄像机上,这样就会自动调用我们的后处理shader了,可以看一个例子。
项目链接
在Scene0中我们实现了一个可调节亮度、饱和度、对比度的后处理效果,这个效果还算比较好理解的,实在不懂就看看Unity Shader入门精要吧。
边缘检测
卷积
先从卷积开始, 卷积操作就是用卷积核 kernel来对每个像素进行处理,一个常见的卷积核,均值卷积如下。通常是一个方形区域,每一个格子对应一个权值。以这个卷积核为例,计算时,我们要把像素放在中心,对周围其他像素与对应的卷积权值的乘积求和,得到的就是最终像素值。
均值模糊卷积核
例如我们用上面的均值卷积对下面例子中值为的0的像素进行运算。
结果为 5* 1 + 4* 1 + 3* 1 + 2* 1 + 0* 1 + 1* 1 + 5* 1 + 4* 1 + 3* 1 = 27
最后我们还要用27除以所有权值的和来做归一化,即27/ (1+1+1 +1+1+1 +1+1+1) = 3,至此我们运用均值卷积把0平均到了3,这就是均值模糊的思想。
理解了这个例子边缘检测就好理解多了,简单的算子如下。
我们对下面例子中间四个进行处理,结果如下。
运算后结果
可以看出,第二列的两个数因为处于色块中间,结果为0。而第三列的两个则变成了较大的数值,我们可以定义,经卷积处理后大于10的点为边缘,把他的颜色设立为_OutlineColor 黑色,小于10的则不做处理,这样我们就得到了黑色的描边,当然最好的还是用Lerp函数。
上面提到的只是简易的版本,实际上还要再进行横向算子运算。,得到两个方向的结果后进行以下操作,当然考虑到开根号的运算量过大,有时也会用这种方法来简化代替。
该部分实际案例见Scene1
高斯模糊
我们前面提到了均值模糊,高斯模糊是在这个的基础上进一步优化,做到越靠近中心点,影响越大,类似的例子如下。
我们这次将使用55的卷积核,如下。但我们对一个像素的周围进行这个卷积时,每个像素要进行55的采样,其中就有很多重复的运算,我们可以把这个55的卷积核拆分成一个15和51的卷积核,这样每个像素只用采样25次,得到了优化。(这部分的拆分我并没有查找到推导的资料,如果有找到的欢迎和我联系)。
使用上面这种拆分,我们要使用双pass,第一个pass先对原图像进行一个方向进行卷积得到buffer1,第二个pass再对buffer1进行另一个方向进行卷积得到buffer2,最后把buffer2映射到结果。
代码见Scene2,推荐阅读顺序,先看shader代码,再看cs代码。
Bloom效果
Bloom的原理很简单,规定一个阈值LuminanceThreshold,提取出大于这个阈值的额外存储再一个纹理上,用高斯模糊让这部分高亮更加均匀,再和原纹理叠加就可以了。
见Scene3