后处理SSAO
//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScreenSpaceAmbientAcclusion : PostProcessBase
{
private Camera mainCamera;
public Camera camera
{
get
{
if(mainCamera == null)
{
mainCamera= GetComponent<Camera>();
}
return mainCamera;
}
}
public Shader SSAOShader;
private Material ssaoMaterial;
public Material ssaoMat
{
get
{
ssaoMaterial = CheckShaderAndCreateMaterial(SSAOShader, ssaoMaterial);
return ssaoMaterial;
}
}
public Shader BlurShader;
private Material blurMaterial;
public Material blurMat
{
get
{
blurMaterial = CheckShaderAndCreateMaterial(BlurShader, blurMaterial);
return blurMaterial;
}
}
void OnEnable()
{
camera.depthTextureMode |= DepthTextureMode.DepthNormals;
}
[Range(1,256)]
public int SampleCount;
[Range(0.01f, 0.5f)]
public float SampleRadius; //SSAO 相机空间 随机半径最大值。
public Color AOColor = new Color(0.0f,0.0f,0.0f);
[Range(0.0f, 0.1f)]
public float UVOffset; //双边模糊采样UV偏移。
[Range(0.0f, 1.0f)]
public float BilaterFilterFactor; //法线比较的敏感度,值越大,法线差别对模糊的影响越小。
private void OnRenderImage(RenderTexture src, RenderTexture dest)
{
Matrix4x4 cameraProj = camera.projectionMatrix;
ssaoMat.SetMatrix("_Matrix_P",cameraProj);
ssaoMat.SetMatrix("_Matrix_IP", cameraProj.inverse); //传入投影矩阵逆矩阵
ssaoMat.SetInt("_SampleCount", SampleCount);
ssaoMat.SetFloat("_SampleRadius", SampleRadius);
ssaoMat.SetColor("_AOColor", AOColor);
RenderTexture buffer0 = RenderTexture.GetTemporary(src.width / 2, src.height / 2, 0); //downsample
RenderTexture buffer1 = RenderTexture.GetTemporary(src.width / 2, src.height / 2, 0);
Graphics.Blit(src, buffer0, ssaoMat, 0);
blurMat.SetFloat("_UVOffset",UVOffset); //模糊AO图
blurMat.SetFloat("_BilaterFilterFactor",BilaterFilterFactor);
Graphics.Blit(buffer0, buffer1, blurMat,0);
Graphics.Blit(buffer1, buffer0, blurMat, 1);
blurMat.SetTexture("_AoTex", buffer0); //与原图叠加
Graphics.Blit(src, dest, blurMat, 2);
Graphics.Blit(src, dest, blurMat, 2);
}
}
//SSAO shader
Shader "may/SSAO"
{
Properties
{
_MainTex("Source Tex", 2D) = "white"{}
}
SubShader
{
Cull Off ZWrite Off ZTest Always
pass
{
Blend Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _CameraDepthNormalsTexture; //深度法线图
float4x4 _Matrix_IP; //逆矩阵
float4x4 _Matrix_P;
int _SampleCount; //半球采样点数量
float _SampleRadius; //半球半径
fixed4 _AOColor; //ao的颜色,默认黑色
struct a2v
{
float4 vertex:POSITION;
float2 uv:TEXCOORD;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
float RandomFloat(float2 uv) //随机
{
return frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453);
}
float3 RandomFloat3(float2 uv) //随机向量 单位随机向量 * [-1,1]
{
float3 ranVector;
ranVector.x = RandomFloat(uv) * 2 - 1;
ranVector.y = RandomFloat(uv*uv) * 2 - 1;
ranVector.z = RandomFloat(uv*uv*uv) * 2 - 1;
return normalize(ranVector);
}
fixed4 frag(v2f i):SV_TARGET
{
//重建世界坐标
float depthTex = DecodeFloatRG(tex2D(_CameraDepthNormalsTexture, i.uv).zw);
float3 normalVS = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, i.uv));
float4 posNDC = float4(i.uv.x * 2 -1, i.uv.y * 2 -1, depthTex * 2 - 1, 1);
float4 posVS = mul(_Matrix_IP, posNDC);
posVS = posVS / posVS.w;
//在观察空间,定义一个切线空间
float3 tangentVS = RandomFloat3(i.uv);
float3 binormalVS = normalize(cross(tangentVS, normalVS));
tangentVS = cross(normalVS, binormalVS);
float3x3 ViewSpaceToTangentSpace = {tangentVS, binormalVS, normalVS};
float3x3 TangentSpaceToViewSpace = transpose(ViewSpaceToTangentSpace);
int count = 0; // 没被遮挡采样点数
for(int k = 0; k < _SampleCount; k++)
{
float3 randomVector = RandomFloat3(i.uv * (k+1) ); //偏移量,像素的切线空间 ,注意要保证每次循环产生的向量不同(所以乘k)
randomVector.z =abs( randomVector.z ) * 0.8 +0.2; //切线空间,偏移量,分量范围: [-1, 1], [-1, 1], [0, 1]
randomVector = mul(TangentSpaceToViewSpace, randomVector);
randomVector *= _SampleRadius;
float4 SamplerPointPosVS = posVS + float4(randomVector, 0); //采样点,相机空间
float4 SamplerPointPosCS = mul(_Matrix_P, SamplerPointPosVS);
float4 SamplerPointPosNDC = SamplerPointPosCS / SamplerPointPosCS.w;
float2 SamplerPointUV = (SamplerPointPosNDC.xy + 1) / 2;
float Depth = DecodeFloatRG(tex2D(_CameraDepthNormalsTexture, SamplerPointUV).zw);
float4 ndc = float4( SamplerPointUV * 2 -1, Depth * 2 - 1, 1);
float4 vs = mul(_Matrix_IP, ndc);
vs /= vs.w;
if( (-vs.z) - (-SamplerPointPosVS.z) > 0 || (-SamplerPointPosVS.z) - (-vs.z) > _SampleRadius ) // 场景深度图的深度 大于 采样点深度(未被遮挡) 或 采样点深度 大于 场景深度 很多(被遮挡,但是是错开的物体)
{
count++;
}
}
//float4 rowTex = tex2D(_MainTex, i.uv);
fixed ao= float(count)/_SampleCount;
return lerp( _AOColor, fixed4(1, 1, 1, 1), ao);// (1-ao)*_AOColor + ao * fixed4(1, 1, 1, 1); ao做出的遮罩 * ao颜色 + 非ao区域 * 白色
}
ENDCG
}
}
FallBack "Diffuse"
}
//BilateralBlur //模糊,但保持图像中的边缘信息
Shader "may/BilateralBlur"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader
{
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _AoTex;
sampler2D _CameraDepthNormalsTexture; //深度法线
float4 _AoTex_TexelSize;
float _UVOffset; //uv偏移量, 0 不偏移, 1 偏移量为窗口的宽/高 5x5采样
float _BilaterFilterFactor;
struct a2v
{
float4 vertex:POSITION;
float2 uv:TEXCOORD;
};
struct v2f_blur
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD;
half2 uvOffset:TEXCOORD1;
};
struct v2f_Add
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD;
};
v2f_blur vert_Horizontal(a2v v)
{
v2f_blur o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.uvOffset = half2(_UVOffset, 0);
return o;
}
v2f_blur vert_Vertical(a2v v)
{
v2f_blur o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.uvOffset = half2(0, _UVOffset);
return o;
}
float CompareNormal(float3 normal0, float3 normal1)
{
return smoothstep(_BilaterFilterFactor, 1.0, dot(normal0, normal1));
}
fixed4 frag_blur( v2f_blur i):SV_TARGET
{
half2 UVOffset = i.uvOffset;
half2 uv0 = i.uv - 3 * UVOffset;
half2 uv1 = i.uv - 2 * UVOffset;
half2 uv2 = i.uv - 1 * UVOffset;
half2 uv3 = i.uv;
half2 uv4 = i.uv + 1 * UVOffset;
half2 uv5 = i.uv + 2 * UVOffset;
half2 uv6 = i.uv + 3 * UVOffset;
fixed4 color0 = tex2D(_MainTex, uv0);
fixed4 color1 = tex2D(_MainTex, uv1);
fixed4 color2 = tex2D(_MainTex, uv2);
fixed4 color3 = tex2D(_MainTex, uv3);
fixed4 color4 = tex2D(_MainTex, uv4);
fixed4 color5 = tex2D(_MainTex, uv5);
fixed4 color6 = tex2D(_MainTex, uv6);
float3 normal0 = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, uv0));
float3 normal1 = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, uv1));
float3 normal2 = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, uv2));
float3 normal3 = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, uv3));
float3 normal4 = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, uv4));
float3 normal5 = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, uv5));
float3 normal6 = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, uv6));
fixed weight0 = CompareNormal(normal3, normal0) * 0.11453744493;
fixed weight1 = CompareNormal(normal3, normal1) * 0.19823788546;
fixed weight2 = CompareNormal(normal3, normal2) * 0.31718061674;
fixed weight3 = 0.37004405286;
fixed weight4 = CompareNormal(normal3, normal4) * 0.31718061674;
fixed weight5 = CompareNormal(normal3, normal5) * 0.19823788546;
fixed weight6 = CompareNormal(normal3, normal6) * 0.11453744493;
fixed weight = weight0 + weight1 + weight2 + weight3 + weight4 + weight5 + weight6;
fixed4 blurColor = fixed4(0,0,0,0);
blurColor += color0 * weight0;
blurColor += color1 * weight1;
blurColor += color2 * weight2;
blurColor += color3 * weight3;
blurColor += color4 * weight4;
blurColor += color5 * weight5;
blurColor += color6 * weight6;
//return color5;
return blurColor /weight;
}
v2f_Add vert_Add(a2v v)
{
v2f_Add o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag_Add( v2f_Add i):SV_TARGET
{
fixed4 src = tex2D(_MainTex, i.uv); //原图
fixed4 bluredAO = tex2D(_AoTex, i.uv); //模糊后的AO;
return src * bluredAO;
}
ENDCG
ZWrite Off ZTest Always Cull Off
pass
{
CGPROGRAM
#pragma vertex vert_Horizontal
#pragma fragment frag_blur
ENDCG
}
pass
{
CGPROGRAM
#pragma vertex vert_Vertical
#pragma fragment frag_blur
ENDCG
}
pass
{
CGPROGRAM
#pragma vertex vert_Add
#pragma fragment frag_Add
ENDCG
}
}
FallBack "Diffuse"
}
SSAO,HBAO,GTAO