Search Unity

  1. Check out the Unite LA keynote for updates on the Visual Effect Editor, the FPS Sample, ECS, Unity for Film and more! Watch it now!
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  4. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Add Outline to Cutout Shader

Discussion in 'Shaders' started by bhayward_incrowd, Dec 1, 2015.

  1. bhayward_incrowd

    bhayward_incrowd

    Joined:
    Nov 3, 2015
    Posts:
    9
    Hello everyone,

    I have a very simple Cutout Shader for displaying Icons in 3D space (see below).

    I want to 'programatically' add an outline/stroke which follows the alpha contours, with a user defined thickness and colour.


    (Left): What I currently have - an alpha cutout shader
    (Right): What I want - An outline to go around the cutout
    Please Note: These are not sprites, they are 3D planes

    How can I go about doing this, please?

    Code (C#):
    1. Shader "Custom/Transparent/CutoutEmissive" {
    2. Properties {
    3.     _Color ("Main Color", Color) = (1,1,1,1)
    4.     _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    5.     _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
    6.     _EmissiveAmount ("Emissive Amount", Range(0,1)) = 0.5
    7.     _Outline ("Outline Thickness", Range(0,10)) = 0.0
    8. }
    9.  
    10. SubShader {
    11.     Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
    12.     LOD 200
    13.    
    14. CGPROGRAM
    15. #pragma surface surf Lambert alphatest:_Cutoff
    16.  
    17. sampler2D _MainTex;
    18. fixed4 _Color;
    19. float _EmissiveAmount;
    20. float _Outline;
    21. struct Input {
    22.     float2 uv_MainTex;
    23. };
    24.  
    25. void surf (Input IN, inout SurfaceOutput o) {
    26.     fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    27.     o.Albedo = c.rgb;
    28.     o.Alpha = c.a;
    29.    
    30.     o.Emission = c.rgb*_EmissiveAmount;
    31. }
    32. ENDCG
    33. }
    34.  
    35. Fallback "Legacy Shaders/Transparent/Cutout/VertexLit"
    36. }
    37.  
     
  2. karp505

    karp505

    Joined:
    Jul 24, 2014
    Posts:
    18
    Check out the "Rim Lighting" shader here. You can use that as the basis, and just tweak a few parameters to suit your needs. http://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html

    To get the alpha cutout effect, grab this section from the shader you pasted:

    Code (CSharp):
    1. SubShader {
    2.     Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
    3.     LOD 200
    4.  
    5. CGPROGRAM
    6. #pragma surface surf Lambert alphatest:_Cutoff
    and use that in the rim lighting shader.
     
  3. bhayward_incrowd

    bhayward_incrowd

    Joined:
    Nov 3, 2015
    Posts:
    9
    I know how to do Rim Lighting, but I don't see how I can translate that to an outline?

    I wouldn't want the rim light to cover up any details on the original texture. As you can see from the image above, the outline adds thickness to the original texture and is rendered behind it.
     
  4. karp505

    karp505

    Joined:
    Jul 24, 2014
    Posts:
    18
    Hmm, well if you want the outline to not overlap at all, I think the easiest thing to do would be to write a script that will blit the sprite into another texture, scale it up a bit, color it the way you want and then render it behind the original sprite.

    You could also do the same method in a shader by doing two separate passes - the first would scale it in the vertex shader and color it red (or whatever) in the fragment shader, and then the second pass would render it normally.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    5,135
    I would suggest you look into using distance fields. These sound much scarier than they are and naive ones can be easily generated in Photoshop or Gimp using edge glow.

    @karp505's suggestion of scaling works as well, but you can't guarantee the line width as it is just simply scaling. It might be good enough as it's quite a cheap option.

    The more expensive option is doing edging in the shader using multiple samples. Something like a sobel filter but applied to the texture's alpha only would allow you to get fairly accurate outlines, but this can get expensive quickly, especially for larger outlines.
     
  6. Dr-Game

    Dr-Game

    Joined:
    Mar 12, 2015
    Posts:
    122
    HI~
    I have same problem!!Did you figure it out??