您好,欢迎来到外链网!
当前位置:外链网 » 站长资讯 » 专业问答 » 文章详细 订阅RssFeed

Unity Shader学习SSAA超采样抗锯齿,unity渲染采样锯齿

来源:互联网 浏览:112次 时间:2023-04-08
Unity Shader学习:SSAA超采样抗锯齿

抗锯齿Shader网上看了下没看到比较好的直接能用的,只能自己搜搜随便撸了一个,实现不一定特别好,有需要的话可以用用看。

SSAA超采样抗锯齿主要思路:利用Sobel算子做卷积算出哪些像素处在颜色变化的边缘,再使用周边采样算法进行插值模糊。

C#部分:

//屏幕后处理基类using UnityEngine;using System.Collections;//非运行时也触发效果[ExecuteInEditMode]//屏幕后处理特效一般都需要绑定在摄像机上[RequireComponent(typeof(Camera))]//提供一个后处理的基类,主要功能在于直接通过Inspector面板拖入shader,生成shader对应的材质public class PostEffectBase : MonoBehaviour{ //Inspector面板上直接拖入 public Shader shader = null; private Material _material = null; public Material _Material { get { if (_material == null) _material = GenerateMaterial(shader); return _material; } } //根据shader创建用于屏幕特效的材质 protected Material GenerateMaterial(Shader shader) { if (shader == null) return null; //需要判断shader是否支持 if (shader.isSupported == false) return null; Material material = new Material(shader); material.hideFlags = HideFlags.DontSave; if (material) return material; return null; }} //SSAA抗锯齿后处理using System.Collections;using System.Collections.Generic;using UnityEngine;[ExecuteInEditMode]public class SSAAPostEffect : PostEffectBase { /// <summary> /// 像素点采样的范围 /// </summary> [Range(0.1f, 1.0f)] public float size=0.5f; /// <summary> /// 索贝尔算子采样范围 /// </summary> [Range(0.1f, 1.0f)] public float sobelSize=0.5f; private void OnRenderImage(RenderTexture source, RenderTexture destination) { _Material.SetFloat("_Size", size); _Material.SetFloat("_SobelSize", sobelSize); Graphics.Blit(source, destination, _Material); }}

shader部分:

//SSAA抗锯齿shaderShader "Custom/SSAA" {Properties {_MainTex("Base(RGB)",2D)="white"{}_Size("Size",Range(0.1,2.0))=1.0_SobelSize("SobelSize",Range(0.1,1.0))=1.0}SubShader {Pass{ CGPROGRAM#include "UnityCG.cginc"sampler2D _MainTex;float4 _MainTex_TexelSize;float _Size;float _SobelSize;#pragma vertex vert#pragma fragment fragstruct v2f{float4 pos:SV_POSITION;float2 uv[9]:TEXCOORD0;};//取灰度的方法,返回一个颜色的灰度值float luminance(float4 color){return 0.2125* color.r+0.7154*color.g+0.0721*color.b;}//索贝尔算子求得当前像素点是否是边缘float Sobel(v2f i){const float Gx[9]={-1,-2,-1, 0, 0, 0, 1, 2, 1};const float Gy[9]={-1, 0, 1, -2, 0, 2, -1, 0, 1};float texColor;float edgeX=0;float edgeY=0;for(int it=0;it<9;it++){ //取灰度texColor=luminance(tex2D(_MainTex,i.uv[it]));edgeX+=texColor*Gx[it];edgeY+=texColor*Gy[it];}float edge=1-abs(edgeX)-abs(edgeY);//值越小证明在边缘(和周边像素颜色差距大)return edge;}v2f vert(appdata_img v){v2f o;o.pos=UnityObjectToClipPos(v.vertex);float2 uv=v.texcoord;//像素周围八个点和自身o.uv[0]=uv+_MainTex_TexelSize.xy*float2(-1,-1)*_SobelSize;o.uv[1]=uv+_MainTex_TexelSize.xy*float2(0,-1)*_SobelSize;o.uv[2]=uv+_MainTex_TexelSize.xy*float2(1,-1)*_SobelSize;o.uv[3]=uv+_MainTex_TexelSize.xy*float2(-1,0)*_SobelSize;o.uv[4]=uv+_MainTex_TexelSize.xy*float2(0,0)*_SobelSize;o.uv[5]=uv+_MainTex_TexelSize.xy*float2(1,0)*_SobelSize;o.uv[6]=uv+_MainTex_TexelSize.xy*float2(-1,1)*_SobelSize;o.uv[7]=uv+_MainTex_TexelSize.xy*float2(0,1)*_SobelSize;o.uv[8]=uv+_MainTex_TexelSize.xy*float2(1,1)*_SobelSize;return o;}float4 frag(v2f i):SV_Target{float edge=Sobel(i);//采用了旋转网格采样,最佳的旋转角度是arctan (1/2) (大约 26.6°)//也可以采取别的采样方法,网上有很多算法float4 c0 = tex2D(_MainTex, i.uv[4] + float2(0.2 / 2, 0.8)*_Size*_MainTex_TexelSize);float4 c1 = tex2D(_MainTex, i.uv[4] + float2(0.8 / 2, -0.2)*_Size*_MainTex_TexelSize);float4 c2 = tex2D(_MainTex, i.uv[4] + float2(-0.2 / 2, -0.8)*_Size*_MainTex_TexelSize);float4 c3 = tex2D(_MainTex, i.uv[4] + float2(-0.8 / 2, 0.2)*_Size*_MainTex_TexelSize);float4 mainColor = tex2D(_MainTex, i.uv[4]);float4 color = (c0 + c1 + c2 + c3)*0.25;//按边缘比重插值采样平均色和原颜色return lerp(color,mainColor,edge);}ENDCG}}}