什么是 SSAA

超级采样抗锯齿(Super-Sampling Anti-aliasing,简称SSAA)此是早期抗锯齿方法,比较消耗资源,但简单直接,先把图像映射到缓存并把它放大,再用超级采样把放大后的图像像素进行采样,一般选取2个或4个邻近像素,把这些采样混合起来后,生成的最终像素,令每个像素拥有邻近像素的特征,像素与像素之间的过渡色彩,就变得近似,令图形的边缘色彩过渡趋于平滑。再把最终像素还原回原来大小的图像,并保存到帧缓存也就是显存中,替代原图像存储起来,最后输出到显示器,显示出一帧画面。

C# 实现

将下面的脚本绑定到需要进行 SSAA 的摄像机上即可

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
using System;
using System.Collections.Generic;
using UnityEngine;

public class Antialiasing : MonoBehaviour
{
private static GameObject renderTargetCam;
private static TextureRenderer textureRenderer;
private static RenderTexture renderTexture;
public static float scale = 2;
private Camera mainCam;
private int screenX;
private int screenY;
private int targetX = 100;
private int targetY = 100;
private int hideFlagDontShowSave = 61;
public bool restart;
private bool rendering;
public static RenderTextureFormat Format = RenderTextureFormat.ARGB32;
public static GameObject RenderTargetCamera
{
get
{
return Antialiasing.renderTargetCam;
}
}
public static RenderTexture RenderTexture
{
get
{
return Antialiasing.renderTexture;
}
}
public Camera RenderingCamera
{
get
{
return this.mainCam;
}
}
private void OnEnable()
{
this.mainCam = base.GetComponent<Camera>();
if (this.mainCam == null)
{
Debug.LogError("Missing Camera on GameObject!");
base.enabled = false;
return;
}
this.hideFlagDontShowSave = 13;
this.targetX = Screen.width;
this.targetY = Screen.height;
//new Shader();
if (Application.isEditor)
{
this.restart = true;
return;
}
this.StartAntialiasing();
}
private void OnDisable()
{
this.StopAntialiasing();
}
private void Update()
{
if (this.screenX != Screen.width || this.screenY != Screen.height)
{
this.restart = true;
}
if (this.restart)
{
this.Restart();
}
}
private void Restart()
{
this.StopAntialiasing();
this.StartAntialiasing();
this.restart = false;
}
private void OnPreCull()
{
if (this.rendering && (this.screenX != Screen.width || this.screenY != Screen.height))
{
this.targetX = Screen.width;
this.targetY = Screen.height;
this.restart = true;
}
if (this.rendering)
{
this.mainCam.targetTexture = Antialiasing.renderTexture;
}
}
private void FinishedRendering()
{
if (this.rendering)
{
this.mainCam.targetTexture = null;
}
}
public void StartAntialiasing()
{
if (this.mainCam == null)
{
Debug.LogError("Missing Camera on Object!");
return;
}
this.screenX = Screen.width;
this.screenY = Screen.height;
int num = (int)((float)Screen.width * Antialiasing.scale);
int num2 = (int)((float)Screen.height * Antialiasing.scale);
if (num <= 0)
{
num = 100;
}
if (num2 <= 0)
{
num2 = 100;
}
if (Antialiasing.renderTexture == null || Antialiasing.renderTexture.width != num || Antialiasing.renderTexture.height != num2)
{
if (Antialiasing.renderTexture != null)
{
Antialiasing.renderTexture.Release();
}
Antialiasing.renderTexture = new RenderTexture(num, num2, 2, Antialiasing.Format);
Antialiasing.renderTexture.name = "SSAARenderTarget";
Antialiasing.renderTexture.hideFlags = (HideFlags)this.hideFlagDontShowSave;
}
if (Antialiasing.renderTargetCam == null)
{
Antialiasing.renderTargetCam = new GameObject("SSAARenderTargetCamera");
Antialiasing.renderTargetCam.hideFlags = (HideFlags)this.hideFlagDontShowSave;

Camera c = Antialiasing.renderTargetCam.AddComponent<Camera>();

c.CopyFrom(this.mainCam);
c.cullingMask = 0;
c.targetTexture = null;
c.depth = this.mainCam.depth + 0.5f;
Antialiasing.textureRenderer = Antialiasing.renderTargetCam.AddComponent<TextureRenderer>();
Antialiasing.textureRenderer.hideFlags = (HideFlags)this.hideFlagDontShowSave;
}
this.rendering = true;
}
public void StopAntialiasing()
{
if (this.mainCam != null && this.mainCam.targetTexture != null)
{
this.mainCam.targetTexture = null;
}
if (renderTargetCam != null)
{
GameObject.Destroy(renderTargetCam);
}
this.rendering = false;
}
}
public class TextureRenderer : MonoBehaviour
{
private Camera c;
public bool stereoFirstPass = true;
private void Awake()
{
this.c = gameObject.GetComponent<Camera>();
if (this.c == null)
{
Debug.LogError("TextureRenderer init fail! (no Camera)");
base.enabled = false;
}
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(Antialiasing.RenderTexture, destination);
Antialiasing.RenderTexture.DiscardContents();
}
}