主要思路:1.随机采样像素法线半球周围的像素,平均对比与该像素深度是否处在暗处。2.双边滤波去噪点。3.后期AO图与原图混合。
原文链接:https://blog.csdn.net/puppet_master/article/details/82929708
c#部分:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSAO : MonoBehaviour {
public Material SSAOMaterial;
private List<Vector4> sampleKernelList = new List<Vector4>();
[Range(0f, 0.002f)]
public float depthBiasValue = 0f;
[Range(0.01f, 1f)]
public float sampleKernelRadius = 1.0f;
[Range(4,32)]
public int sampleKernelCount = 16;
[Range(0.0f, 5.0f)]
public float AOStrength = 1.0f;
[Range(0, 2)]
public int downSample = 0;
[Range(1, 4)]
public int blurRadius = 1;
[Range(0f, 0.2f)]
public float bilateralFilterStrength = 0.2f;
public bool onlyShowAO = false;
public enum SSAOPassName
{
GenerateAO=0,
BilateralFilter=1,
Composite=2
}
private Camera currentCamera;
void Start () {
currentCamera = Camera.main;
currentCamera.depthTextureMode = DepthTextureMode.DepthNormals;
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
//采样点生成
GenerateAOSampleKernel();
RenderTexture aoRT = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0);
SSAOMaterial.SetMatrix("_InverseProjectionMatrix", currentCamera.projectionMatrix.inverse);
SSAOMaterial.SetFloat("_DepthBiasValue", depthBiasValue);
SSAOMaterial.SetVectorArray("_SampleKernelArray", sampleKernelList.ToArray());
SSAOMaterial.SetFloat("_SampleKernelCount", sampleKernelList.Count);
SSAOMaterial.SetFloat("_AOStrength", AOStrength);
SSAOMaterial.SetFloat("_SampleKernelRadius", sampleKernelRadius);
Graphics.Blit(source, aoRT, SSAOMaterial, (int)SSAOPassName.GenerateAO);
RenderTexture blurRT = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0);
SSAOMaterial.SetFloat("_BilaterFilterFactor", 1.0f - bilateralFilterStrength);
SSAOMaterial.SetVector("_BlurRadius", new Vector4(blurRadius, 0, 0, 0));
Graphics.Blit(aoRT, blurRT, SSAOMaterial, (int)SSAOPassName.BilateralFilter);
SSAOMaterial.SetVector("_BlurRadius", new Vector4(0, blurRadius, 0, 0));
if (onlyShowAO)
{
Graphics.Blit(blurRT, destination, SSAOMaterial, (int)SSAOPassName.BilateralFilter);
}
else
{
Graphics.Blit(blurRT, aoRT, SSAOMaterial, (int)SSAOPassName.BilateralFilter);
SSAOMaterial.SetTexture("_AOTex", aoRT);
Graphics.Blit(source, destination, SSAOMaterial, (int)SSAOPassName.Composite);
}
RenderTexture.ReleaseTemporary(aoRT);
RenderTexture.ReleaseTemporary(blurRT);
}
private void GenerateAOSampleKernel()
{
if (sampleKernelCount==sampleKernelList.Count)
{
return;
}
sampleKernelList.Clear();
for (int i = 0; i < sampleKernelCount; i++)
{
Vector4 vec = new Vector4(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f), 1f);
vec.Normalize();
float scale = ((float)i) / sampleKernelCount;
//调整分布的曲线
scale = Mathf.Lerp(0.01f, 1.0f, scale * scale);
vec *= scale;
sampleKernelList.Add(vec);
}
}
}
shader部分:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSAO : MonoBehaviour {
public Material SSAOMaterial;
private List<Vector4> sampleKernelList = new List<Vector4>();
[Range(0f, 0.002f)]
public float depthBiasValue = 0f;
[Range(0.01f, 1f)]
public float sampleKernelRadius = 1.0f;
[Range(4,32)]
public int sampleKernelCount = 16;
[Range(0.0f, 5.0f)]
public float AOStrength = 1.0f;
[Range(0, 2)]
public int downSample = 0;
[Range(1, 4)]
public int blurRadius = 1;
[Range(0f, 0.2f)]
public float bilateralFilterStrength = 0.2f;
public bool onlyShowAO = false;
public enum SSAOPassName
{
GenerateAO=0,
BilateralFilter=1,
Composite=2
}
private Camera currentCamera;
void Start () {
currentCamera = Camera.main;
currentCamera.depthTextureMode = DepthTextureMode.DepthNormals;
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
//采样点生成
GenerateAOSampleKernel();
RenderTexture aoRT = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0);
SSAOMaterial.SetMatrix("_InverseProjectionMatrix", currentCamera.projectionMatrix.inverse);
SSAOMaterial.SetFloat("_DepthBiasValue", depthBiasValue);
SSAOMaterial.SetVectorArray("_SampleKernelArray", sampleKernelList.ToArray());
SSAOMaterial.SetFloat("_SampleKernelCount", sampleKernelList.Count);
SSAOMaterial.SetFloat("_AOStrength", AOStrength);
SSAOMaterial.SetFloat("_SampleKernelRadius", sampleKernelRadius);
Graphics.Blit(source, aoRT, SSAOMaterial, (int)SSAOPassName.GenerateAO);
RenderTexture blurRT = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0);
SSAOMaterial.SetFloat("_BilaterFilterFactor", 1.0f - bilateralFilterStrength);
SSAOMaterial.SetVector("_BlurRadius", new Vector4(blurRadius, 0, 0, 0));
Graphics.Blit(aoRT, blurRT, SSAOMaterial, (int)SSAOPassName.BilateralFilter);
SSAOMaterial.SetVector("_BlurRadius", new Vector4(0, blurRadius, 0, 0));
if (onlyShowAO)
{
Graphics.Blit(blurRT, destination, SSAOMaterial, (int)SSAOPassName.BilateralFilter);
}
else
{
Graphics.Blit(blurRT, aoRT, SSAOMaterial, (int)SSAOPassName.BilateralFilter);
SSAOMaterial.SetTexture("_AOTex", aoRT);
Graphics.Blit(source, destination, SSAOMaterial, (int)SSAOPassName.Composite);
}
RenderTexture.ReleaseTemporary(aoRT);
RenderTexture.ReleaseTemporary(blurRT);
}
private void GenerateAOSampleKernel()
{
if (sampleKernelCount==sampleKernelList.Count)
{
return;
}
sampleKernelList.Clear();
for (int i = 0; i < sampleKernelCount; i++)
{
Vector4 vec = new Vector4(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f), 1f);
vec.Normalize();
float scale = ((float)i) / sampleKernelCount;
//调整分布的曲线
scale = Mathf.Lerp(0.01f, 1.0f, scale * scale);
vec *= scale;
sampleKernelList.Add(vec);
}
}
}