using System; using UnityEngine; namespace UnityStandardAssets.ImageEffects { [ExecuteInEditMode] [RequireComponent(typeof(Camera))] [AddComponentMenu("Image Effects/Rendering/Screen Space Ambient Occlusion")] public class ScreenSpaceAmbientOcclusion : MonoBehaviour { public enum SSAOSamples { Low = 0, Medium = 1, High = 2 } public float m_Radius = 0.4f; public SSAOSamples m_SampleCount = SSAOSamples.Medium; public float m_OcclusionIntensity = 1.5f; public int m_Blur = 2; public int m_Downsampling = 2; public float m_OcclusionAttenuation = 1f; public float m_MinZ = 0.01f; public Shader m_SSAOShader; private Material m_SSAOMaterial; public Texture2D m_RandomTexture; private bool m_Supported; private static Material CreateMaterial(Shader shader) { if (!shader) { return null; } return new Material(shader) { hideFlags = HideFlags.HideAndDontSave }; } private static void DestroyMaterial(Material mat) { if ((bool)mat) { UnityEngine.Object.DestroyImmediate(mat); mat = null; } } private void OnDisable() { DestroyMaterial(m_SSAOMaterial); } private void Start() { if (!SystemInfo.supportsImageEffects || !SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Depth)) { m_Supported = false; base.enabled = false; return; } CreateMaterials(); if (!m_SSAOMaterial || m_SSAOMaterial.passCount != 5) { m_Supported = false; base.enabled = false; } else { m_Supported = true; } } private void OnEnable() { GetComponent().depthTextureMode |= DepthTextureMode.DepthNormals; } private void CreateMaterials() { if (!m_SSAOMaterial && m_SSAOShader.isSupported) { m_SSAOMaterial = CreateMaterial(m_SSAOShader); m_SSAOMaterial.SetTexture("_RandomTexture", m_RandomTexture); } } [ImageEffectOpaque] private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (!m_Supported || !m_SSAOShader.isSupported) { base.enabled = false; return; } CreateMaterials(); m_Downsampling = Mathf.Clamp(m_Downsampling, 1, 6); m_Radius = Mathf.Clamp(m_Radius, 0.05f, 1f); m_MinZ = Mathf.Clamp(m_MinZ, 1E-05f, 0.5f); m_OcclusionIntensity = Mathf.Clamp(m_OcclusionIntensity, 0.5f, 4f); m_OcclusionAttenuation = Mathf.Clamp(m_OcclusionAttenuation, 0.2f, 2f); m_Blur = Mathf.Clamp(m_Blur, 0, 4); RenderTexture renderTexture = RenderTexture.GetTemporary(source.width / m_Downsampling, source.height / m_Downsampling, 0); float fieldOfView = GetComponent().fieldOfView; float farClipPlane = GetComponent().farClipPlane; float num = Mathf.Tan(fieldOfView * (MathF.PI / 180f) * 0.5f) * farClipPlane; float x = num * GetComponent().aspect; m_SSAOMaterial.SetVector("_FarCorner", new Vector3(x, num, farClipPlane)); int num2; int num3; if ((bool)m_RandomTexture) { num2 = m_RandomTexture.width; num3 = m_RandomTexture.height; } else { num2 = 1; num3 = 1; } m_SSAOMaterial.SetVector("_NoiseScale", new Vector3((float)renderTexture.width / (float)num2, (float)renderTexture.height / (float)num3, 0f)); m_SSAOMaterial.SetVector("_Params", new Vector4(m_Radius, m_MinZ, 1f / m_OcclusionAttenuation, m_OcclusionIntensity)); bool num4 = m_Blur > 0; Graphics.Blit(num4 ? null : source, renderTexture, m_SSAOMaterial, (int)m_SampleCount); if (num4) { RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0); m_SSAOMaterial.SetVector("_TexelOffsetScale", new Vector4((float)m_Blur / (float)source.width, 0f, 0f, 0f)); m_SSAOMaterial.SetTexture("_SSAO", renderTexture); Graphics.Blit(null, temporary, m_SSAOMaterial, 3); RenderTexture.ReleaseTemporary(renderTexture); RenderTexture temporary2 = RenderTexture.GetTemporary(source.width, source.height, 0); m_SSAOMaterial.SetVector("_TexelOffsetScale", new Vector4(0f, (float)m_Blur / (float)source.height, 0f, 0f)); m_SSAOMaterial.SetTexture("_SSAO", temporary); Graphics.Blit(source, temporary2, m_SSAOMaterial, 3); RenderTexture.ReleaseTemporary(temporary); renderTexture = temporary2; } m_SSAOMaterial.SetTexture("_SSAO", renderTexture); Graphics.Blit(source, destination, m_SSAOMaterial, 4); RenderTexture.ReleaseTemporary(renderTexture); } } }