You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
8.6 KiB
357 lines
8.6 KiB
3 years ago
|
// SSAO Pro - Unity Asset
|
||
|
// Copyright (c) 2015 - Thomas Hourdel
|
||
|
// http://www.thomashourdel.com
|
||
|
|
||
|
#if (UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
|
||
|
#define UNITY_4_X
|
||
|
#else
|
||
|
#define UNITY_5_X
|
||
|
#endif
|
||
|
|
||
|
using UnityEngine;
|
||
|
using SSAOProUtils;
|
||
|
|
||
|
[HelpURL("http://www.thomashourdel.com/ssaopro/doc/")]
|
||
|
[ExecuteInEditMode, AddComponentMenu("Image Effects/SSAO Pro")]
|
||
|
[RequireComponent(typeof(Camera))]
|
||
|
public class SSAOPro : MonoBehaviour
|
||
|
{
|
||
|
public enum BlurMode
|
||
|
{
|
||
|
None,
|
||
|
Gaussian,
|
||
|
Bilateral,
|
||
|
HighQualityBilateral
|
||
|
}
|
||
|
|
||
|
public enum SampleCount
|
||
|
{
|
||
|
VeryLow,
|
||
|
Low,
|
||
|
Medium,
|
||
|
High,
|
||
|
Ultra
|
||
|
}
|
||
|
|
||
|
public Texture2D NoiseTexture;
|
||
|
|
||
|
public bool UseHighPrecisionDepthMap = false;
|
||
|
|
||
|
public SampleCount Samples = SampleCount.Medium;
|
||
|
|
||
|
[Range(1, 4)]
|
||
|
public int Downsampling = 1;
|
||
|
|
||
|
[Range(0.01f, 1.25f)]
|
||
|
public float Radius = 0.125f;
|
||
|
|
||
|
[Range(0f, 16f)]
|
||
|
public float Intensity = 2f;
|
||
|
|
||
|
[Range(0f, 10f)]
|
||
|
public float Distance = 1f;
|
||
|
|
||
|
[Range(0f, 1f)]
|
||
|
public float Bias = 0.1f;
|
||
|
|
||
|
[Range(0f, 1f)]
|
||
|
public float LumContribution = 0.5f;
|
||
|
|
||
|
[ColorUsage(false)]
|
||
|
public Color OcclusionColor = Color.black;
|
||
|
|
||
|
public float CutoffDistance = 150f;
|
||
|
public float CutoffFalloff = 50f;
|
||
|
|
||
|
public BlurMode Blur = BlurMode.None;
|
||
|
public bool BlurDownsampling = false;
|
||
|
|
||
|
[Range(1, 4)]
|
||
|
public int BlurPasses = 1;
|
||
|
|
||
|
[Range(0.05f, 1f)]
|
||
|
public float BlurBilateralThreshold = 0.1f;
|
||
|
|
||
|
public bool DebugAO = false;
|
||
|
|
||
|
protected Shader m_ShaderSSAO_v2;
|
||
|
protected Shader m_ShaderHighPrecisionDepth;
|
||
|
protected Material m_Material_v2;
|
||
|
protected Camera m_Camera;
|
||
|
protected Camera m_RWSCamera;
|
||
|
protected RenderTextureFormat m_RTFormat = RenderTextureFormat.RFloat;
|
||
|
|
||
|
public Material Material
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (m_Material_v2 == null)
|
||
|
{
|
||
|
m_Material_v2 = new Material(ShaderSSAO);
|
||
|
m_Material_v2.hideFlags = HideFlags.HideAndDontSave;
|
||
|
}
|
||
|
|
||
|
return m_Material_v2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Shader ShaderSSAO
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (m_ShaderSSAO_v2 == null)
|
||
|
m_ShaderSSAO_v2 = Shader.Find("Hidden/SSAO Pro V2");
|
||
|
|
||
|
return m_ShaderSSAO_v2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if UNITY_4_X
|
||
|
public Shader ShaderHighPrecisionDepth
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (m_ShaderHighPrecisionDepth == null)
|
||
|
m_ShaderHighPrecisionDepth = Shader.Find("Hidden/SSAO Pro - High Precision Depth Map");
|
||
|
|
||
|
return m_ShaderHighPrecisionDepth;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void Start()
|
||
|
{
|
||
|
// Disable if we don't support image effects
|
||
|
if (!SystemInfo.supportsImageEffects)
|
||
|
{
|
||
|
Debug.LogWarning("Image Effects are not supported on this platform.");
|
||
|
enabled = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Disable if we don't support render textures
|
||
|
if (SystemInfo.supportsRenderTextures)
|
||
|
{
|
||
|
#if UNITY_4_X
|
||
|
if (!SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RFloat))
|
||
|
{
|
||
|
if (!SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Depth))
|
||
|
{
|
||
|
Debug.LogWarning("RFloat && Depth RenderTextures are not supported on this platform.");
|
||
|
enabled = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m_RTFormat = RenderTextureFormat.Depth;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning("RenderTextures are not supported on this platform.");
|
||
|
enabled = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Disable the image effect if the shaders can't run on the users graphics card
|
||
|
if (ShaderSSAO != null && !ShaderSSAO.isSupported)
|
||
|
{
|
||
|
Debug.LogWarning("Unsupported shader (SSAO).");
|
||
|
enabled = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if UNITY_4_X
|
||
|
if (ShaderHighPrecisionDepth != null && !ShaderHighPrecisionDepth.isSupported)
|
||
|
{
|
||
|
Debug.LogWarning("Unsupported shader (High Precision Depth Map).");
|
||
|
enabled = false;
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void OnEnable()
|
||
|
{
|
||
|
m_Camera = GetComponent<Camera>();
|
||
|
}
|
||
|
|
||
|
void OnDestroy()
|
||
|
{
|
||
|
if (m_Material_v2 != null)
|
||
|
DestroyImmediate(m_Material_v2);
|
||
|
|
||
|
if (m_RWSCamera != null)
|
||
|
DestroyImmediate(m_RWSCamera.gameObject);
|
||
|
}
|
||
|
|
||
|
#if UNITY_4_X
|
||
|
void OnPreRender()
|
||
|
{
|
||
|
if (!UseHighPrecisionDepthMap)
|
||
|
return;
|
||
|
|
||
|
// Create the camera used to generate the alternate depth map
|
||
|
if (m_RWSCamera == null)
|
||
|
{
|
||
|
GameObject go = new GameObject("Depth Normal Camera", typeof(Camera));
|
||
|
go.hideFlags = HideFlags.HideAndDontSave;
|
||
|
m_RWSCamera = go.GetComponent<Camera>();
|
||
|
m_RWSCamera.CopyFrom(m_Camera);
|
||
|
m_RWSCamera.renderingPath = RenderingPath.Forward;
|
||
|
m_RWSCamera.clearFlags = CameraClearFlags.Color;
|
||
|
m_RWSCamera.backgroundColor = new Color(0f, 0f, 0f, 0f);
|
||
|
m_RWSCamera.enabled = false;
|
||
|
}
|
||
|
|
||
|
// Render depth & normals to a custom Float RenderTexture
|
||
|
m_RWSCamera.CopyFrom(m_Camera);
|
||
|
m_RWSCamera.rect = new Rect(0f, 0f, 1f, 1f);
|
||
|
m_RWSCamera.renderingPath = RenderingPath.Forward;
|
||
|
m_RWSCamera.clearFlags = CameraClearFlags.Color;
|
||
|
m_RWSCamera.backgroundColor = new Color(1f, 1f, 1f, 1f);
|
||
|
m_RWSCamera.farClipPlane = CutoffDistance;
|
||
|
|
||
|
RenderTexture rt = RenderTexture.GetTemporary((int)m_Camera.pixelWidth, (int)m_Camera.pixelHeight, 24, m_RTFormat);
|
||
|
rt.filterMode = FilterMode.Bilinear;
|
||
|
m_RWSCamera.targetTexture = rt;
|
||
|
m_RWSCamera.RenderWithShader(m_ShaderHighPrecisionDepth, "RenderType");
|
||
|
rt.SetGlobalShaderProperty("_DepthNormalMapF32");
|
||
|
m_RWSCamera.targetTexture = null;
|
||
|
RenderTexture.ReleaseTemporary(rt);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
[ImageEffectOpaque]
|
||
|
void OnRenderImage(RenderTexture source, RenderTexture destination)
|
||
|
{
|
||
|
// Fail checks
|
||
|
if (ShaderSSAO == null)
|
||
|
{
|
||
|
Graphics.Blit(source, destination);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if UNITY_4_X
|
||
|
if (ShaderHighPrecisionDepth == null && UseHighPrecisionDepthMap)
|
||
|
{
|
||
|
Graphics.Blit(source, destination);
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Shader keywords & pass ID
|
||
|
int ssaoPass = SetShaderStates();
|
||
|
|
||
|
// Uniforms
|
||
|
Material.SetMatrix("_InverseViewProject", (m_Camera.projectionMatrix * m_Camera.worldToCameraMatrix).inverse);
|
||
|
Material.SetMatrix("_CameraModelView", m_Camera.cameraToWorldMatrix);
|
||
|
Material.SetTexture("_NoiseTex", NoiseTexture);
|
||
|
Material.SetVector("_Params1", new Vector4(NoiseTexture == null ? 0f : NoiseTexture.width, Radius, Intensity, Distance));
|
||
|
Material.SetVector("_Params2", new Vector4(Bias, LumContribution, CutoffDistance, CutoffFalloff));
|
||
|
Material.SetColor("_OcclusionColor", OcclusionColor);
|
||
|
|
||
|
// Render !
|
||
|
if (Blur == BlurMode.None)
|
||
|
{
|
||
|
RenderTexture rt = RenderTexture.GetTemporary(source.width / Downsampling, source.height / Downsampling, 0, RenderTextureFormat.ARGB32);
|
||
|
Graphics.Blit(rt, rt, Material, 0); // Clear
|
||
|
|
||
|
if (DebugAO)
|
||
|
{
|
||
|
Graphics.Blit(source, rt, Material, ssaoPass);
|
||
|
Graphics.Blit(rt, destination);
|
||
|
RenderTexture.ReleaseTemporary(rt);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Graphics.Blit(source, rt, Material, ssaoPass);
|
||
|
Material.SetTexture("_SSAOTex", rt);
|
||
|
Graphics.Blit(source, destination, Material, 8);
|
||
|
RenderTexture.ReleaseTemporary(rt);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Pass ID
|
||
|
int blurPass = 5;
|
||
|
|
||
|
if (Blur == BlurMode.Bilateral)
|
||
|
blurPass = 6;
|
||
|
else if (Blur == BlurMode.HighQualityBilateral)
|
||
|
blurPass = 7;
|
||
|
|
||
|
// Prep work
|
||
|
int d = BlurDownsampling ? Downsampling : 1;
|
||
|
RenderTexture rt1 = RenderTexture.GetTemporary(source.width / d, source.height / d, 0, RenderTextureFormat.ARGB32);
|
||
|
RenderTexture rt2 = RenderTexture.GetTemporary(source.width / Downsampling, source.height / Downsampling, 0, RenderTextureFormat.ARGB32);
|
||
|
Graphics.Blit(rt1, rt1, Material, 0); // Clear
|
||
|
|
||
|
// SSAO
|
||
|
Graphics.Blit(source, rt1, Material, ssaoPass);
|
||
|
|
||
|
if (Blur == BlurMode.HighQualityBilateral)
|
||
|
Material.SetFloat("_BilateralThreshold", BlurBilateralThreshold / 10000);
|
||
|
|
||
|
for (int i = 0; i < BlurPasses; i++)
|
||
|
{
|
||
|
// Horizontal blur
|
||
|
Material.SetVector("_Direction", new Vector2(1f / source.width, 0f));
|
||
|
Graphics.Blit(rt1, rt2, Material, blurPass);
|
||
|
|
||
|
// Vertical blur
|
||
|
Material.SetVector("_Direction", new Vector2(0f, 1f / source.height));
|
||
|
Graphics.Blit(rt2, rt1, Material, blurPass);
|
||
|
}
|
||
|
|
||
|
if (!DebugAO)
|
||
|
{
|
||
|
Material.SetTexture("_SSAOTex", rt1);
|
||
|
Graphics.Blit(source, destination, Material, 8);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Graphics.Blit(rt1, destination);
|
||
|
}
|
||
|
|
||
|
RenderTexture.ReleaseTemporary(rt1);
|
||
|
RenderTexture.ReleaseTemporary(rt2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// State switching
|
||
|
private string[] keywords = new string[2];
|
||
|
|
||
|
int SetShaderStates()
|
||
|
{
|
||
|
// Depth & normal maps
|
||
|
m_Camera.depthTextureMode |= DepthTextureMode.Depth;
|
||
|
m_Camera.depthTextureMode |= DepthTextureMode.DepthNormals;
|
||
|
|
||
|
// Shader keywords
|
||
|
keywords[0] = (Samples == SampleCount.Low) ? "SAMPLES_LOW"
|
||
|
: (Samples == SampleCount.Medium) ? "SAMPLES_MEDIUM"
|
||
|
: (Samples == SampleCount.High) ? "SAMPLES_HIGH"
|
||
|
: (Samples == SampleCount.Ultra) ? "SAMPLES_ULTRA"
|
||
|
: "SAMPLES_VERY_LOW";
|
||
|
|
||
|
#if UNITY_4_X
|
||
|
keywords[1] = (UseHighPrecisionDepthMap) ? "HIGH_PRECISION_DEPTHMAP_ON" : "HIGH_PRECISION_DEPTHMAP_OFF";
|
||
|
#else
|
||
|
keywords[1] = "HIGH_PRECISION_DEPTHMAP_OFF";
|
||
|
#endif
|
||
|
|
||
|
Material.shaderKeywords = keywords;
|
||
|
|
||
|
// SSAO pass ID
|
||
|
int pass = 0;
|
||
|
|
||
|
if (NoiseTexture != null)
|
||
|
pass = 1;
|
||
|
|
||
|
if (LumContribution >= 0.001f)
|
||
|
pass += 2;
|
||
|
|
||
|
return 1 + pass;
|
||
|
}
|
||
|
}
|