Antialiasing 抗锯齿效果(render to texture锯齿问题处理)
很多时候需要把相机得texture渲染到texture上。但是效果往往不理想。
如图对比:
没有处理过得效果 处理过得效果
还是比较明显得变化得。
那么如何处理呢?下面介绍四种方式
方式一
具体原理不多啰嗦,直接讲步骤。
首先创建一个脚本Antialiasing.cs
using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; 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 RawImage StoreRenderTexture; 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; // Shader a= 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; StoreRenderTexture.texture = Antialiasing.RenderTexture; } 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(); } }
然后,将脚本挂载到相机上。
将你要展示得RawImage拽到脚本中得RawImage处。
大功告成!
方式二
当然你想要获得更好得效果还可以这样做。
1、打开菜单栏Edit中Project Settings中的Quality选项
2、在QualitySettings中可以找到Shadows设置
3、开始各种调整,直到自己满意
4、Shadow Distance值如果很大就会边缘锯齿,Resolution也有影响
方式三
也可以这样做,通过官方得抗锯齿滤镜插件。
这里推荐Beautify,可以加很多得相机效果,同时在锯齿处理也是相当完美。官网35刀。不过CSDN或者随便哪个论坛都可以下载。这个钱能省则省,实在需要联系我,哈哈哈请问吃顿饭就好。开玩笑拉自己去下载
方式四
当然这里也有通过Super Sampling Anti-Aliasing来进行抗锯齿处理,跟前面得也是差不多。这里贴出Shader代码
Shader "Custom/SSAA1" { Properties{ _MainTex("MainTex", 2D) = "white" {} _Size("Size", range(1, 2048)) = 512 } SubShader{ pass{ Tags{ "LightMode" = "ForwardBase" } Cull off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" float _Size; sampler2D _MainTex; float4 _MainTex_ST; struct v2f { float4 pos : SV_POSITION; float2 uv_MainTex : TEXCOORD0; }; v2f vert(appdata_full v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv_MainTex = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } float4 frag(v2f i) :COLOR { /* *this part is about edge detection algorithms used Sobel operator */ float3 lum = float3(0.2125, 0.7154, 0.0721); float mc00 = dot(tex2D(_MainTex, i.uv_MainTex - fixed2(1, 1) / _Size).rgb, lum); float mc10 = dot(tex2D(_MainTex, i.uv_MainTex - fixed2(0, 1) / _Size).rgb, lum); float mc20 = dot(tex2D(_MainTex, i.uv_MainTex - fixed2(-1, 1) / _Size).rgb, lum); float mc01 = dot(tex2D(_MainTex, i.uv_MainTex - fixed2(1, 0) / _Size).rgb, lum); float mc11mc = dot(tex2D(_MainTex, i.uv_MainTex).rgb, lum); float mc21 = dot(tex2D(_MainTex, i.uv_MainTex - fixed2(-1, 0) / _Size).rgb, lum); float mc02 = dot(tex2D(_MainTex, i.uv_MainTex - fixed2(1, -1) / _Size).rgb, lum); float mc12 = dot(tex2D(_MainTex, i.uv_MainTex - fixed2(0, -1) / _Size).rgb, lum); float mc22 = dot(tex2D(_MainTex, i.uv_MainTex - fixed2(-1, -1) / _Size).rgb, lum); float GX = -1 * mc00 + mc20 + -2 * mc01 + 2 * mc21 - mc02 + mc22; float GY = mc00 + 2 * mc10 + mc20 - mc02 - 2 * mc12 - mc22; float G = abs(GX) + abs(GY); float4 c = 0; c = length(float2(GX, GY)); /* *this part is about blur edge */ float4 cc = tex2D(_MainTex, i.uv_MainTex); if (c.x < 0.2) { return cc; } else { float2 n = float2(GX, GY); n *= 1 / _Size / c.x; //roated float4 c0 = tex2D(_MainTex, i.uv_MainTex + fixed2(0.2 / 2, 0.8) / _Size); float4 c1 = tex2D(_MainTex, i.uv_MainTex + fixed2(0.8 / 2, -0.2) / _Size); float4 c2 = tex2D(_MainTex, i.uv_MainTex + fixed2(-0.2 / 2, -0.8) / _Size); float4 c3 = tex2D(_MainTex, i.uv_MainTex + fixed2(-0.8 / 2, 0.2) / _Size); //random float2 randUV = 0; randUV = rand(float2(n.x, n.y)); float4 c0 = tex2D(_MainTex, i.uv_MainTex + float2(randUV.x / 2, randUV.y) / _Size); randUV = rand(float2(-n.x, n.y)); float4 c1 = tex2D(_MainTex, i.uv_MainTex + float2(randUV.x / 2, randUV.y) / _Size); randUV = rand(float2(n.x, -n.y)); float4 c2 = tex2D(_MainTex, i.uv_MainTex + float2(randUV.x / 2, randUV.y) / _Size); randUV = rand(float2(-n.x, -n.y)); float4 c3 = tex2D(_MainTex, i.uv_MainTex + float2(randUV.x / 2, randUV.y) / _Size); //Gird float4 c0 = tex2D(_MainTex, i.uv_MainTex + fixed2(0.5, 1) / _Size); float4 c1 = tex2D(_MainTex, i.uv_MainTex + fixed2(-0.5, 1) / _Size); float4 c2 = tex2D(_MainTex, i.uv_MainTex + fixed2(0.5, -1) / _Size); float4 c3 = tex2D(_MainTex, i.uv_MainTex + fixed2(-0.5, -1) / _Size); cc = (cc + c0 + c1 + c2 + c3) *0.2; return cc; } } ENDCG } } }
关于SSAA得抗锯齿处理原理比较简单就是;查找边缘然会进行模糊化处理。这样锯齿就能减弱,几乎没有啥感觉!
推荐博文:https://blog.csdn.net/wolf96/article/details/45438653
NVIDIA资料(自行翻译了解):https://docs.nvidia.com/gameworks/index.html#gameworkslibrary/graphicssamples/d3d_samples/antialiaseddeferredrendering.htm