diff --git a/Assets/SpriteGlow/SpriteOutline.shader b/Assets/SpriteGlow/SpriteOutline.shader index f6e9bcb..715448e 100644 --- a/Assets/SpriteGlow/SpriteOutline.shader +++ b/Assets/SpriteGlow/SpriteOutline.shader @@ -1,5 +1,5 @@ // Draws an HDR outline over the sprite borders. -// Based on Sprites/Default shader from Unity 2017.2. +// Based on Sprites/Default shader from Unity 2017.3. Shader "Sprites/Outline" { @@ -13,10 +13,10 @@ Shader "Sprites/Outline" [PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {} [PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0 - [HideInInspector] _IsOutlineEnabled("Enable Outline", float) = 0 - [HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,1,1) - [HideInInspector] _OutlineSize("Outline Size", float) = 1 - [HideInInspector] _AlphaThreshold("Alpha Threshold", Float) = 0.01 + [MaterialToggle] _IsOutlineEnabled("Enable Outline", float) = 0 + [HDR] _OutlineColor("Outline Color", Color) = (1,1,1,1) + _OutlineSize("Outline Size", Range (1, 10)) = 1 + _AlphaThreshold("Alpha Threshold", Range (0, 1)) = 0.01 } SubShader @@ -54,29 +54,36 @@ Shader "Sprites/Outline" #endif #ifdef UNITY_INSTANCING_ENABLED - UNITY_INSTANCING_CBUFFER_START(PerDrawSprite) - fixed4 unity_SpriteRendererColorArray[UNITY_INSTANCED_ARRAY_SIZE]; - float4 unity_SpriteFlipArray[UNITY_INSTANCED_ARRAY_SIZE]; - UNITY_INSTANCING_CBUFFER_END - #define _RendererColor unity_SpriteRendererColorArray[unity_InstanceID] - #define _Flip unity_SpriteFlipArray[unity_InstanceID] - #endif - - UNITY_INSTANCING_CBUFFER_START(SpriteOutline) - UNITY_DEFINE_INSTANCED_PROP(float, _IsOutlineEnabled) + UNITY_INSTANCING_BUFFER_START(PerDrawSprite) + UNITY_DEFINE_INSTANCED_PROP(fixed4, unity_SpriteRendererColorArray) + UNITY_DEFINE_INSTANCED_PROP(fixed2, unity_SpriteFlipArray) + UNITY_INSTANCING_BUFFER_END(PerDrawSprite) + #define _RendererColor UNITY_ACCESS_INSTANCED_PROP(PerDrawSprite, unity_SpriteRendererColorArray) + #define _Flip UNITY_ACCESS_INSTANCED_PROP(PerDrawSprite, unity_SpriteFlipArray) + + UNITY_INSTANCING_BUFFER_START(PerDrawSpriteOutline) + UNITY_DEFINE_INSTANCED_PROP(float, _IsOutlineEnabled) UNITY_DEFINE_INSTANCED_PROP(fixed4, _OutlineColor) - UNITY_DEFINE_INSTANCED_PROP(float, _OutlineSize) - UNITY_DEFINE_INSTANCED_PROP(float, _AlphaThreshold) - UNITY_INSTANCING_CBUFFER_END + UNITY_DEFINE_INSTANCED_PROP(float, _OutlineSize) + UNITY_DEFINE_INSTANCED_PROP(float, _AlphaThreshold) + UNITY_INSTANCING_BUFFER_END(PerDrawSpriteOutline) + #endif CBUFFER_START(UnityPerDrawSprite) #ifndef UNITY_INSTANCING_ENABLED fixed4 _RendererColor; - float4 _Flip; + fixed2 _Flip; #endif float _EnableExternalAlpha; CBUFFER_END + CBUFFER_START(UnityPerDrawSpriteOutline) + #ifndef UNITY_INSTANCING_ENABLED + fixed4 _OutlineColor; + float _IsOutlineEnabled, _OutlineSize, _AlphaThreshold; + #endif + CBUFFER_END + sampler2D _MainTex, _AlphaTex; float4 _MainTex_TexelSize; fixed4 _Color; @@ -107,7 +114,7 @@ Shader "Sprites/Outline" UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(vertexOutput); #ifdef UNITY_INSTANCING_ENABLED - vertexInput.Vertex.xy *= _Flip.xy; + vertexInput.Vertex.xy *= _Flip; #endif vertexOutput.Vertex = UnityObjectToClipPos(vertexInput.Vertex); @@ -128,24 +135,27 @@ Shader "Sprites/Outline" // Won't draw if effect is disabled, outline size is zero or sampled fragment is tranpsarent. if (isOutlineEnabled * outlineSize * sampledColor.a == 0) return 0; + float2 texDdx = ddx(texCoord); + float2 texDdy = ddy(texCoord); + // Looking for a transparent pixel (sprite border from inside) around computed fragment with given depth (_OutlineSize). // Also checking if sampled fragment is out of the texture space (UV is out of 0-1 range); considering such fragment as sprite border. for (int i = 1; i <= SAMPLE_DEPTH_LIMIT; i++) { float2 pixelUpTexCoord = texCoord + float2(0, i * _MainTex_TexelSize.y); - fixed pixelUpAlpha = pixelUpTexCoord.y > 1.0 ? 0.0 : tex2D(_MainTex, pixelUpTexCoord).a; + fixed pixelUpAlpha = pixelUpTexCoord.y > 1.0 ? 0.0 : tex2Dgrad(_MainTex, pixelUpTexCoord, texDdx, texDdy).a; if (pixelUpAlpha <= alphaThreshold) return 1; float2 pixelDownTexCoord = texCoord - float2(0, i * _MainTex_TexelSize.y); - fixed pixelDownAlpha = pixelDownTexCoord.y < 0.0 ? 0.0 : tex2D(_MainTex, pixelDownTexCoord).a; + fixed pixelDownAlpha = pixelDownTexCoord.y < 0.0 ? 0.0 : tex2Dgrad(_MainTex, pixelDownTexCoord, texDdx, texDdy).a; if (pixelDownAlpha <= alphaThreshold) return 1; float2 pixelRightTexCoord = texCoord + float2(i * _MainTex_TexelSize.x, 0); - fixed pixelRightAlpha = pixelRightTexCoord.x > 1.0 ? 0.0 : tex2D(_MainTex, pixelRightTexCoord).a; + fixed pixelRightAlpha = pixelRightTexCoord.x > 1.0 ? 0.0 : tex2Dgrad(_MainTex, pixelRightTexCoord, texDdx, texDdy).a; if (pixelRightAlpha <= alphaThreshold) return 1; float2 pixelLeftTexCoord = texCoord - float2(i * _MainTex_TexelSize.x, 0); - fixed pixelLeftAlpha = pixelLeftTexCoord.x < 0.0 ? 0.0 : tex2D(_MainTex, pixelLeftTexCoord).a; + fixed pixelLeftAlpha = pixelLeftTexCoord.x < 0.0 ? 0.0 : tex2Dgrad(_MainTex, pixelLeftTexCoord, texDdx, texDdy).a; if (pixelLeftAlpha <= alphaThreshold) return 1; if (i > outlineSize) break; @@ -162,23 +172,26 @@ Shader "Sprites/Outline" if (isOutlineEnabled * outlineSize == 0) return 0; if (sampledColor.a > alphaThreshold) return 0; + float2 texDdx = ddx(texCoord); + float2 texDdy = ddy(texCoord); + // Looking for an opaque pixel (sprite border from outise) around computed fragment with given depth (_OutlineSize). for (int i = 1; i <= SAMPLE_DEPTH_LIMIT; i++) { float2 pixelUpTexCoord = texCoord + float2(0, i * _MainTex_TexelSize.y); - fixed pixelUpAlpha = tex2D(_MainTex, pixelUpTexCoord).a; + fixed pixelUpAlpha = tex2Dgrad(_MainTex, pixelUpTexCoord, texDdx, texDdy).a; if (pixelUpAlpha > alphaThreshold) return 1; float2 pixelDownTexCoord = texCoord - float2(0, i * _MainTex_TexelSize.y); - fixed pixelDownAlpha = tex2D(_MainTex, pixelDownTexCoord).a; + fixed pixelDownAlpha = tex2Dgrad(_MainTex, pixelDownTexCoord, texDdx, texDdy).a; if (pixelDownAlpha > alphaThreshold) return 1; float2 pixelRightTexCoord = texCoord + float2(i * _MainTex_TexelSize.x, 0); - fixed pixelRightAlpha = tex2D(_MainTex, pixelRightTexCoord).a; + fixed pixelRightAlpha = tex2Dgrad(_MainTex, pixelRightTexCoord, texDdx, texDdy).a; if (pixelRightAlpha > alphaThreshold) return 1; float2 pixelLeftTexCoord = texCoord - float2(i * _MainTex_TexelSize.x, 0); - fixed pixelLeftAlpha = tex2D(_MainTex, pixelLeftTexCoord).a; + fixed pixelLeftAlpha = tex2Dgrad(_MainTex, pixelLeftTexCoord, texDdx, texDdy).a; if (pixelLeftAlpha > alphaThreshold) return 1; if (i > outlineSize) break; @@ -206,10 +219,10 @@ Shader "Sprites/Outline" fixed4 color = SampleSpriteTexture(vertexOutput.TexCoord) * vertexOutput.Color; color.rgb *= color.a; - int isOutlineEnabled = UNITY_ACCESS_INSTANCED_PROP(_IsOutlineEnabled); - fixed4 outlineColor = UNITY_ACCESS_INSTANCED_PROP(_OutlineColor); - int outlineSize = UNITY_ACCESS_INSTANCED_PROP(_OutlineSize); - float alphaThreshold = UNITY_ACCESS_INSTANCED_PROP(_AlphaThreshold); + int isOutlineEnabled = UNITY_ACCESS_INSTANCED_PROP(PerDrawSpriteOutline, _IsOutlineEnabled); + fixed4 outlineColor = UNITY_ACCESS_INSTANCED_PROP(PerDrawSpriteOutline, _OutlineColor); + int outlineSize = UNITY_ACCESS_INSTANCED_PROP(PerDrawSpriteOutline, _OutlineSize); + float alphaThreshold = UNITY_ACCESS_INSTANCED_PROP(PerDrawSpriteOutline, _AlphaThreshold); #ifdef SPRITE_OUTLINE_OUTSIDE int shouldDrawOutline = ShouldDrawOutlineOutside(color, vertexOutput.TexCoord, isOutlineEnabled, outlineSize, alphaThreshold);