Guest User

Untitled

a guest
Jul 19th, 2018
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.04 KB | None | 0 0
  1. Shader "Sprites/Outline"
  2. {
  3. Properties
  4. {
  5. [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
  6. _Color("Tint", Color) = (1,1,1,1)
  7. [MaterialToggle] PixelSnap("Pixel snap", Float) = 0
  8. [HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1)
  9. [HideInInspector] _Flip("Flip", Vector) = (1,1,1,1)
  10. [PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {}
  11. [PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0
  12.  
  13. [MaterialToggle] _IsOutlineEnabled("Enable Outline", float) = 0
  14. [HDR] _OutlineColor("Outline Color", Color) = (1,1,1,1)
  15. _OutlineSize("Outline Size", Range(1, 10)) = 1
  16. _AlphaThreshold("Alpha Threshold", Range(0, 1)) = 0.01
  17. }
  18.  
  19. SubShader
  20. {
  21. Tags
  22. {
  23. "Queue" = "Transparent"
  24. "IgnoreProjector" = "True"
  25. "RenderType" = "Transparent"
  26. "PreviewType" = "Plane"
  27. "CanUseSpriteAtlas" = "True"
  28. }
  29.  
  30. Cull Off
  31. Lighting Off
  32. ZWrite Off
  33. Blend One OneMinusSrcAlpha
  34.  
  35. Pass
  36. {
  37. CGPROGRAM
  38.  
  39. #include "UnityCG.cginc"
  40.  
  41. #pragma vertex ComputeVertex
  42. #pragma fragment ComputeFragment
  43. #pragma target 2.0
  44. #pragma multi_compile_instancing
  45. #pragma multi_compile _ PIXELSNAP_ON
  46. #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
  47. #pragma multi_compile _ SPRITE_OUTLINE_OUTSIDE
  48.  
  49. #ifndef SAMPLE_DEPTH_LIMIT
  50. #define SAMPLE_DEPTH_LIMIT 10
  51. #endif
  52.  
  53. #ifdef UNITY_INSTANCING_ENABLED
  54. UNITY_INSTANCING_BUFFER_START(PerDrawSprite)
  55. UNITY_DEFINE_INSTANCED_PROP(fixed4, unity_SpriteRendererColorArray)
  56. UNITY_DEFINE_INSTANCED_PROP(fixed2, unity_SpriteFlipArray)
  57. UNITY_INSTANCING_BUFFER_END(PerDrawSprite)
  58. #define _RendererColor UNITY_ACCESS_INSTANCED_PROP(PerDrawSprite, unity_SpriteRendererColorArray)
  59. #define _Flip UNITY_ACCESS_INSTANCED_PROP(PerDrawSprite, unity_SpriteFlipArray)
  60.  
  61. UNITY_INSTANCING_BUFFER_START(PerDrawSpriteOutline)
  62. UNITY_DEFINE_INSTANCED_PROP(float, _IsOutlineEnabled)
  63. UNITY_DEFINE_INSTANCED_PROP(fixed4, _OutlineColor)
  64. UNITY_DEFINE_INSTANCED_PROP(float, _OutlineSize)
  65. UNITY_DEFINE_INSTANCED_PROP(float, _AlphaThreshold)
  66. UNITY_INSTANCING_BUFFER_END(PerDrawSpriteOutline)
  67. #endif
  68.  
  69. CBUFFER_START(UnityPerDrawSprite)
  70. #ifndef UNITY_INSTANCING_ENABLED
  71. fixed4 _RendererColor;
  72. fixed2 _Flip;
  73. #endif
  74. float _EnableExternalAlpha;
  75. CBUFFER_END
  76.  
  77. CBUFFER_START(UnityPerDrawSpriteOutline)
  78. #ifndef UNITY_INSTANCING_ENABLED
  79. fixed4 _OutlineColor;
  80. float _IsOutlineEnabled, _OutlineSize, _AlphaThreshold;
  81. #endif
  82. CBUFFER_END
  83.  
  84. sampler2D _MainTex, _AlphaTex;
  85. float4 _MainTex_TexelSize;
  86. fixed4 _Color;
  87.  
  88. struct VertexInput
  89. {
  90. float4 Vertex : POSITION;
  91. float4 Color : COLOR;
  92. float2 TexCoord : TEXCOORD0;
  93. UNITY_VERTEX_INPUT_INSTANCE_ID
  94. };
  95.  
  96. struct VertexOutput
  97. {
  98. float4 Vertex : SV_POSITION;
  99. fixed4 Color : COLOR;
  100. float2 TexCoord : TEXCOORD0;
  101. UNITY_VERTEX_INPUT_INSTANCE_ID
  102. UNITY_VERTEX_OUTPUT_STEREO
  103. };
  104.  
  105. VertexOutput ComputeVertex(VertexInput vertexInput)
  106. {
  107. VertexOutput vertexOutput;
  108.  
  109. UNITY_SETUP_INSTANCE_ID(vertexInput);
  110. UNITY_TRANSFER_INSTANCE_ID(vertexInput, vertexOutput);
  111. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(vertexOutput);
  112.  
  113. #ifdef UNITY_INSTANCING_ENABLED
  114. vertexInput.Vertex.xy *= _Flip;
  115. #endif
  116.  
  117. vertexOutput.Vertex = UnityObjectToClipPos(vertexInput.Vertex);
  118. vertexOutput.TexCoord = vertexInput.TexCoord;
  119. vertexOutput.Color = vertexInput.Color * _Color * _RendererColor;
  120.  
  121. #ifdef PIXELSNAP_ON
  122. vertexOutput.Vertex = UnityPixelSnap(vertexOutput.Vertex);
  123. #endif
  124.  
  125. return vertexOutput;
  126. }
  127.  
  128. // Determines whether _OutlineColor should replace sampledColor at the given texCoord when drawing inside the sprite borders.
  129. // Will return 1 when the test is positive (should draw outline), 0 otherwise.
  130. int ShouldDrawOutlineInside(fixed4 sampledColor, float2 texCoord, int isOutlineEnabled, int outlineSize, float alphaThreshold)
  131. {
  132. // Won't draw if effect is disabled, outline size is zero or sampled fragment is tranpsarent.
  133. if (isOutlineEnabled * outlineSize * sampledColor.a == 0) return 0;
  134.  
  135. float2 texDdx = ddx(texCoord);
  136. float2 texDdy = ddy(texCoord);
  137.  
  138. // Looking for a transparent pixel (sprite border from inside) around computed fragment with given depth (_OutlineSize).
  139. // Also checking if sampled fragment is out of the texture space (UV is out of 0-1 range); considering such fragment as sprite border.
  140. for (int i = 1; i <= SAMPLE_DEPTH_LIMIT; i++)
  141. {
  142. float2 pixelUpTexCoord = texCoord + float2(0, i * _MainTex_TexelSize.y);
  143. fixed pixelUpAlpha = pixelUpTexCoord.y > 1.0 ? 0.0 : tex2Dgrad(_MainTex, pixelUpTexCoord, texDdx, texDdy).a;
  144. if (pixelUpAlpha <= alphaThreshold) return 1;
  145.  
  146. float2 pixelDownTexCoord = texCoord - float2(0, i * _MainTex_TexelSize.y);
  147. fixed pixelDownAlpha = pixelDownTexCoord.y < 0.0 ? 0.0 : tex2Dgrad(_MainTex, pixelDownTexCoord, texDdx, texDdy).a;
  148. if (pixelDownAlpha <= alphaThreshold) return 1;
  149.  
  150. float2 pixelRightTexCoord = texCoord + float2(i * _MainTex_TexelSize.x, 0);
  151. fixed pixelRightAlpha = pixelRightTexCoord.x > 1.0 ? 0.0 : tex2Dgrad(_MainTex, pixelRightTexCoord, texDdx, texDdy).a;
  152. if (pixelRightAlpha <= alphaThreshold) return 1;
  153.  
  154. float2 pixelLeftTexCoord = texCoord - float2(i * _MainTex_TexelSize.x, 0);
  155. fixed pixelLeftAlpha = pixelLeftTexCoord.x < 0.0 ? 0.0 : tex2Dgrad(_MainTex, pixelLeftTexCoord, texDdx, texDdy).a;
  156. if (pixelLeftAlpha <= alphaThreshold) return 1;
  157.  
  158. if (i > outlineSize) break;
  159. }
  160.  
  161. return 0;
  162. }
  163.  
  164. // Determines whether _OutlineColor should replace sampledColor at the given texCoord when drawing outside the sprite borders.
  165. // Will return 1 when the test is positive (should draw outline), 0 otherwise.
  166. int ShouldDrawOutlineOutside(fixed4 sampledColor, float2 texCoord, int isOutlineEnabled, int outlineSize, float alphaThreshold)
  167. {
  168. // Won't draw if effect is disabled, outline size is zero or sampled fragment is above alpha threshold.
  169. if (isOutlineEnabled * outlineSize == 0) return 0;
  170. if (sampledColor.a > alphaThreshold) return 0;
  171.  
  172. float2 texDdx = ddx(texCoord);
  173. float2 texDdy = ddy(texCoord);
  174.  
  175. // Looking for an opaque pixel (sprite border from outise) around computed fragment with given depth (_OutlineSize).
  176. for (int i = 1; i <= SAMPLE_DEPTH_LIMIT; i++)
  177. {
  178. float2 pixelUpTexCoord = texCoord + float2(0, i * _MainTex_TexelSize.y);
  179. fixed pixelUpAlpha = tex2Dgrad(_MainTex, pixelUpTexCoord, texDdx, texDdy).a;
  180. if (pixelUpAlpha > alphaThreshold) return 1;
  181.  
  182. float2 pixelDownTexCoord = texCoord - float2(0, i * _MainTex_TexelSize.y);
  183. fixed pixelDownAlpha = tex2Dgrad(_MainTex, pixelDownTexCoord, texDdx, texDdy).a;
  184. if (pixelDownAlpha > alphaThreshold) return 1;
  185.  
  186. float2 pixelRightTexCoord = texCoord + float2(i * _MainTex_TexelSize.x, 0);
  187. fixed pixelRightAlpha = tex2Dgrad(_MainTex, pixelRightTexCoord, texDdx, texDdy).a;
  188. if (pixelRightAlpha > alphaThreshold) return 1;
  189.  
  190. float2 pixelLeftTexCoord = texCoord - float2(i * _MainTex_TexelSize.x, 0);
  191. fixed pixelLeftAlpha = tex2Dgrad(_MainTex, pixelLeftTexCoord, texDdx, texDdy).a;
  192. if (pixelLeftAlpha > alphaThreshold) return 1;
  193.  
  194. if (i > outlineSize) break;
  195. }
  196.  
  197. return 0;
  198. }
  199.  
  200. fixed4 SampleSpriteTexture(float2 uv)
  201. {
  202. fixed4 color = tex2D(_MainTex, uv);
  203.  
  204. #if ETC1_EXTERNAL_ALPHA
  205. fixed4 alpha = tex2D(_AlphaTex, uv);
  206. color.a = lerp(color.a, alpha.r, _EnableExternalAlpha);
  207. #endif
  208.  
  209. return color;
  210. }
  211.  
  212. fixed4 ComputeFragment(VertexOutput vertexOutput) : SV_Target
  213. {
  214. UNITY_SETUP_INSTANCE_ID(vertexOutput);
  215.  
  216. fixed4 color = SampleSpriteTexture(vertexOutput.TexCoord) * vertexOutput.Color;
  217. color.rgb *= color.a;
  218.  
  219. int isOutlineEnabled = UNITY_ACCESS_INSTANCED_PROP(PerDrawSpriteOutline, _IsOutlineEnabled);
  220. fixed4 outlineColor = UNITY_ACCESS_INSTANCED_PROP(PerDrawSpriteOutline, _OutlineColor);
  221. int outlineSize = UNITY_ACCESS_INSTANCED_PROP(PerDrawSpriteOutline, _OutlineSize);
  222. float alphaThreshold = UNITY_ACCESS_INSTANCED_PROP(PerDrawSpriteOutline, _AlphaThreshold);
  223.  
  224. #ifdef SPRITE_OUTLINE_OUTSIDE
  225. int shouldDrawOutline = ShouldDrawOutlineOutside(color, vertexOutput.TexCoord, isOutlineEnabled, outlineSize, alphaThreshold);
  226. #else
  227. int shouldDrawOutline = ShouldDrawOutlineInside(color, vertexOutput.TexCoord, isOutlineEnabled, outlineSize, alphaThreshold);
  228. #endif
  229.  
  230. color = lerp(color, outlineColor * outlineColor.a, shouldDrawOutline);
  231.  
  232. return color;
  233. }
  234.  
  235. ENDCG
  236. }
  237. }
  238. }
Add Comment
Please, Sign In to add comment