- 后处理原理及过程
- 边缘检测(描边)
- 高斯模糊和 Bloom 效果
- 运动模糊
- 脚本
后处理是在渲染完后对图像进行处理,unity使用的是 C# 脚本
就是渲染完后不显示,多走一步,经由脚本处理后再显示到屏幕上,以实现诸如各种模糊效果、Bloom、描边等等
后处理一般过程
获取当前屏幕图像,利用C#脚本调用shader对图像进行处理,在将处理后的图像显示到屏幕上
原理
创建了一个同屏幕宽高完全一样的面,将之前的渲染结果作为渲染纹理传入脚本,调用shader对纹理采样渲染回面片
所以在后处理时需要关闭深度写入等,防止渲染纹理覆盖了特殊情况下最后渲染的半透明物体
Unity提供了OnRenderImage()函数获取屏幕图像
MonoBehaviour.OnRenderImage (RenderTexture src, RenderTexture dest)
public static void Blit(Texture src, Texture dest); public static void Blit(Texture src, Texture dest, Material mat, int pass = -1); public static void Blit(Texture src, Material mat, int pass = -1);
Blit函数获取屏幕图像后调用shader,将源图像src作为一张渲染纹理赋值给shader中_MainTex
边缘检测(描边)
梯度的本意是一个向量(矢量),表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)
二维空间下的偏微分方程
∂
f
(
x
,
y
)
∂
x
=
lim
ϵ
−
>
0
f
(
x
+
ϵ
,
y
)
−
f
(
x
,
y
)
ϵ
frac{∂f(x,y)}{∂x}=lim_{epsilon->0}frac{f(x+epsilon,y)-f(x,y)}{epsilon}
∂x∂f(x,y)=ϵ−>0limϵf(x+ϵ,y)−f(x,y)
∂ f ( x , y ) ∂ y = lim ϵ − > 0 f ( x , y + ϵ ) − f ( x , y ) ϵ frac{∂f(x,y)}{∂y}=lim_{epsilon->0}frac{f(x,y+epsilon)-f(x,y)}{epsilon} ∂y∂f(x,y)=ϵ−>0limϵf(x,y+ϵ)−f(x,y)
由于像素不是连续的,只要计算当前像素沿偏微分方向的差值,ε=1,所以只需进行简单的加减运算
在xy得到的值经过勾股定理后就得到,二维空间下灰度的变化率
边缘检测算子
注意:图中后两个算子是错的,xy方向反了!!!
一般不采用 Roberts 这样偶数的算子,因为结果对原像素存在偏移
Prewitt: G x = f ( x + 1 ) + 0 ∗ f ( x ) − f ( x − 1 ) Gx = f(x+1) + 0 * f(x)-f(x-1) Gx=f(x+1)+0∗f(x)−f(x−1),提取系数就是[-1, 0, 1]
所以该算子Gx就是: 同理Gy: [-1, 0, 1] [-1, -1, -1] [-1, 0, 1] [ 0, 0, 0] [-1, 0, 1] [ 1, 1, 1]
Sobel就是prewitt的基础上,加强了对直线上像素的检测
高斯模糊和 Bloom 效果
均值模糊
卷积核的各元素值相同,n*n的核每个的值就是1/n^2
高斯模糊
高斯模糊的卷积核又叫高斯核
高斯模糊的名字来源于高斯分布(正态分布),其概率密度函数所表示的就是均值与样本值之间的关系,所以高斯模糊就是一种权值按距离减少的方法
G
(
x
,
y
)
=
1
2
π
σ
2
e
−
x
2
+
y
2
2
σ
2
G(x,y)=frac{1}{2pisigma^2}e^{-frac{x^2+y^2}{2sigma^2}}
G(x,y)=2πσ21e−2σ2x2+y2
μ
mu
μ就是0,因为当前像素的原点距离为0,方差
σ
sigma
σ取标准方差1
n*n 的高斯核可以使用两个一维的高斯核替换
而且由于概率密度函数是对称的,所以存储上可以优化
_MainTex获取屏幕图像
_MainTex_TexelSize获取纹素尺寸
half2 uv[5] : TEXCOORDS0
//Vertical
uv[0]=uv;
uv[1]=uv + float2(0.0, _MainTex_TexelSize * 1.0);//上方一格的坐标
uv[2]=uv - float2(0.0, _MainTex_TexelSize * 1.0);//下方一格的坐标
uv[3]=uv + float2(0.0, _MainTex_TexelSize * 2.0);//上方两格的坐标
uv[4]=uv - float2(0.0, _MainTex_TexelSize * 2.0);//下方两格的坐标
//horizontal同理
Bloom效果
步骤:提取图像中的亮部(像素的亮度可由rgb通过一定比例的计算获得),对提取的亮部进行高斯模糊,混合原图和Bloom
luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b,可以看出绿色对亮度的贡献最大,红色次之,蓝色最小
运动模糊
方法:累计缓存(混合多张图像),速度缓存(按照像素的运动速度来模糊处理)
脚本
using UnityEngine;
using System.Collections;
public class MyScript : MonoBehaviour {
public Shader MyScriptShader;
private Material MyScriptMaterial = null;
public Material material {
get {
MyScriptMaterial = function(MyScriptShader, MyScriptMaterial);
return MyScriptMaterial;
}
}
//暴露的属性
[Range(0, 4)]
public int temp = 3;
...
//调用shader
void OnRangeImage(RenderTexture src, RenderTexture dest) {
if(material != null) {
material.setFloat("_temp", temp);
//后处理
Graphics.Blit(src, dest, material);
}
else {
//直接返回
Graphics.Blit(src, dest);
}
}
}



