ScreenSpaceAmbientOcclusion.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. using System;
  2. using UnityEngine;
  3. namespace UnityStandardAssets.ImageEffects
  4. {
  5. [ExecuteInEditMode]
  6. [RequireComponent (typeof(Camera))]
  7. [AddComponentMenu("Image Effects/Rendering/Screen Space Ambient Occlusion")]
  8. public class ScreenSpaceAmbientOcclusion : MonoBehaviour
  9. {
  10. public enum SSAOSamples
  11. {
  12. Low = 0,
  13. Medium = 1,
  14. High = 2,
  15. }
  16. [Range(0.05f, 1.0f)]
  17. public float m_Radius = 0.4f;
  18. public SSAOSamples m_SampleCount = SSAOSamples.Medium;
  19. [Range(0.5f, 4.0f)]
  20. public float m_OcclusionIntensity = 1.5f;
  21. [Range(0, 4)]
  22. public int m_Blur = 2;
  23. [Range(1,6)]
  24. public int m_Downsampling = 2;
  25. [Range(0.2f, 2.0f)]
  26. public float m_OcclusionAttenuation = 1.0f;
  27. [Range(0.00001f, 0.5f)]
  28. public float m_MinZ = 0.01f;
  29. public Shader m_SSAOShader;
  30. private Material m_SSAOMaterial;
  31. public Texture2D m_RandomTexture;
  32. private bool m_Supported;
  33. private static Material CreateMaterial (Shader shader)
  34. {
  35. if (!shader)
  36. return null;
  37. Material m = new Material (shader);
  38. m.hideFlags = HideFlags.HideAndDontSave;
  39. return m;
  40. }
  41. private static void DestroyMaterial (Material mat)
  42. {
  43. if (mat)
  44. {
  45. DestroyImmediate (mat);
  46. mat = null;
  47. }
  48. }
  49. void OnDisable()
  50. {
  51. DestroyMaterial (m_SSAOMaterial);
  52. }
  53. void Start()
  54. {
  55. if (!SystemInfo.SupportsRenderTextureFormat (RenderTextureFormat.Depth))
  56. {
  57. m_Supported = false;
  58. enabled = false;
  59. return;
  60. }
  61. CreateMaterials ();
  62. if (!m_SSAOMaterial || m_SSAOMaterial.passCount != 5)
  63. {
  64. m_Supported = false;
  65. enabled = false;
  66. return;
  67. }
  68. //CreateRandomTable (26, 0.2f);
  69. m_Supported = true;
  70. }
  71. void OnEnable () {
  72. GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;
  73. }
  74. private void CreateMaterials ()
  75. {
  76. if (!m_SSAOMaterial && m_SSAOShader.isSupported)
  77. {
  78. m_SSAOMaterial = CreateMaterial (m_SSAOShader);
  79. m_SSAOMaterial.SetTexture ("_RandomTexture", m_RandomTexture);
  80. }
  81. }
  82. [ImageEffectOpaque]
  83. void OnRenderImage (RenderTexture source, RenderTexture destination)
  84. {
  85. if (!m_Supported || !m_SSAOShader.isSupported) {
  86. enabled = false;
  87. return;
  88. }
  89. CreateMaterials ();
  90. m_Downsampling = Mathf.Clamp (m_Downsampling, 1, 6);
  91. m_Radius = Mathf.Clamp (m_Radius, 0.05f, 1.0f);
  92. m_MinZ = Mathf.Clamp (m_MinZ, 0.00001f, 0.5f);
  93. m_OcclusionIntensity = Mathf.Clamp (m_OcclusionIntensity, 0.5f, 4.0f);
  94. m_OcclusionAttenuation = Mathf.Clamp (m_OcclusionAttenuation, 0.2f, 2.0f);
  95. m_Blur = Mathf.Clamp (m_Blur, 0, 4);
  96. // Render SSAO term into a smaller texture
  97. RenderTexture rtAO = RenderTexture.GetTemporary (source.width / m_Downsampling, source.height / m_Downsampling, 0);
  98. float fovY = GetComponent<Camera>().fieldOfView;
  99. float far = GetComponent<Camera>().farClipPlane;
  100. float y = Mathf.Tan (fovY * Mathf.Deg2Rad * 0.5f) * far;
  101. float x = y * GetComponent<Camera>().aspect;
  102. m_SSAOMaterial.SetVector ("_FarCorner", new Vector3(x,y,far));
  103. int noiseWidth, noiseHeight;
  104. if (m_RandomTexture) {
  105. noiseWidth = m_RandomTexture.width;
  106. noiseHeight = m_RandomTexture.height;
  107. } else {
  108. noiseWidth = 1; noiseHeight = 1;
  109. }
  110. m_SSAOMaterial.SetVector ("_NoiseScale", new Vector3 ((float)rtAO.width / noiseWidth, (float)rtAO.height / noiseHeight, 0.0f));
  111. m_SSAOMaterial.SetVector ("_Params", new Vector4(
  112. m_Radius,
  113. m_MinZ,
  114. 1.0f / m_OcclusionAttenuation,
  115. m_OcclusionIntensity));
  116. bool doBlur = m_Blur > 0;
  117. Graphics.Blit (doBlur ? null : source, rtAO, m_SSAOMaterial, (int)m_SampleCount);
  118. if (doBlur)
  119. {
  120. // Blur SSAO horizontally
  121. RenderTexture rtBlurX = RenderTexture.GetTemporary (source.width, source.height, 0);
  122. m_SSAOMaterial.SetVector ("_TexelOffsetScale",
  123. new Vector4 ((float)m_Blur / source.width, 0,0,0));
  124. m_SSAOMaterial.SetTexture ("_SSAO", rtAO);
  125. Graphics.Blit (null, rtBlurX, m_SSAOMaterial, 3);
  126. RenderTexture.ReleaseTemporary (rtAO); // original rtAO not needed anymore
  127. // Blur SSAO vertically
  128. RenderTexture rtBlurY = RenderTexture.GetTemporary (source.width, source.height, 0);
  129. m_SSAOMaterial.SetVector ("_TexelOffsetScale",
  130. new Vector4 (0, (float)m_Blur/source.height, 0,0));
  131. m_SSAOMaterial.SetTexture ("_SSAO", rtBlurX);
  132. Graphics.Blit (source, rtBlurY, m_SSAOMaterial, 3);
  133. RenderTexture.ReleaseTemporary (rtBlurX); // blurX RT not needed anymore
  134. rtAO = rtBlurY; // AO is the blurred one now
  135. }
  136. // Modulate scene rendering with SSAO
  137. m_SSAOMaterial.SetTexture ("_SSAO", rtAO);
  138. Graphics.Blit (source, destination, m_SSAOMaterial, 4);
  139. RenderTexture.ReleaseTemporary (rtAO);
  140. }
  141. /*
  142. private void CreateRandomTable (int count, float minLength)
  143. {
  144. Random.seed = 1337;
  145. Vector3[] samples = new Vector3[count];
  146. // initial samples
  147. for (int i = 0; i < count; ++i)
  148. samples[i] = Random.onUnitSphere;
  149. // energy minimization: push samples away from others
  150. int iterations = 100;
  151. while (iterations-- > 0) {
  152. for (int i = 0; i < count; ++i) {
  153. Vector3 vec = samples[i];
  154. Vector3 res = Vector3.zero;
  155. // minimize with other samples
  156. for (int j = 0; j < count; ++j) {
  157. Vector3 force = vec - samples[j];
  158. float fac = Vector3.Dot (force, force);
  159. if (fac > 0.00001f)
  160. res += force * (1.0f / fac);
  161. }
  162. samples[i] = (samples[i] + res * 0.5f).normalized;
  163. }
  164. }
  165. // now scale samples between minLength and 1.0
  166. for (int i = 0; i < count; ++i) {
  167. samples[i] = samples[i] * Random.Range (minLength, 1.0f);
  168. }
  169. string table = string.Format ("#define SAMPLE_COUNT {0}\n", count);
  170. table += "const float3 RAND_SAMPLES[SAMPLE_COUNT] = {\n";
  171. for (int i = 0; i < count; ++i) {
  172. Vector3 v = samples[i];
  173. table += string.Format("\tfloat3({0},{1},{2}),\n", v.x, v.y, v.z);
  174. }
  175. table += "};\n";
  176. Debug.Log (table);
  177. }
  178. */
  179. }
  180. }