EdgeDetectNormals.shader 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
  2. Shader "Hidden/EdgeDetect" {
  3. Properties {
  4. _MainTex ("Base (RGB)", 2D) = "" {}
  5. }
  6. CGINCLUDE
  7. #include "UnityCG.cginc"
  8. struct v2f {
  9. float4 pos : SV_POSITION;
  10. float2 uv[5] : TEXCOORD0;
  11. };
  12. struct v2fd {
  13. float4 pos : SV_POSITION;
  14. float2 uv[2] : TEXCOORD0;
  15. };
  16. sampler2D _MainTex;
  17. uniform float4 _MainTex_TexelSize;
  18. sampler2D _CameraDepthNormalsTexture;
  19. sampler2D_float _CameraDepthTexture;
  20. uniform half4 _Sensitivity;
  21. uniform half4 _BgColor;
  22. uniform half _BgFade;
  23. uniform half _SampleDistance;
  24. uniform float _Exponent;
  25. uniform float _Threshold;
  26. struct v2flum {
  27. float4 pos : SV_POSITION;
  28. float2 uv[3] : TEXCOORD0;
  29. };
  30. v2flum vertLum (appdata_img v)
  31. {
  32. v2flum o;
  33. o.pos = UnityObjectToClipPos (v.vertex);
  34. float2 uv = MultiplyUV( UNITY_MATRIX_TEXTURE0, v.texcoord );
  35. o.uv[0] = uv;
  36. o.uv[1] = uv + float2(-_MainTex_TexelSize.x, -_MainTex_TexelSize.y) * _SampleDistance;
  37. o.uv[2] = uv + float2(+_MainTex_TexelSize.x, -_MainTex_TexelSize.y) * _SampleDistance;
  38. return o;
  39. }
  40. fixed4 fragLum (v2flum i) : SV_Target
  41. {
  42. fixed4 original = tex2D(_MainTex, i.uv[0]);
  43. // a very simple cross gradient filter
  44. half3 p1 = original.rgb;
  45. half3 p2 = tex2D(_MainTex, i.uv[1]).rgb;
  46. half3 p3 = tex2D(_MainTex, i.uv[2]).rgb;
  47. half3 diff = p1 * 2 - p2 - p3;
  48. half len = dot(diff, diff);
  49. len = step(len, _Threshold);
  50. //if(len >= _Threshold)
  51. // original.rgb = 0;
  52. return len * lerp(original, _BgColor, _BgFade);
  53. }
  54. inline half CheckSame (half2 centerNormal, float centerDepth, half4 theSample)
  55. {
  56. // difference in normals
  57. // do not bother decoding normals - there's no need here
  58. half2 diff = abs(centerNormal - theSample.xy) * _Sensitivity.y;
  59. int isSameNormal = (diff.x + diff.y) * _Sensitivity.y < 0.1;
  60. // difference in depth
  61. float sampleDepth = DecodeFloatRG (theSample.zw);
  62. float zdiff = abs(centerDepth-sampleDepth);
  63. // scale the required threshold by the distance
  64. int isSameDepth = zdiff * _Sensitivity.x < 0.09 * centerDepth;
  65. // return:
  66. // 1 - if normals and depth are similar enough
  67. // 0 - otherwise
  68. return isSameNormal * isSameDepth ? 1.0 : 0.0;
  69. }
  70. v2f vertRobert( appdata_img v )
  71. {
  72. v2f o;
  73. o.pos = UnityObjectToClipPos(v.vertex);
  74. float2 uv = v.texcoord.xy;
  75. o.uv[0] = uv;
  76. #if UNITY_UV_STARTS_AT_TOP
  77. if (_MainTex_TexelSize.y < 0)
  78. uv.y = 1-uv.y;
  79. #endif
  80. // calc coord for the X pattern
  81. // maybe nicer TODO for the future: 'rotated triangles'
  82. o.uv[1] = uv + _MainTex_TexelSize.xy * half2(1,1) * _SampleDistance;
  83. o.uv[2] = uv + _MainTex_TexelSize.xy * half2(-1,-1) * _SampleDistance;
  84. o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1,1) * _SampleDistance;
  85. o.uv[4] = uv + _MainTex_TexelSize.xy * half2(1,-1) * _SampleDistance;
  86. return o;
  87. }
  88. v2f vertThin( appdata_img v )
  89. {
  90. v2f o;
  91. o.pos = UnityObjectToClipPos (v.vertex);
  92. float2 uv = v.texcoord.xy;
  93. o.uv[0] = uv;
  94. #if UNITY_UV_STARTS_AT_TOP
  95. if (_MainTex_TexelSize.y < 0)
  96. uv.y = 1-uv.y;
  97. #endif
  98. o.uv[1] = uv;
  99. o.uv[4] = uv;
  100. // offsets for two additional samples
  101. o.uv[2] = uv + float2(-_MainTex_TexelSize.x, -_MainTex_TexelSize.y) * _SampleDistance;
  102. o.uv[3] = uv + float2(+_MainTex_TexelSize.x, -_MainTex_TexelSize.y) * _SampleDistance;
  103. return o;
  104. }
  105. v2fd vertD( appdata_img v )
  106. {
  107. v2fd o;
  108. o.pos = UnityObjectToClipPos (v.vertex);
  109. float2 uv = v.texcoord.xy;
  110. o.uv[0] = uv;
  111. #if UNITY_UV_STARTS_AT_TOP
  112. if (_MainTex_TexelSize.y < 0)
  113. uv.y = 1-uv.y;
  114. #endif
  115. o.uv[1] = uv;
  116. return o;
  117. }
  118. float4 fragDCheap(v2fd i) : SV_Target
  119. {
  120. // inspired by borderlands implementation of popular "sobel filter"
  121. float centerDepth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv[1]));
  122. float4 depthsDiag;
  123. float4 depthsAxis;
  124. float2 uvDist = _SampleDistance * _MainTex_TexelSize.xy;
  125. depthsDiag.x = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]+uvDist)); // TR
  126. depthsDiag.y = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]+uvDist*float2(-1,1))); // TL
  127. depthsDiag.z = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]-uvDist*float2(-1,1))); // BR
  128. depthsDiag.w = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]-uvDist)); // BL
  129. depthsAxis.x = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]+uvDist*float2(0,1))); // T
  130. depthsAxis.y = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]-uvDist*float2(1,0))); // L
  131. depthsAxis.z = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]+uvDist*float2(1,0))); // R
  132. depthsAxis.w = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]-uvDist*float2(0,1))); // B
  133. depthsDiag -= centerDepth;
  134. depthsAxis /= centerDepth;
  135. const float4 HorizDiagCoeff = float4(1,1,-1,-1);
  136. const float4 VertDiagCoeff = float4(-1,1,-1,1);
  137. const float4 HorizAxisCoeff = float4(1,0,0,-1);
  138. const float4 VertAxisCoeff = float4(0,1,-1,0);
  139. float4 SobelH = depthsDiag * HorizDiagCoeff + depthsAxis * HorizAxisCoeff;
  140. float4 SobelV = depthsDiag * VertDiagCoeff + depthsAxis * VertAxisCoeff;
  141. float SobelX = dot(SobelH, float4(1,1,1,1));
  142. float SobelY = dot(SobelV, float4(1,1,1,1));
  143. float Sobel = sqrt(SobelX * SobelX + SobelY * SobelY);
  144. Sobel = 1.0-pow(saturate(Sobel), _Exponent);
  145. return Sobel * lerp(tex2D(_MainTex, i.uv[0].xy), _BgColor, _BgFade);
  146. }
  147. // pretty much also just a sobel filter, except for that edges "outside" the silhouette get discarded
  148. // which makes it compatible with other depth based post fx
  149. float4 fragD(v2fd i) : SV_Target
  150. {
  151. // inspired by borderlands implementation of popular "sobel filter"
  152. float centerDepth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv[1]));
  153. float4 depthsDiag;
  154. float4 depthsAxis;
  155. float2 uvDist = _SampleDistance * _MainTex_TexelSize.xy;
  156. depthsDiag.x = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]+uvDist)); // TR
  157. depthsDiag.y = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]+uvDist*float2(-1,1))); // TL
  158. depthsDiag.z = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]-uvDist*float2(-1,1))); // BR
  159. depthsDiag.w = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]-uvDist)); // BL
  160. depthsAxis.x = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]+uvDist*float2(0,1))); // T
  161. depthsAxis.y = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]-uvDist*float2(1,0))); // L
  162. depthsAxis.z = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]+uvDist*float2(1,0))); // R
  163. depthsAxis.w = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv[1]-uvDist*float2(0,1))); // B
  164. // make it work nicely with depth based image effects such as depth of field:
  165. depthsDiag = (depthsDiag > centerDepth.xxxx) ? depthsDiag : centerDepth.xxxx;
  166. depthsAxis = (depthsAxis > centerDepth.xxxx) ? depthsAxis : centerDepth.xxxx;
  167. depthsDiag -= centerDepth;
  168. depthsAxis /= centerDepth;
  169. const float4 HorizDiagCoeff = float4(1,1,-1,-1);
  170. const float4 VertDiagCoeff = float4(-1,1,-1,1);
  171. const float4 HorizAxisCoeff = float4(1,0,0,-1);
  172. const float4 VertAxisCoeff = float4(0,1,-1,0);
  173. float4 SobelH = depthsDiag * HorizDiagCoeff + depthsAxis * HorizAxisCoeff;
  174. float4 SobelV = depthsDiag * VertDiagCoeff + depthsAxis * VertAxisCoeff;
  175. float SobelX = dot(SobelH, float4(1,1,1,1));
  176. float SobelY = dot(SobelV, float4(1,1,1,1));
  177. float Sobel = sqrt(SobelX * SobelX + SobelY * SobelY);
  178. Sobel = 1.0-pow(saturate(Sobel), _Exponent);
  179. return Sobel * lerp(tex2D(_MainTex, i.uv[0].xy), _BgColor, _BgFade);
  180. }
  181. half4 fragRobert(v2f i) : SV_Target {
  182. half4 sample1 = tex2D(_CameraDepthNormalsTexture, i.uv[1].xy);
  183. half4 sample2 = tex2D(_CameraDepthNormalsTexture, i.uv[2].xy);
  184. half4 sample3 = tex2D(_CameraDepthNormalsTexture, i.uv[3].xy);
  185. half4 sample4 = tex2D(_CameraDepthNormalsTexture, i.uv[4].xy);
  186. half edge = 1.0;
  187. edge *= CheckSame(sample1.xy, DecodeFloatRG(sample1.zw), sample2);
  188. edge *= CheckSame(sample3.xy, DecodeFloatRG(sample3.zw), sample4);
  189. return edge * lerp(tex2D(_MainTex, i.uv[0]), _BgColor, _BgFade);
  190. }
  191. half4 fragThin (v2f i) : SV_Target
  192. {
  193. half4 original = tex2D(_MainTex, i.uv[0]);
  194. half4 center = tex2D (_CameraDepthNormalsTexture, i.uv[1]);
  195. half4 sample1 = tex2D (_CameraDepthNormalsTexture, i.uv[2]);
  196. half4 sample2 = tex2D (_CameraDepthNormalsTexture, i.uv[3]);
  197. // encoded normal
  198. half2 centerNormal = center.xy;
  199. // decoded depth
  200. float centerDepth = DecodeFloatRG (center.zw);
  201. half edge = 1.0;
  202. edge *= CheckSame(centerNormal, centerDepth, sample1);
  203. edge *= CheckSame(centerNormal, centerDepth, sample2);
  204. return edge * lerp(original, _BgColor, _BgFade);
  205. }
  206. ENDCG
  207. Subshader {
  208. Pass {
  209. ZTest Always Cull Off ZWrite Off
  210. CGPROGRAM
  211. #pragma vertex vertThin
  212. #pragma fragment fragThin
  213. ENDCG
  214. }
  215. Pass {
  216. ZTest Always Cull Off ZWrite Off
  217. CGPROGRAM
  218. #pragma vertex vertRobert
  219. #pragma fragment fragRobert
  220. ENDCG
  221. }
  222. Pass {
  223. ZTest Always Cull Off ZWrite Off
  224. CGPROGRAM
  225. #pragma target 3.0
  226. #pragma vertex vertD
  227. #pragma fragment fragDCheap
  228. ENDCG
  229. }
  230. Pass {
  231. ZTest Always Cull Off ZWrite Off
  232. CGPROGRAM
  233. #pragma target 3.0
  234. #pragma vertex vertD
  235. #pragma fragment fragD
  236. ENDCG
  237. }
  238. Pass {
  239. ZTest Always Cull Off ZWrite Off
  240. CGPROGRAM
  241. #pragma target 3.0
  242. #pragma vertex vertLum
  243. #pragma fragment fragLum
  244. ENDCG
  245. }
  246. }
  247. Fallback off
  248. } // shader