ScreenSpaceReflections.hlsl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. #ifndef UNITY_POSTFX_SSR
  2. #define UNITY_POSTFX_SSR
  3. #include "UnityCG.cginc"
  4. #include "UnityPBSLighting.cginc"
  5. #include "UnityStandardBRDF.cginc"
  6. #include "UnityStandardUtils.cginc"
  7. #define SSR_MINIMUM_ATTENUATION 0.275
  8. #define SSR_ATTENUATION_SCALE (1.0 - SSR_MINIMUM_ATTENUATION)
  9. #define SSR_VIGNETTE_INTENSITY _VignetteIntensity
  10. #define SSR_VIGNETTE_SMOOTHNESS 5.
  11. #define SSR_COLOR_NEIGHBORHOOD_SAMPLE_SPREAD 1.0
  12. #define SSR_FINAL_BLEND_STATIC_FACTOR 0.95
  13. #define SSR_FINAL_BLEND_DYNAMIC_FACTOR 0.7
  14. #define SSR_ENABLE_CONTACTS 0
  15. #define SSR_KILL_FIREFLIES 0
  16. //
  17. // Helper structs
  18. //
  19. struct Ray
  20. {
  21. float3 origin;
  22. float3 direction;
  23. };
  24. struct Segment
  25. {
  26. float3 start;
  27. float3 end;
  28. float3 direction;
  29. };
  30. struct Result
  31. {
  32. bool isHit;
  33. float2 uv;
  34. float3 position;
  35. int iterationCount;
  36. };
  37. //
  38. // Uniforms
  39. //
  40. Texture2D _MainTex; SamplerState sampler_MainTex;
  41. Texture2D _History; SamplerState sampler_History;
  42. Texture2D _CameraDepthTexture; SamplerState sampler_CameraDepthTexture;
  43. Texture2D _CameraMotionVectorsTexture; SamplerState sampler_CameraMotionVectorsTexture;
  44. Texture2D _CameraReflectionsTexture; SamplerState sampler_CameraReflectionsTexture;
  45. Texture2D _CameraGBufferTexture0; // albedo = g[0].rgb
  46. Texture2D _CameraGBufferTexture1; // roughness = g[1].a
  47. Texture2D _CameraGBufferTexture2; SamplerState sampler_CameraGBufferTexture2; // normal.xyz 2. * g[2].rgb - 1.
  48. Texture2D _Noise; SamplerState sampler_Noise;
  49. Texture2D _Test; SamplerState sampler_Test;
  50. Texture2D _Resolve; SamplerState sampler_Resolve;
  51. float4 _MainTex_TexelSize;
  52. float4 _Test_TexelSize;
  53. float4x4 _ViewMatrix;
  54. float4x4 _InverseViewMatrix;
  55. float4x4 _InverseProjectionMatrix;
  56. float4x4 _ScreenSpaceProjectionMatrix;
  57. float4 _Params; // x: vignette intensity, y: distance fade, z: maximum march distance, w: blur pyramid lod count
  58. float4 _Params2; // x: aspect ratio, y: noise tiling, z: thickness, w: maximum iteration count
  59. #define _Attenuation .25
  60. #define _VignetteIntensity _Params.x
  61. #define _DistanceFade _Params.y
  62. #define _MaximumMarchDistance _Params.z
  63. #define _BlurPyramidLODCount _Params.w
  64. #define _AspectRatio _Params2.x
  65. #define _NoiseTiling _Params2.y
  66. #define _Bandwidth _Params2.z
  67. #define _MaximumIterationCount _Params2.w
  68. //
  69. // Helper functions
  70. //
  71. float Attenuate(float2 uv)
  72. {
  73. float offset = min(1.0 - max(uv.x, uv.y), min(uv.x, uv.y));
  74. float result = offset / (SSR_ATTENUATION_SCALE * _Attenuation + SSR_MINIMUM_ATTENUATION);
  75. result = saturate(result);
  76. return pow(result, 0.5);
  77. }
  78. float Vignette(float2 uv)
  79. {
  80. float2 k = abs(uv - 0.5) * SSR_VIGNETTE_INTENSITY;
  81. k.x *= _MainTex_TexelSize.y * _MainTex_TexelSize.z;
  82. return pow(saturate(1.0 - dot(k, k)), SSR_VIGNETTE_SMOOTHNESS);
  83. }
  84. float3 GetViewSpacePosition(float2 uv)
  85. {
  86. float depth = _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, UnityStereoTransformScreenSpaceTex(uv), 0).r;
  87. float4 result = mul(_InverseProjectionMatrix, float4(2.0 * uv - 1.0, depth, 1.0));
  88. return result.xyz / result.w;
  89. }
  90. float GetSquaredDistance(float2 first, float2 second)
  91. {
  92. first -= second;
  93. return dot(first, first);
  94. }
  95. float4 ProjectToScreenSpace(float3 position)
  96. {
  97. return float4(
  98. _ScreenSpaceProjectionMatrix[0][0] * position.x + _ScreenSpaceProjectionMatrix[0][2] * position.z,
  99. _ScreenSpaceProjectionMatrix[1][1] * position.y + _ScreenSpaceProjectionMatrix[1][2] * position.z,
  100. _ScreenSpaceProjectionMatrix[2][2] * position.z + _ScreenSpaceProjectionMatrix[2][3],
  101. _ScreenSpaceProjectionMatrix[3][2] * position.z
  102. );
  103. }
  104. // Heavily adapted from McGuire and Mara's original implementation
  105. // http://casual-effects.blogspot.com/2014/08/screen-space-ray-tracing.html
  106. Result March(Ray ray, VaryingsDefault input)
  107. {
  108. Result result;
  109. result.isHit = false;
  110. result.uv = 0.0;
  111. result.position = 0.0;
  112. result.iterationCount = 0;
  113. Segment segment;
  114. segment.start = ray.origin;
  115. float end = ray.origin.z + ray.direction.z * _MaximumMarchDistance;
  116. float magnitude = _MaximumMarchDistance;
  117. if (end > -_ProjectionParams.y)
  118. magnitude = (-_ProjectionParams.y - ray.origin.z) / ray.direction.z;
  119. segment.end = ray.origin + ray.direction * magnitude;
  120. float4 r = ProjectToScreenSpace(segment.start);
  121. float4 q = ProjectToScreenSpace(segment.end);
  122. const float2 homogenizers = rcp(float2(r.w, q.w));
  123. segment.start *= homogenizers.x;
  124. segment.end *= homogenizers.y;
  125. float4 endPoints = float4(r.xy, q.xy) * homogenizers.xxyy;
  126. endPoints.zw += step(GetSquaredDistance(endPoints.xy, endPoints.zw), 0.0001) * max(_Test_TexelSize.x, _Test_TexelSize.y);
  127. float2 displacement = endPoints.zw - endPoints.xy;
  128. bool isPermuted = false;
  129. if (abs(displacement.x) < abs(displacement.y))
  130. {
  131. isPermuted = true;
  132. displacement = displacement.yx;
  133. endPoints.xyzw = endPoints.yxwz;
  134. }
  135. float direction = sign(displacement.x);
  136. float normalizer = direction / displacement.x;
  137. segment.direction = (segment.end - segment.start) * normalizer;
  138. float4 derivatives = float4(float2(direction, displacement.y * normalizer), (homogenizers.y - homogenizers.x) * normalizer, segment.direction.z);
  139. float stride = 1.0 - min(1.0, -ray.origin.z * 0.01);
  140. float2 uv = input.texcoord * _NoiseTiling;
  141. uv.y *= _AspectRatio;
  142. float jitter = _Noise.SampleLevel(sampler_Noise, uv + _WorldSpaceCameraPos.xz, 0).a;
  143. stride *= _Bandwidth;
  144. derivatives *= stride;
  145. segment.direction *= stride;
  146. float2 z = 0.0;
  147. float4 tracker = float4(endPoints.xy, homogenizers.x, segment.start.z) + derivatives * jitter;
  148. for (int i = 0; i < _MaximumIterationCount; ++i)
  149. {
  150. if (any(result.uv < 0.0) || any(result.uv > 1.0))
  151. {
  152. result.isHit = false;
  153. return result;
  154. }
  155. tracker += derivatives;
  156. z.x = z.y;
  157. z.y = tracker.w + derivatives.w * 0.5;
  158. z.y /= tracker.z + derivatives.z * 0.5;
  159. #if SSR_KILL_FIREFLIES
  160. UNITY_FLATTEN
  161. if (z.y < -_MaximumMarchDistance)
  162. {
  163. result.isHit = false;
  164. return result;
  165. }
  166. #endif
  167. UNITY_FLATTEN
  168. if (z.y > z.x)
  169. {
  170. float k = z.x;
  171. z.x = z.y;
  172. z.y = k;
  173. }
  174. uv = tracker.xy;
  175. UNITY_FLATTEN
  176. if (isPermuted)
  177. uv = uv.yx;
  178. uv *= _Test_TexelSize.xy;
  179. float d = _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, UnityStereoTransformScreenSpaceTex(uv), 0);
  180. float depth = -LinearEyeDepth(d);
  181. UNITY_FLATTEN
  182. if (z.y < depth)
  183. {
  184. result.uv = uv;
  185. result.isHit = true;
  186. result.iterationCount = i + 1;
  187. return result;
  188. }
  189. }
  190. return result;
  191. }
  192. //
  193. // Fragment shaders
  194. //
  195. float4 FragTest(VaryingsDefault i) : SV_Target
  196. {
  197. float4 gbuffer2 = _CameraGBufferTexture2.Sample(sampler_CameraGBufferTexture2, i.texcoordStereo);
  198. if (dot(gbuffer2, 1.0) == 0.0)
  199. return 0.0;
  200. float3 normal = 2.0 * gbuffer2.rgb - 1.0;
  201. normal = mul((float3x3)_ViewMatrix, normal);
  202. Ray ray;
  203. ray.origin = GetViewSpacePosition(i.texcoord);
  204. if (ray.origin.z < -_MaximumMarchDistance)
  205. return 0.0;
  206. ray.direction = normalize(reflect(normalize(ray.origin), normal));
  207. if (ray.direction.z > 0.0)
  208. return 0.0;
  209. Result result = March(ray, i);
  210. float confidence = (float)result.iterationCount / (float)_MaximumIterationCount;
  211. return float4(result.uv, confidence, (float)result.isHit);
  212. }
  213. float4 FragResolve(VaryingsDefault i) : SV_Target
  214. {
  215. float4 test = _Test.Load(int3(i.vertex.xy, 0));
  216. if (test.w == 0.0)
  217. return _MainTex.Sample(sampler_MainTex, i.texcoordStereo);
  218. float4 color = _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(test.xy), 0);
  219. float confidence = test.w * Attenuate(test.xy) * Vignette(test.xy);
  220. color.rgb *= confidence;
  221. color.a = test.z;
  222. return color;
  223. }
  224. float4 FragReproject(VaryingsDefault i) : SV_Target
  225. {
  226. float2 motion = _CameraMotionVectorsTexture.SampleLevel(sampler_CameraMotionVectorsTexture, i.texcoordStereo, 0).xy;
  227. float2 uv = i.texcoord - motion;
  228. const float2 k = SSR_COLOR_NEIGHBORHOOD_SAMPLE_SPREAD * _MainTex_TexelSize.xy;
  229. float4 color = _MainTex.SampleLevel(sampler_MainTex, i.texcoordStereo, 0);
  230. // 0 1 2
  231. // 3
  232. float4x4 top = float4x4(
  233. _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + float2(-k.x, -k.y)), 0),
  234. _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + float2( 0.0, -k.y)), 0),
  235. _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + float2( k.x, -k.y)), 0),
  236. _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + float2(-k.x, 0.0)), 0)
  237. );
  238. // 0
  239. // 1 2 3
  240. float4x4 bottom = float4x4(
  241. _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + float2( k.x, 0.0)), 0),
  242. _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + float2(-k.x, k.y)), 0),
  243. _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + float2( 0.0, k.y)), 0),
  244. _MainTex.SampleLevel(sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + float2( k.x, k.y)), 0)
  245. );
  246. // PS4 INTRINSIC_MINMAX3
  247. #if SHADER_API_PSSL
  248. float4 minimum = min3(min3(min3(min3(top[0], top[1], top[2]), top[3], bottom[0]), bottom[1], bottom[2]), bottom[3], color);
  249. float4 maximum = max3(max3(max3(max3(top[0], top[1], top[2]), top[3], bottom[0]), bottom[1], bottom[2]), bottom[3], color);
  250. #else
  251. float4 minimum = min(min(min(min(min(min(min(min(top[0], top[1]), top[2]), top[3]), bottom[0]), bottom[1]), bottom[2]), bottom[3]), color);
  252. float4 maximum = max(max(max(max(max(max(max(max(top[0], top[1]), top[2]), top[3]), bottom[0]), bottom[1]), bottom[2]), bottom[3]), color);
  253. #endif
  254. float4 history = _History.SampleLevel(sampler_History, UnityStereoTransformScreenSpaceTex(uv), 0);
  255. history = clamp(history, minimum, maximum);
  256. color.a = saturate(smoothstep(0.002 * _MainTex_TexelSize.z, 0.0035 * _MainTex_TexelSize.z, length(motion)));
  257. float weight = clamp(lerp(SSR_FINAL_BLEND_STATIC_FACTOR, SSR_FINAL_BLEND_DYNAMIC_FACTOR,
  258. history.a * 100.0), SSR_FINAL_BLEND_DYNAMIC_FACTOR, SSR_FINAL_BLEND_STATIC_FACTOR);
  259. color.a *= 0.85;
  260. return lerp(color, history, weight);
  261. }
  262. float4 FragComposite(VaryingsDefault i) : SV_Target
  263. {
  264. float z = _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, i.texcoordStereo, 0).r;
  265. if (Linear01Depth(z) > 0.999)
  266. return _MainTex.Sample(sampler_MainTex, i.texcoordStereo);
  267. float4 gbuffer0 = _CameraGBufferTexture0.Load(int3(i.vertex.xy, 0));
  268. float4 gbuffer1 = _CameraGBufferTexture1.Load(int3(i.vertex.xy, 0));
  269. float4 gbuffer2 = _CameraGBufferTexture2.Load(int3(i.vertex.xy, 0));
  270. float oneMinusReflectivity = 0.0;
  271. EnergyConservationBetweenDiffuseAndSpecular(gbuffer0.rgb, gbuffer1.rgb, oneMinusReflectivity);
  272. float3 normal = 2.0 * gbuffer2.rgb - 1.0;
  273. float3 position = GetViewSpacePosition(i.texcoord);
  274. float3 eye = mul((float3x3)_InverseViewMatrix, normalize(position));
  275. position = mul(_InverseViewMatrix, float4(position, 1.0)).xyz;
  276. #if SSR_ENABLE_CONTACTS
  277. float4 test = _Test.SampleLevel(sampler_Test, i.texcoordStereo, 0);
  278. float4 resolve = _Resolve.SampleLevel(sampler_Resolve, i.texcoordStereo, SmoothnessToRoughness(gbuffer1.a) * (_BlurPyramidLODCount - 1.0) * test.z + 1.0);
  279. #else
  280. float4 resolve = _Resolve.SampleLevel(sampler_Resolve, i.texcoordStereo, SmoothnessToRoughness(gbuffer1.a) * (_BlurPyramidLODCount - 1.0) + 1.0);
  281. #endif
  282. float confidence = saturate(2.0 * dot(-eye, normalize(reflect(-eye, normal))));
  283. UnityLight light;
  284. light.color = 0.0;
  285. light.dir = 0.0;
  286. light.ndotl = 0.0;
  287. UnityIndirect indirect;
  288. indirect.diffuse = 0.0;
  289. indirect.specular = resolve.rgb;
  290. resolve.rgb = UNITY_BRDF_PBS(gbuffer0.rgb, gbuffer1.rgb, oneMinusReflectivity, gbuffer1.a, normal, -eye, light, indirect).rgb;
  291. float4 reflectionProbes = _CameraReflectionsTexture.Sample(sampler_CameraReflectionsTexture, i.texcoordStereo);
  292. float4 color = _MainTex.Sample(sampler_MainTex, i.texcoordStereo);
  293. color.rgb = max(0.0, color.rgb - reflectionProbes.rgb);
  294. resolve.a *= 2. * resolve.a; // 2 and 1.5 are quite important for the correct ratio of 3:2 distribution
  295. float fade = 1.0 - saturate(1.5 * resolve.a * smoothstep(0.5, 1.0, 1.5 * resolve.a) * _DistanceFade);
  296. resolve.rgb = lerp(reflectionProbes.rgb, resolve.rgb, confidence * fade);
  297. color.rgb += resolve.rgb * gbuffer0.a;
  298. return color;
  299. }
  300. #endif // UNITY_POSTFX_SSR