Unity 5.6’s release made some changes to the default sprite shader which make parts of the shader in the following post invalid. At the bottom of this post you’ll find an updated version of the demo project that works in Unity 5.6.
Unity provides a component to outline UI objects, but it doesn’t work on world space sprites. This post will demonstrate a simple way to add outlines to sprites using an extended version of the default sprite shader along with a simple component. This could be used to highlight sprites on mouse over, highlight items in the environment, or just to make sprites stand out from their surroundings.
To begin, create a new shader in your project called Sprite-Outline. This shader provides all the functionality of the default sprite shader, with the additions to allow sprite outlines.
Shader "Sprites/Outline"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
// Add values to determine if outlining is enabled and outline color.
[PerRendererData] _Outline ("Outline", Float) = 0
[PerRendererData] _OutlineColor("Outline Color", Color) = (1,1,1,1)
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ PIXELSNAP_ON
#pragma shader_feature ETC1_EXTERNAL_ALPHA
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
fixed4 _Color;
float _Outline;
fixed4 _OutlineColor;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap (OUT.vertex);
#endif
return OUT;
}
sampler2D _MainTex;
sampler2D _AlphaTex;
float4 _MainTex_TexelSize;
fixed4 SampleSpriteTexture (float2 uv)
{
fixed4 color = tex2D (_MainTex, uv);
#if ETC1_EXTERNAL_ALPHA
// get the color from an external texture (usecase: Alpha support for ETC1 on android)
color.a = tex2D (_AlphaTex, uv).r;
#endif //ETC1_EXTERNAL_ALPHA
return color;
}
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
// If outline is enabled and there is a pixel, try to draw an outline.
if (_Outline > 0 && c.a != 0) {
// Get the neighbouring four pixels.
fixed4 pixelUp = tex2D(_MainTex, IN.texcoord + fixed2(0, _MainTex_TexelSize.y));
fixed4 pixelDown = tex2D(_MainTex, IN.texcoord - fixed2(0, _MainTex_TexelSize.y));
fixed4 pixelRight = tex2D(_MainTex, IN.texcoord + fixed2(_MainTex_TexelSize.x, 0));
fixed4 pixelLeft = tex2D(_MainTex, IN.texcoord - fixed2(_MainTex_TexelSize.x, 0));
// If one of the neighbouring pixels is invisible, we render an outline.
if (pixelUp.a * pixelDown.a * pixelRight.a * pixelLeft.a == 0) {
c.rgba = fixed4(1, 1, 1, 1) * _OutlineColor;
}
}
c.rgb *= c.a;
return c;
}
ENDCG
}
}
}
Now create a new material called SpriteOutline and assign the newly created shader to it in the inspector.
Next create a new C# script and name it SpriteOutline. This component is going to handle updating our material in the editor and at runtime to toggle the outline off or on and also change the color. This component can also be targetted in an animation to enable or disable outlines for specific animation frames or to change the outline color.
Now that the hard work is done, add a few sprites to your scene. Change the material field of the SpriteRenderer component to the SpriteOutline material created above. You’ll also want to add the SpriteOutline component to this game object to show a white outline by default. To hide the outline simply disable or remove the component.
With all that completed, you should now have a sprite with a white outline. In the inspector you can change the color to anything you’d like, independently from the SpriteRenderer color. The custom shader also maintains all existing functionality of the default sprite shader.
Please download the demo project and play around with it to get a better idea of how this technique looks and works. It contains a single scene with three examples of outlined sprites, one of which is animated.
Shaders can be complicated, but they are very powerful and make it quite easy to implement graphical features, even in 2D. If you have any further questions please feel free to message me on Twitter @RyanNielson or comment below.
Update (June 2, 2016)
Some people have been asking about how to change the thickness of the sprite outlines. Please download this new demo project with the changes to add this functionality. Changes were made to both the shader and component. Just adjust the outline size slider on the sprite outline component to change outline size. There is a limited outline size of 16 to prevent issues with shader for loop unrolling. It hasn’t been tested throughly, so your results may vary, but it’s probably a good place to start.
Update (April 7, 2017)
Unity 5.6 has been released, and along with that came some changes to the default sprite shader. Unfortunetely this seems to be causing issues with parts of the method used above. Please download this new demo project which changes the sprite outline shader to incorporate the 5.6 shader changes.
If you ever want to create cool effects like hot air waving or thick glass refraction or some underwater streams you will came to Detonator package and HeatDistort shader.But as for me it looks very complicated, so write my own and use it well with latest Unity 2D system.
NOTE: it works only with Unity Pro and Deffered lighting on. It works the same way how Detonator'a works. It tooks image and project it correctly on a plane with texture distortion.
We will split tutorial into 2 steps. 1.Explain shader 2. How to use it.
_Refraction -amount of distortion _DistortText - texture according to what we gonna distort our environment. You can use any colored texture. To make distortion. But in fact only Red and Green channels are working as distortion vector.
Tags { "RenderType"="Transparent" "Queue"="Overlay" } - We set Queue to Overlay because we want to render this effect after everything.
#pragma surface surf NoLighting #pragma vertex vert We used custom NoLigthing model and custom vertex shader to have deal with vertex color that used in particle system. There is a little chunk, cuz we write only Emission to have absolutely No Lighting shader.
float3 distort = tex2D(_DistortTex, IN.uv_DistortTex) * float3(IN.color.r,IN.color.g,IN.color.b ); float2 offset = distort * _Refraction * _GrabTexture_TexelSize.xy; IN.screenPos.xy = offset * IN.screenPos.z + IN.screenPos.xy; float4 refrColor = tex2Dproj(_GrabTexture, IN.screenPos); Here we read distort texture, calculate offset of the screen and project on the model correctly. That's it.
2. Create a simple material and apply that shader. Next if you use particle system apply particle render order script to that. Other way some object will be rendered after distortion so it will looks weird. You can use particle Color or Color Over LifeTime to make distortion more/less. I often setup it thats way:
to make distortion fade in and fade out. Thats probabbly all that you need to know about.
Know bugs:
1.
How to resolve: Add particle order script to PS and set order to bigger then foreground sprite. Effect is not working with orthographic camera
2. To much distortion on large distance to camera
How to resolve: add script that decreasing material property distortion with distance to camera.
Ok. Here's small update: http://www.jostavo.net/NShader.rar (it's a new fork for 2013 by SilentSouls that uses embedded coloring, the one Nims mentioned before)
I've added support of .shader, .compute, .cginc (sorry just handling not native support, see attach)
*optional* - in VisualStudio go Tools > Extensions and Updates find NShader and uninstall it, reboot studio (it need to be restarted to remove files) Make sure Visual Studio is closed
Who afraid to download my file, install one from jostavo.net and then create and add .reg: For future updates: {af99cc5c-2a8a-3547-b255-896525bc39d1} - is UUID for current build only!
To find one You needed - open NShader.pkgdef and look for: Or after install go There will be yours.
NGUI's clipping is done by choosing a different shader with a similar name. Look at the existing shaders, for exmaple:
Unlit - Transparent Colored < -- used if no clipping is needed Unlit - Transparent Colored 1 <-- used if there is 1 panel clipping the content Unlit - Transparent Colored 2 <-- used if there are 2 panels clipping the content Unlit - Transparent Colored 3 <-- used if there are 3 panels clipping the content
When making custom shaders, you would need to follow the same naming convention. The easiest thing to do is to just make a copy of at least two shaders (the first two) and modify them to suit your needs. In case of additive blending, all you would do is change the blend line from:
댓글을 달아 주세요