11. Post Processing
52. Preparing for post processing
什么是后处理技术?如果你熟知PS,那么你应该知道什么是滤镜,后处理技术就像滤镜一样。
打开69scene,想想为什么这里会黑屏呢?因为_MainTex没有设置到rendered image上,也就是说纹理在摄像机中渲染了,但是没用到屏幕上。怎么办呢?注意Scene 69 Render Image脚本,这里有一个Cur Shader(Cursor shader),我们将原图传到这个shader里处理,然后渲染到屏幕上。
方便的是,在unity中我们就有这样一个函数OnRenderImage来做这件事。
52.1 Unity 中的OnRenderImage 函数
- 如果我们不将sourceTexture拷贝到destTexture那么我们就会得到黑色。
- 默认的destTesture就是黑色
- 如果摄像机下的脚本中没有这个函数,那么就会正常渲染,但是如果有OnRenderImage这个函数,那么我们必须传入sourceTexture 到 destTexture。
void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
{
}
52.1.1 Graphics.Blit函数
拷贝功能,将第一个参数拷贝到第二个参数.
Graphics.Blit(sourceTexture,destTexture);
这里图像就会显示了。
但是我们现在的需求是将source传递到shader。
这里我们首先在脚本中动态创建了一个应用curShader的材质:
Material ScreenMat
{
get
{
if (screenMat == null)
{
screenMat = new Material(curShader);
screenMat.hideFlags = HideFlags.HideAndDontSave;
}
return screenMat;
}
}
然后修改OnRenderImage,如果有处理shader就进入处理shader,没有就直接输出。
void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
{
if (curShader != null)//如果curShader不为空,就用这个shader去处理源图
{
ScreenMat.SetColor("_TintColor",tintColor);
Graphics.Blit(sourceTexture,destTexture,ScreenMat);//这里第三个参数是材质
}
else
{
Graphics.Blit(sourceTexture,destTexture);
}
}
当然在脚本开始还要看这个处理shader是否被支持。
void Start()
{
if (!curShader && !curShader.isSupported)
{
enabled = false;
}
}
52.2 简单的后处理Shader
Shader "NiksShaders/Shader69Unlit"
{
Properties
{
_MainTex("Base (RGB)", 2D) = "white" {}
_TintColor("Tint Color", Color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _TintColor;
fixed4 frag (v2f_img i) : SV_Target
{
fixed3 renderTex = tex2D(_MainTex, i.uv).rgb;
fixed3 grayScale = (renderTex.r + renderTex.g + renderTex.b)/3;//取RGB的平均值可以让最后显示的颜色偏向某一个(这个和显示的颜色一致)
fixed3 curCol = grayScale * _TintColor;
return fixed4(curCol, 1);
}
ENDCG
}
}
FallBack off
}
52.3 Summary
- When using post processing the developer needs to copy the rendered image to a sampler2D.
- One way is to use the OnRenderlmage method.
- Use the Graphics.Blit method
- When passed a material as the 3rd parameter it will copy destTexture as the sampler2D MainTex
53. Night goggles effect
护目镜效果,基本上和上一节同理。
Shader "NiksShaders/Shader70aUnlit"
{
Properties
{
_MainTex("Base (RGB)", 2D) = "white" {}
_Tint("Tint", Range(0, 1)) = 1.0
_ScanLines("Scanlines", Range(50, 150)) = 100
_ScanlineColor("Scanline Color", Color) = (0,0,0,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed _Tint;
float _Scanlines;
fixed4 _ScanlineColor;
fixed4 frag (v2f_img i) : SV_Target
{
fixed3 renderTex = tex2D(_MainTex, i.uv).rgb;//取样
fixed3 tintColor = fixed3( 0.6, 1, 0.6 );
fixed3 grayScale = (renderTex.r + renderTex.g + renderTex.b) / 3;
fixed3 tinted = grayScale * tintColor;//上滤镜
fixed3 finalColor = lerp(renderTex, tinted, _Tint);//选择滤镜还是主纹理
float scanline = smoothstep(0.2, 0.4, frac(i.uv.y * _Scanlines));//将uv.y翻倍成_Scanlines取小数,以小于0.2是0是黑色,大于0.4是1,中间是过渡
finalColor = lerp(_ScanlineColor.rgb, finalColor, scanline);//0的部分返回线的颜色,1的部分返回纹理颜色
return fixed4(finalColor, 1);
}
ENDCG
}
}
FallBack off
}