后处理技术(上)

后处理技术(上)

二月 20, 2022

后处理(上)

启用后处理

在摄像头添加脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode()]//编辑模式就能看到效果
public class CameraPostPress : MonoBehaviour
{
public Material mat;
// Start is called before the first frame update
void Start()
{
if(mat==null||SystemInfo.supportsImageEffects==false||mat.shader==null||mat.shader.isSupported==false) {
enabled = false;
return;
}
}
private void OnRenderImage(RenderTexture source, RenderTexture destination) {
//当渲染图片启用 source是帧处理的图片 0是pass的顺序
Graphics.Blit(source,destination,mat, 0);
}
}

背景板

在这里插入图片描述

只要物体能拓展到屏幕上,就能让图片平铺到图片上,在片源部分做

1
2
half2 screen_uv = i.screen_pos.xy / (i.screen_pos.w + 0.000001);
screen_uv = (screen_uv + 1.0) * 0.5;

注意的是dx的y轴是反的

有三套解决方案

第一种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.screen_pos = o.vertex;
o.screen_pos.y = -o.screen_pos.y;
return o;
}

fixed4 frag(v2f i) : SV_Target
{
half2 screen_uv = i.screen_pos.xy / (i.screen_pos.w + 0.000001);
screen_uv = (screen_uv + 1.0) * 0.5;
// sample the texture
fixed4 col = tex2D(_MainTex, screen_uv);

return col;
}

第二种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.screen_pos = o.vertex;
o.screen_pos.y = o.screen_pos.y * _ProjectionParams.x;//改变
return o;
}

fixed4 frag(v2f i) : SV_Target
{
half2 screen_uv = i.screen_pos.xy / (i.screen_pos.w + 0.000001);
screen_uv = (screen_uv + 1.0) * 0.5;
// sample the texture
fixed4 col = tex2D(_MainTex, screen_uv);

return col;
}

第三种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.screen_pos=ComputeScreenPos(o.vertex);//改变
return o;
}c

fixed4 frag(v2f i) : SV_Target
{
half2 screen_uv = i.screen_pos.xy / (i.screen_pos.w + 0.000001);
//改变
// sample the texture
fixed4 col = tex2D(_MainTex, screen_uv);

return col;
}

背景板代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Shader "Unlit/Quad"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work


#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f
{
float2 uv : TEXCOORD0;
float4 screen_pos:TEXCOORD1;
float4 vertex : SV_POSITION;
};

sampler2D _MainTex;
float4 _MainTex_ST;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
//o.screen_pos = o.vertex;
//o.screen_pos.y = -o.screen_pos.y;
o.screen_pos=ComputeScreenPos(o.vertex);
return o;
}

fixed4 frag(v2f i) : SV_Target
{
half2 screen_uv = i.screen_pos.xy / (i.screen_pos.w + 0.000001);
screen_uv = (screen_uv + 1.0) * 0.5;
// sample the texture
fixed4 col = tex2D(_MainTex, screen_uv);

return col;
}
ENDCG
}
}
}

调色

在这里插入图片描述

ASE

在这里插入图片描述

内容

色调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
float3 HSVToRGB(float3 c) {
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
}
//RGB B*lerp(float3(1.0,1.0,1.0)) frac 取小数部分 色调(H),饱和度(S),明度(V)。
//H=B*lerp(1.0f,saturate(abs(frac(R + 1.0) * 6.0 - 3.0) - 1.0f),G)
//S=B*lerp(1.0f,saturate(abs(frac(R + 2.0 / 3.0) * 6.0 - 3.0) - 1.0f),G)
//V=B*lerp(1.0f,saturate(abs(frac(R + 1.0 / 3.0) * 6.0 - 3.0) - 1.0f),G)
float3 RGBToHSV(float3 c) {
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

亮度

简单粗暴直接乘

1
col.rgb=col.rgb*_Brightness;

饱和度

1
2
float lumin=dot(col.rgb,float3(0.22,0.707,0.071));
col.rgb=lerp(lumin,col.rgb,_Saturation);

对比度

float3(0.5,0.5,0.5)是灰色

1
col.rgb=lerp(float3(0.5,0.5,0.5),col.rgb,_Contrast);

暗角/晕影

1
2
3
4
float2 d=abs(i.uv-0.5)*_VignetteIntensity;
d=pow(saturate(d),_VignetteRoundness);
float dist=length(d);
col.rgb=pow(saturate(1.0-dist*dist),_VignetteSmoothness)*col.rgb;

调色代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Shader "Hidden/Color_Code"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Brightness("Brightness", Float) = 1
_Saturation("Saturation",Float) = 1
_Contrast("Contrast",Float) = 1
_VignetteIntensity("VignetteIntensity",Range(0.05,3.0)) = 1.5
_VignetteRoundness("VignetteRoundness",Range(1,6)) = 5
_VignetteSmoothness("VignetteSmoothness",Range(0.05,5)) = 5
_HueShift("HueShift",Range(0,1)) = 0

}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always

Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag

#include "UnityCG.cginc"
float3 HSVToRGB(float3 c) {
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
}
//RGB B*lerp(float3(1.0,1.0,1.0)) frac 取小数部分 色调(H),饱和度(S),明度(V)。
//H=B*lerp(1.0f,saturate(abs(frac(R + 1.0) * 6.0 - 3.0) - 1.0f),G)
//S=B*lerp(1.0f,saturate(abs(frac(R + 2.0 / 3.0) * 6.0 - 3.0) - 1.0f),G)
//V=B*lerp(1.0f,saturate(abs(frac(R + 1.0 / 3.0) * 6.0 - 3.0) - 1.0f),G)
float3 RGBToHSV(float3 c) {
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
sampler2D _MainTex;
float _Brightness;
float _Saturation;
float _Contrast;
float _VignetteIntensity;
float _VignetteRoundness;
float _VignetteSmoothness;
float _HueShift;

fixed4 frag (v2f_img i) : SV_Target
{

fixed4 sourse = tex2D(_MainTex, i.uv);
fixed4 col=sourse;
//色相
fixed3 hsv = RGBToHSV(sourse.rgb);
hsv.r= hsv.r +_HueShift;
col.rgb=HSVToRGB(hsv);
//亮度
col.rgb=col.rgb*_Brightness;
//饱和度
float lumin=dot(col.rgb,float3(0.22,0.707,0.071));
col.rgb=lerp(lumin,col.rgb,_Saturation);
//对比度
col.rgb=lerp(float3(0.5,0.5,0.5),col.rgb,_Contrast);
//暗角/晕影
float2 d=abs(i.uv-0.5)*_VignetteIntensity;

d=pow(saturate(d),_VignetteRoundness);
float dist=length(d);
col.rgb=pow(saturate(1.0-dist*dist),_VignetteSmoothness)*col.rgb;
return col;
}
ENDCG
}
}
}

破碎的玻璃

在这里插入图片描述

上玻璃

1
2
3
4
5
float aspect = _ScreenParams.x / _ScreenParams.y; // x = width y = height z = 1 + 1.0/width w = 1 + 1.0/height
float2 glass_uv = float2(i.uv.x * aspect, i.uv.y) * _GlassMask_ST.xy + _GlassMask_ST.zw;

half glass_opacity = tex2D(_GlassMask, glass_uv).r;
finalcolor = lerp(finalcolor, _GlassCrack.xxx, glass_opacity);

上法线

1
half3 glass_normal = UnpackNormal(tex2D(_GlassNormal, glass_uv));

解决边缘法线贴图重影

1
2
half2 d = 1.0 - smoothstep(0.95,1,abs(i.uv * 2.0 - 1.0));
half vfactor = d.x * d.y;

解决法线贴图毛玻璃的问题

1
2
3
4
float2 d_mask = step(0.005, abs(glass_normal.xy));
float mask = d_mask.x * d_mask.y;
half2 uv_distort = i.uv + glass_normal.xy * _Distort * vfactor * mask;
half4 col = tex2D(_MainTex, uv_distort);

总代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Shader "Hidden/BrokenGlass"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_GlassMask("GlassMask",2D) = "black"{}
_GlassCrack("GlassCrack",Float) = 1
_GlassNormal("GlassNormal",2D) = "bump"{}
_Distort("Distort",Float) = 1
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always

Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag

#include "UnityCG.cginc"

sampler2D _MainTex;
sampler2D _GlassMask;
float4 _GlassMask_ST;
float _GlassCrack;
sampler2D _GlassNormal;
float _Distort;

half4 frag (v2f_img i) : SV_Target
{
float aspect = _ScreenParams.x / _ScreenParams.y; // x = width y = height z = 1 + 1.0/width w = 1 + 1.0/height
float2 glass_uv = float2(i.uv.x * aspect, i.uv.y) * _GlassMask_ST.xy + _GlassMask_ST.zw;

half glass_opacity = tex2D(_GlassMask, glass_uv).r;
half3 glass_normal = UnpackNormal(tex2D(_GlassNormal, glass_uv));

half2 d = 1.0 - smoothstep(0.95,1,abs(i.uv * 2.0 - 1.0));
half vfactor = d.x * d.y;

float2 d_mask = step(0.005, abs(glass_normal.xy));
float mask = d_mask.x * d_mask.y;

half2 uv_distort = i.uv + glass_normal.xy * _Distort * vfactor * mask;
half4 col = tex2D(_MainTex, uv_distort);
half3 finalcolor = col.rgb;
finalcolor = lerp(finalcolor, _GlassCrack.xxx, glass_opacity);
return float4(finalcolor,col.a);
}
ENDCG
}
}
}