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.

500 lines
15 KiB

  1. // Upgrade NOTE: commented out 'float4x4 _WorldToCamera', a built-in variable
  2. // Upgrade NOTE: replaced '_WorldToCamera' with 'unity_WorldToCamera'
  3. #ifndef __AMBIENT_OCCLUSION__
  4. #define __AMBIENT_OCCLUSION__
  5. #include "UnityCG.cginc"
  6. #include "Common.cginc"
  7. // --------
  8. // Options for further customization
  9. // --------
  10. // By default, a 5-tap Gaussian with the linear sampling technique is used
  11. // in the bilateral noise filter. It can be replaced with a 7-tap Gaussian
  12. // with adaptive sampling by enabling the macro below. Although the
  13. // differences are not noticeable in most cases, it may provide preferable
  14. // results with some special usage (e.g. NPR without textureing).
  15. // #define BLUR_HIGH_QUALITY
  16. // By default, a fixed sampling pattern is used in the AO estimator. Although
  17. // this gives preferable results in most cases, a completely random sampling
  18. // pattern could give aesthetically better results. Disable the macro below
  19. // to use such a random pattern instead of the fixed one.
  20. #define FIX_SAMPLING_PATTERN
  21. // The SampleNormal function normalizes samples from G-buffer because
  22. // they're possibly unnormalized. We can eliminate this if it can be said
  23. // that there is no wrong shader that outputs unnormalized normals.
  24. // #define VALIDATE_NORMALS
  25. // The constant below determines the contrast of occlusion. This allows
  26. // users to control over/under occlusion. At the moment, this is not exposed
  27. // to the editor because it�s rarely useful.
  28. static const float kContrast = 0.6;
  29. // The constant below controls the geometry-awareness of the bilateral
  30. // filter. The higher value, the more sensitive it is.
  31. static const float kGeometryCoeff = 0.8;
  32. // The constants below are used in the AO estimator. Beta is mainly used
  33. // for suppressing self-shadowing noise, and Epsilon is used to prevent
  34. // calculation underflow. See the paper (Morgan 2011 http://goo.gl/2iz3P)
  35. // for further details of these constants.
  36. static const float kBeta = 0.002;
  37. // --------
  38. // System built-in variables
  39. sampler2D _CameraGBufferTexture2;
  40. sampler2D_float _CameraDepthTexture;
  41. sampler2D _CameraDepthNormalsTexture;
  42. float4 _CameraDepthTexture_ST;
  43. // Sample count
  44. #if !defined(SHADER_API_GLES)
  45. int _SampleCount;
  46. #else
  47. // GLES2: In many cases, dynamic looping is not supported.
  48. static const int _SampleCount = 3;
  49. #endif
  50. // Source texture properties
  51. sampler2D _OcclusionTexture;
  52. float4 _OcclusionTexture_TexelSize;
  53. // Other parameters
  54. half _Intensity;
  55. float _Radius;
  56. float _Downsample;
  57. float3 _FogParams; // x: density, y: start, z: end
  58. // Accessors for packed AO/normal buffer
  59. fixed4 PackAONormal(fixed ao, fixed3 n)
  60. {
  61. return fixed4(ao, n * 0.5 + 0.5);
  62. }
  63. fixed GetPackedAO(fixed4 p)
  64. {
  65. return p.r;
  66. }
  67. fixed3 GetPackedNormal(fixed4 p)
  68. {
  69. return p.gba * 2.0 - 1.0;
  70. }
  71. // Boundary check for depth sampler
  72. // (returns a very large value if it lies out of bounds)
  73. float CheckBounds(float2 uv, float d)
  74. {
  75. float ob = any(uv < 0) + any(uv > 1);
  76. #if defined(UNITY_REVERSED_Z)
  77. ob += (d <= 0.00001);
  78. #else
  79. ob += (d >= 0.99999);
  80. #endif
  81. return ob * 1e8;
  82. }
  83. // Depth/normal sampling functions
  84. float SampleDepth(float2 uv)
  85. {
  86. #if defined(SOURCE_GBUFFER) || defined(SOURCE_DEPTH)
  87. float d = LinearizeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv));
  88. #else
  89. float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
  90. float d = DecodeFloatRG(cdn.zw);
  91. #endif
  92. return d * _ProjectionParams.z + CheckBounds(uv, d);
  93. }
  94. float3 SampleNormal(float2 uv)
  95. {
  96. #if defined(SOURCE_GBUFFER)
  97. float3 norm = tex2D(_CameraGBufferTexture2, uv).xyz;
  98. norm = norm * 2 - any(norm); // gets (0,0,0) when norm == 0
  99. norm = mul((float3x3)unity_WorldToCamera, norm);
  100. #if defined(VALIDATE_NORMALS)
  101. norm = normalize(norm);
  102. #endif
  103. return norm;
  104. #else
  105. float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
  106. return DecodeViewNormalStereo(cdn) * float3(1.0, 1.0, -1.0);
  107. #endif
  108. }
  109. float SampleDepthNormal(float2 uv, out float3 normal)
  110. {
  111. #if defined(SOURCE_GBUFFER) || defined(SOURCE_DEPTH)
  112. normal = SampleNormal(uv);
  113. return SampleDepth(uv);
  114. #else
  115. float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
  116. normal = DecodeViewNormalStereo(cdn) * float3(1.0, 1.0, -1.0);
  117. float d = DecodeFloatRG(cdn.zw);
  118. return d * _ProjectionParams.z + CheckBounds(uv, d);
  119. #endif
  120. }
  121. // Normal vector comparer (for geometry-aware weighting)
  122. half CompareNormal(half3 d1, half3 d2)
  123. {
  124. return smoothstep(kGeometryCoeff, 1.0, dot(d1, d2));
  125. }
  126. // Common vertex shader
  127. struct VaryingsMultitex
  128. {
  129. float4 pos : SV_POSITION;
  130. half2 uv : TEXCOORD0; // Original UV
  131. half2 uv01 : TEXCOORD1; // Alternative UV (supports v-flip case)
  132. half2 uvSPR : TEXCOORD2; // Single pass stereo rendering UV
  133. };
  134. VaryingsMultitex VertMultitex(AttributesDefault v)
  135. {
  136. half2 uvAlt = v.texcoord.xy;
  137. #if UNITY_UV_STARTS_AT_TOP
  138. if (_MainTex_TexelSize.y < 0.0) uvAlt.y = 1.0 - uvAlt.y;
  139. #endif
  140. VaryingsMultitex o;
  141. o.pos = UnityObjectToClipPos(v.vertex);
  142. o.uv = v.texcoord.xy;
  143. o.uv01 = uvAlt;
  144. o.uvSPR = UnityStereoTransformScreenSpaceTex(uvAlt);
  145. return o;
  146. }
  147. // Trigonometric function utility
  148. float2 CosSin(float theta)
  149. {
  150. float sn, cs;
  151. sincos(theta, sn, cs);
  152. return float2(cs, sn);
  153. }
  154. // Pseudo random number generator with 2D coordinates
  155. float UVRandom(float u, float v)
  156. {
  157. float f = dot(float2(12.9898, 78.233), float2(u, v));
  158. return frac(43758.5453 * sin(f));
  159. }
  160. // Check if the camera is perspective.
  161. // (returns 1.0 when orthographic)
  162. float CheckPerspective(float x)
  163. {
  164. return lerp(x, 1.0, unity_OrthoParams.w);
  165. }
  166. // Reconstruct view-space position from UV and depth.
  167. // p11_22 = (unity_CameraProjection._11, unity_CameraProjection._22)
  168. // p13_31 = (unity_CameraProjection._13, unity_CameraProjection._23)
  169. float3 ReconstructViewPos(float2 uv, float depth, float2 p11_22, float2 p13_31)
  170. {
  171. return float3((uv * 2.0 - 1.0 - p13_31) / p11_22 * CheckPerspective(depth), depth);
  172. }
  173. // Sample point picker
  174. float3 PickSamplePoint(float2 uv, float index)
  175. {
  176. // Uniformaly distributed points on a unit sphere http://goo.gl/X2F1Ho
  177. #if defined(FIX_SAMPLING_PATTERN)
  178. float gn = GradientNoise(uv * _Downsample);
  179. // FIXME: This was added to avoid a NVIDIA driver issue.
  180. // vvvvvvvvvvvv
  181. float u = frac(UVRandom(0.0, index + uv.x * 1e-10) + gn) * 2.0 - 1.0;
  182. float theta = (UVRandom(1.0, index + uv.x * 1e-10) + gn) * UNITY_PI_2;
  183. #else
  184. float u = UVRandom(uv.x + _Time.x, uv.y + index) * 2.0 - 1.0;
  185. float theta = UVRandom(-uv.x - _Time.x, uv.y + index) * UNITY_PI_2;
  186. #endif
  187. float3 v = float3(CosSin(theta) * sqrt(1.0 - u * u), u);
  188. // Make them distributed between [0, _Radius]
  189. float l = sqrt((index + 1.0) / _SampleCount) * _Radius;
  190. return v * l;
  191. }
  192. // Fog handling in forward
  193. half ComputeFog(float z)
  194. {
  195. half fog = 0.0;
  196. #if FOG_LINEAR
  197. fog = (_FogParams.z - z) / (_FogParams.z - _FogParams.y);
  198. #elif FOG_EXP
  199. fog = exp2(-_FogParams.x * z);
  200. #else // FOG_EXP2
  201. fog = _FogParams.x * z;
  202. fog = exp2(-fog * fog);
  203. #endif
  204. return saturate(fog);
  205. }
  206. float ComputeDistance(float depth)
  207. {
  208. float dist = depth * _ProjectionParams.z;
  209. dist -= _ProjectionParams.y;
  210. return dist;
  211. }
  212. //
  213. // Distance-based AO estimator based on Morgan 2011 http://goo.gl/2iz3P
  214. //
  215. half4 FragAO(VaryingsMultitex i) : SV_Target
  216. {
  217. float2 uv = i.uv;
  218. // Parameters used in coordinate conversion
  219. float3x3 proj = (float3x3)unity_CameraProjection;
  220. float2 p11_22 = float2(unity_CameraProjection._11, unity_CameraProjection._22);
  221. float2 p13_31 = float2(unity_CameraProjection._13, unity_CameraProjection._23);
  222. // View space normal and depth
  223. float3 norm_o;
  224. float depth_o = SampleDepthNormal(UnityStereoScreenSpaceUVAdjust(uv, _CameraDepthTexture_ST), norm_o);
  225. #if defined(SOURCE_DEPTHNORMALS)
  226. // Offset the depth value to avoid precision error.
  227. // (depth in the DepthNormals mode has only 16-bit precision)
  228. depth_o -= _ProjectionParams.z / 65536;
  229. #endif
  230. // Reconstruct the view-space position.
  231. float3 vpos_o = ReconstructViewPos(i.uv01, depth_o, p11_22, p13_31);
  232. float ao = 0.0;
  233. for (int s = 0; s < _SampleCount; s++)
  234. {
  235. // Sample point
  236. #if defined(SHADER_API_D3D11)
  237. // This 'floor(1.0001 * s)' operation is needed to avoid a NVidia
  238. // shader issue. This issue is only observed on DX11.
  239. float3 v_s1 = PickSamplePoint(uv, floor(1.0001 * s));
  240. #else
  241. float3 v_s1 = PickSamplePoint(uv, s);
  242. #endif
  243. v_s1 = faceforward(v_s1, -norm_o, v_s1);
  244. float3 vpos_s1 = vpos_o + v_s1;
  245. // Reproject the sample point
  246. float3 spos_s1 = mul(proj, vpos_s1);
  247. float2 uv_s1_01 = (spos_s1.xy / CheckPerspective(vpos_s1.z) + 1.0) * 0.5;
  248. // Depth at the sample point
  249. float depth_s1 = SampleDepth(UnityStereoScreenSpaceUVAdjust(uv_s1_01, _CameraDepthTexture_ST));
  250. // Relative position of the sample point
  251. float3 vpos_s2 = ReconstructViewPos(uv_s1_01, depth_s1, p11_22, p13_31);
  252. float3 v_s2 = vpos_s2 - vpos_o;
  253. // Estimate the obscurance value
  254. float a1 = max(dot(v_s2, norm_o) - kBeta * depth_o, 0.0);
  255. float a2 = dot(v_s2, v_s2) + EPSILON;
  256. ao += a1 / a2;
  257. }
  258. ao *= _Radius; // intensity normalization
  259. // Apply other parameters.
  260. ao = pow(ao * _Intensity / _SampleCount, kContrast);
  261. // Apply fog when enabled (forward-only)
  262. #if !FOG_OFF
  263. float d = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv));
  264. d = ComputeDistance(d);
  265. ao *= ComputeFog(d);
  266. #endif
  267. return PackAONormal(ao, norm_o);
  268. }
  269. // Geometry-aware separable bilateral filter
  270. half4 FragBlur(VaryingsMultitex i) : SV_Target
  271. {
  272. #if defined(BLUR_HORIZONTAL)
  273. // Horizontal pass: Always use 2 texels interval to match to
  274. // the dither pattern.
  275. float2 delta = float2(_MainTex_TexelSize.x * 2.0, 0.0);
  276. #else
  277. // Vertical pass: Apply _Downsample to match to the dither
  278. // pattern in the original occlusion buffer.
  279. float2 delta = float2(0.0, _MainTex_TexelSize.y / _Downsample * 2.0);
  280. #endif
  281. #if defined(BLUR_HIGH_QUALITY)
  282. // High quality 7-tap Gaussian with adaptive sampling
  283. fixed4 p0 = tex2D(_MainTex, i.uvSPR);
  284. fixed4 p1a = tex2D(_MainTex, i.uvSPR - delta);
  285. fixed4 p1b = tex2D(_MainTex, i.uvSPR + delta);
  286. fixed4 p2a = tex2D(_MainTex, i.uvSPR - delta * 2.0);
  287. fixed4 p2b = tex2D(_MainTex, i.uvSPR + delta * 2.0);
  288. fixed4 p3a = tex2D(_MainTex, i.uvSPR - delta * 3.2307692308);
  289. fixed4 p3b = tex2D(_MainTex, i.uvSPR + delta * 3.2307692308);
  290. #if defined(BLUR_SAMPLE_CENTER_NORMAL)
  291. fixed3 n0 = SampleNormal(i.uvSPR);
  292. #else
  293. fixed3 n0 = GetPackedNormal(p0);
  294. #endif
  295. half w0 = 0.37004405286;
  296. half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * 0.31718061674;
  297. half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * 0.31718061674;
  298. half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * 0.19823788546;
  299. half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * 0.19823788546;
  300. half w3a = CompareNormal(n0, GetPackedNormal(p3a)) * 0.11453744493;
  301. half w3b = CompareNormal(n0, GetPackedNormal(p3b)) * 0.11453744493;
  302. half s;
  303. s = GetPackedAO(p0) * w0;
  304. s += GetPackedAO(p1a) * w1a;
  305. s += GetPackedAO(p1b) * w1b;
  306. s += GetPackedAO(p2a) * w2a;
  307. s += GetPackedAO(p2b) * w2b;
  308. s += GetPackedAO(p3a) * w3a;
  309. s += GetPackedAO(p3b) * w3b;
  310. s /= w0 + w1a + w1b + w2a + w2b + w3a + w3b;
  311. #else
  312. // Fater 5-tap Gaussian with linear sampling
  313. fixed4 p0 = tex2D(_MainTex, i.uvSPR);
  314. fixed4 p1a = tex2D(_MainTex, i.uvSPR - delta * 1.3846153846);
  315. fixed4 p1b = tex2D(_MainTex, i.uvSPR + delta * 1.3846153846);
  316. fixed4 p2a = tex2D(_MainTex, i.uvSPR - delta * 3.2307692308);
  317. fixed4 p2b = tex2D(_MainTex, i.uvSPR + delta * 3.2307692308);
  318. #if defined(BLUR_SAMPLE_CENTER_NORMAL)
  319. fixed3 n0 = SampleNormal(i.uvSPR);
  320. #else
  321. fixed3 n0 = GetPackedNormal(p0);
  322. #endif
  323. half w0 = 0.2270270270;
  324. half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * 0.3162162162;
  325. half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * 0.3162162162;
  326. half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * 0.0702702703;
  327. half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * 0.0702702703;
  328. half s;
  329. s = GetPackedAO(p0) * w0;
  330. s += GetPackedAO(p1a) * w1a;
  331. s += GetPackedAO(p1b) * w1b;
  332. s += GetPackedAO(p2a) * w2a;
  333. s += GetPackedAO(p2b) * w2b;
  334. s /= w0 + w1a + w1b + w2a + w2b;
  335. #endif
  336. return PackAONormal(s, n0);
  337. }
  338. // Gamma encoding (only needed in gamma lighting mode)
  339. half EncodeAO(half x)
  340. {
  341. half x_g = 1.0 - max(1.055 * pow(1.0 - x, 0.416666667) - 0.055, 0.0);
  342. // ColorSpaceLuminance.w == 0 (gamma) or 1 (linear)
  343. return lerp(x_g, x, unity_ColorSpaceLuminance.w);
  344. }
  345. // Geometry-aware bilateral filter (single pass/small kernel)
  346. half BlurSmall(sampler2D tex, float2 uv, float2 delta)
  347. {
  348. fixed4 p0 = tex2D(tex, uv);
  349. fixed4 p1 = tex2D(tex, uv + float2(-delta.x, -delta.y));
  350. fixed4 p2 = tex2D(tex, uv + float2(+delta.x, -delta.y));
  351. fixed4 p3 = tex2D(tex, uv + float2(-delta.x, +delta.y));
  352. fixed4 p4 = tex2D(tex, uv + float2(+delta.x, +delta.y));
  353. fixed3 n0 = GetPackedNormal(p0);
  354. half w0 = 1.0;
  355. half w1 = CompareNormal(n0, GetPackedNormal(p1));
  356. half w2 = CompareNormal(n0, GetPackedNormal(p2));
  357. half w3 = CompareNormal(n0, GetPackedNormal(p3));
  358. half w4 = CompareNormal(n0, GetPackedNormal(p4));
  359. half s;
  360. s = GetPackedAO(p0) * w0;
  361. s += GetPackedAO(p1) * w1;
  362. s += GetPackedAO(p2) * w2;
  363. s += GetPackedAO(p3) * w3;
  364. s += GetPackedAO(p4) * w4;
  365. return s / (w0 + w1 + w2 + w3 + w4);
  366. }
  367. // Final composition shader
  368. half4 FragComposition(VaryingsMultitex i) : SV_Target
  369. {
  370. float2 delta = _MainTex_TexelSize.xy / _Downsample;
  371. half ao = BlurSmall(_OcclusionTexture, i.uvSPR, delta);
  372. half4 color = tex2D(_MainTex, i.uvSPR);
  373. #if !defined(DEBUG_COMPOSITION)
  374. color.rgb *= 1.0 - EncodeAO(ao);
  375. #else
  376. color.rgb = 1.0 - EncodeAO(ao);
  377. #endif
  378. return color;
  379. }
  380. // Final composition shader (ambient-only mode)
  381. VaryingsDefault VertCompositionGBuffer(AttributesDefault v)
  382. {
  383. VaryingsDefault o;
  384. o.pos = v.vertex;
  385. #if UNITY_UV_STARTS_AT_TOP
  386. o.uv = v.texcoord.xy * float2(1.0, -1.0) + float2(0.0, 1.0);
  387. #else
  388. o.uv = v.texcoord.xy;
  389. #endif
  390. o.uvSPR = UnityStereoTransformScreenSpaceTex(o.uv);
  391. return o;
  392. }
  393. #if !SHADER_API_GLES // excluding the MRT pass under GLES2
  394. struct CompositionOutput
  395. {
  396. half4 gbuffer0 : SV_Target0;
  397. half4 gbuffer3 : SV_Target1;
  398. };
  399. CompositionOutput FragCompositionGBuffer(VaryingsDefault i)
  400. {
  401. // Workaround: _OcclusionTexture_Texelsize hasn't been set properly
  402. // for some reasons. Use _ScreenParams instead.
  403. float2 delta = (_ScreenParams.zw - 1.0) / _Downsample;
  404. half ao = BlurSmall(_OcclusionTexture, i.uvSPR, delta);
  405. CompositionOutput o;
  406. o.gbuffer0 = half4(0.0, 0.0, 0.0, ao);
  407. o.gbuffer3 = half4((half3)EncodeAO(ao), 0.0);
  408. return o;
  409. }
  410. #else
  411. fixed4 FragCompositionGBuffer(VaryingsDefault i) : SV_Target0
  412. {
  413. return 0.0;
  414. }
  415. #endif
  416. #endif // __AMBIENT_OCCLUSION__