Search Unity

Can we use new Unity 5.5 editor outline in Game?

Discussion in 'General Graphics' started by Almakos, Dec 13, 2016.

  1. Almakos

    Almakos

    Joined:
    Dec 13, 2013
    Posts:
    179
    Hey guys,
    Unity 5.5 got this new orange outline around selected game objects in the Editor
    Does anybody know if we can use this for drawing outline around objects in games?

    Thank you
     
  2. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    230
    If you add the Effects package from the engine, the Post FX "Edge detection" have changed a lot. I suggest you to give it a shot.
     
  3. Almakos

    Almakos

    Joined:
    Dec 13, 2013
    Posts:
    179
    nice, thank youI'll check it out
     
  4. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    35
    Did you get it working?
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    7,904
  6. KristoferBoman

    KristoferBoman

    Joined:
    Feb 16, 2016
    Posts:
    58
    Hi,

    I've made an implementation of the Unity editor outline to be used in our game. I'm basing it on this post https://forum.unity3d.com/threads/selection-outline.429292/#post-2776318.

    I've managed to get the outlines rendering but cant' get the part right where the outlines should render with a desaturated color when the outline object is behind something.

    I've found the problem that the first pass that renders the color mask does not obey the ZTest LEqual command and always renders all fragments to the red channel, even if the object is behind something.

    Code (CSharp):
    1.          // #0: things that are visible (pass depth). 1 in alpha, 1 in red (SM2.0)
    2.         Pass
    3.         {
    4.             Blend One Zero
    5.  
    6.             ZTest LEqual
    7.        
    8.             Cull Off
    9.  
    10.             ZWrite Off
    11.             Offset -0.02, 0
    12.  
    13.             CGPROGRAM
    14.             #pragma vertex vert
    15.             #pragma fragment frag
    16.             #pragma target 2.0
    17.             float _ObjectId = 1;
    18.             #define DRAW_COLOR float4(1,1,1, 1)
    19.             #include "SceneViewSelected.cginc"
    20.             ENDCG
    21.         }
    So, the red channel is always filled with the value 1 for all outline objects, even if it is behind something, thus i do not have the information i need in the postprocess shader to desaturate the outline.

    If i understand it right it should not have a value at all (red=0) if id does not pass the ZTest, right?

    In the image below you can see the output from the red channel. As you can see all fragments pass the ZTest, which should not be the case.

    RedChannel.png

    In the image below you can see the final postprocess pass that renders the outlines. If i had the right information in the red channel i would be able to desaturate the outline color for the pixels that are ocluded.
    FinalPostprocess.png

    Below is the Outline script that is attached to the main camera. It creates a temporary camera to render the maskbuffer and the applies the postprocess passes i.e blurring and then combining the result.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class OutlinePosteffect : MonoBehaviour
    5. {
    6.    Camera AttachedCamera;
    7.    public Shader Post_Outline;
    8.    public Shader DrawSimple;
    9.    Camera TempCam;
    10.    Material Post_Mat;
    11.  
    12.  
    13.    void Start ()
    14.    {
    15.        AttachedCamera = GetComponent<Camera>();
    16.        TempCam = new GameObject().AddComponent<Camera>();
    17.        TempCam.enabled = false;
    18.        Post_Mat = new Material(Post_Outline);
    19.     }
    20.    //Subtract the original image from the blurred image
    21.    void OnRenderImage(RenderTexture source, RenderTexture destination)
    22.    {
    23.         //set up a temporary camera
    24.         TempCam.CopyFrom(AttachedCamera);
    25.         TempCam.clearFlags = CameraClearFlags.Color;
    26.         TempCam.backgroundColor = Color.black;
    27.    
    28.         //cull any layer that isn't the outline
    29.         TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");
    30.  
    31.         RenderTextureFormat rtFormat = RenderTextureFormat.ARGBHalf;
    32.         if (!SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf))
    33.             rtFormat = RenderTextureFormat.ARGB32;
    34.  
    35.        //make the temporary rendertexture
    36.        RenderTexture TempRT = new RenderTexture(source.width, source.height, 0, rtFormat);
    37.  
    38.        //put it to video memory
    39.        TempRT.Create();
    40.  
    41.        //set the camera's target texture when rendering
    42.        TempCam.targetTexture = TempRT;
    43.  
    44.         // Outline process:
    45.         // 1. render selected objects into a mask buffer, with different colors for visible vs occluded ones (using existing Z buffer for testing)
    46.         TempCam.RenderWithShader(DrawSimple,"");
    47.         // 1. End
    48.  
    49.         // 2. blur the mask information in two separable passes, keeping the mask channels
    50.         RenderTexture horizontalBlur = new RenderTexture(source.width, source.height, 0, rtFormat);
    51.        horizontalBlur.Create ();
    52.  
    53.        Post_Mat.SetVector ("_BlurDirection", new Vector2 (1, 0));
    54.        Graphics.Blit(TempRT, horizontalBlur,Post_Mat,0);
    55.  
    56.        RenderTexture verticalBlur = new RenderTexture(source.width, source.height, 0, rtFormat);
    57.        verticalBlur.Create ();
    58.  
    59.        Post_Mat.SetVector ("_BlurDirection", new Vector2 (0, 1));
    60.        Graphics.Blit(horizontalBlur, verticalBlur,Post_Mat,0);
    61.         // 2. End
    62.  
    63.  
    64.         // 3. blend outline over existing scene image. blurred information & mask channels allow computing distance to selected
    65.         // object edges, from which we create the outline pixels
    66.         Graphics.Blit(verticalBlur, destination, Post_Mat, 1);
    67.         // 3. End
    68.  
    69.  
    70.  
    71.         //release the temporary RT
    72.         TempRT.Release();
    73.        horizontalBlur.Release ();
    74.        verticalBlur.Release ();
    75.    }
    76.  
    77. }
     
  7. KristoferBoman

    KristoferBoman

    Joined:
    Feb 16, 2016
    Posts:
    58
    After some reading in other post's it seems that if you are using a secondary camera(like i do) it will not share the depthbuffer with the first camera, and thats why the ZTest does not work. But it would be nice if someone from Unity could confirm this.
     
  8. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    230
    Every camera have his own depthbuffer and it will not be shared indeed.
     
  9. KristoferBoman

    KristoferBoman

    Joined:
    Feb 16, 2016
    Posts:
    58
    Hmm, ok. So could anyone maybe shed some light on how i could make the mask camera ZTesting against the first camera depth?

    Or explain in more depth how they do it in the Editor explained in short here https://forum.unity3d.com/threads/selection-outline.429292/#post-2776318.

    // 1. render selected objects into a mask buffer, with different colors for visible vs occluded ones (using existing Z buffer for testing)
     
  10. KristoferBoman

    KristoferBoman

    Joined:
    Feb 16, 2016
    Posts:
    58
    I have still not been able to solve this. Posting my code in the hopes that someone will be able to help

    OutlinePosteffect.cs - Attach this to the main camera.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. public class OutlinePosteffect : MonoBehaviour
    5. {
    6.     Camera _mainCamera;
    7.     Camera _maskCamera;
    8.     RenderTexture _maskRT;
    9.     RenderTexture _blurRT;
    10.  
    11.     public Shader Post_Outline;
    12.     public Shader DrawSimple;
    13.     public Material _postMaterial;
    14.  
    15.     void Awake()
    16.     {
    17.         _blurRT = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.Default);
    18.         _maskRT = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.Default);
    19.  
    20.         _mainCamera = GetComponent<Camera>();
    21.  
    22.         _maskCamera = new GameObject("MaskCamera").AddComponent<Camera>();
    23.         _maskCamera.enabled = false;
    24.  
    25.         _postMaterial = new Material(Post_Outline);
    26.     }
    27.     void OnRenderImage(RenderTexture source, RenderTexture destination)
    28.     {
    29.         _maskCamera.CopyFrom(_mainCamera);
    30.         _maskCamera.backgroundColor = Color.black;
    31.         _maskCamera.clearFlags = CameraClearFlags.Nothing;
    32.         _maskCamera.cullingMask = 1 << LayerMask.NameToLayer("Outline");
    33.  
    34.         RenderTexture activeRT = RenderTexture.active;
    35.         RenderTexture.active = _maskRT;
    36.  
    37.         GL.Clear(true, true, Color.clear);
    38.  
    39.         RenderTexture.active = activeRT;
    40.  
    41.         // 1. render selected objects into a mask buffer, with different colors for visible vs occluded ones (using existing Z buffer for testing)
    42.         // Passing the source.depthBuffer does not work. I.e it does not use it in the ZTest like i think it should?
    43.         _maskCamera.SetTargetBuffers(_maskRT.colorBuffer, source.depthBuffer);
    44.         _maskCamera.RenderWithShader(DrawSimple, "");
    45.         // 1. End
    46.  
    47.         // 2. blur the mask information in two separable passes, keeping the mask channels
    48.         _postMaterial.SetVector("_BlurDirection", new Vector2(0, 1));//Vertical
    49.         Graphics.Blit(_maskRT, _blurRT, _postMaterial, 0);
    50.         _postMaterial.SetVector("_BlurDirection", new Vector2(1, 0));//Vertical
    51.         Graphics.Blit(_blurRT, _maskRT, _postMaterial, 0);
    52.         // 2. End
    53.  
    54.         // 3.blend outline over existing scene image.blurred information &mask channels allow computing distance to selected
    55.         // This is the #1: final postprocessing pass in PostOutline.shader. Right now i just substract mask channel(col.r) from blurred channel(col.b) to get the outline
    56.         Graphics.Blit(_maskRT, destination, _postMaterial, 1);
    57.  
    58.         _maskRT.DiscardContents();
    59.         _blurRT.DiscardContents();
    60.     }
    61. }
    DrawSimple.shader - Drag it to the "Draw Simple" slot on the camera that has the OutlonePosteffect.cs

    Code (CSharp):
    1. Shader "Custom/DrawSimple"
    2. {
    3.     SubShader
    4.     {
    5.         // #0: things that are visible (pass depth). 1 in alpha, 1 in red (SM2.0)
    6.         Pass
    7.         {
    8.  
    9.             //One = The value of one - use this to let either the source or the destination color come through fully.
    10.             //Zero = The value zero - use this to remove either the source or the destination values.
    11.             Blend One Zero
    12.  
    13.             //Only render pixels whose reference value is less than or equal to the value in the buffer.
    14.             ZTest LEqual
    15.          
    16.             //Off = Disables culling - all faces are drawn. Used for special effects.
    17.             Cull Off
    18.  
    19.             //Controls whether pixels from this object are written to the depth buffer (default is On). If you’re drawng solid objects, leave this on.
    20.             //If you’re drawing semitransparent effects, switch to ZWrite Off. For more details read below.
    21.             ZWrite Off
    22.             // push towards camera a bit, so that coord mismatch due to dynamic batching is not affecting us
    23.             Offset -0.02, 0
    24.             CGPROGRAM
    25.             #pragma vertex vert
    26.             #pragma fragment frag
    27.             #pragma target 2.0
    28.  
    29.             float _ObjectId = 1;
    30.             #define DRAW_COLOR float4(1,1,1, 1)
    31.             #include "SceneViewSelected.cginc"
    32.             ENDCG
    33.         }
    34.         // #2: all the things, including the ones that fail the depth test. Additive blend, 1 in green, 1 in alpha (SM2.0)
    35.         Pass
    36.         {
    37.             //Additive Blending
    38.             Blend One One
    39.             //Use the larger of source and destination.
    40.             BlendOp Max
    41.             //Always passes
    42.             ZTest Always
    43.             //Controls whether pixels from this object are written to the depth buffer (default is On). If you’re drawng solid objects, leave this on.
    44.             //If you’re drawing semitransparent effects, switch to ZWrite Off. For more details read below.
    45.             ZWrite Off
    46.             //Off = Disables culling - all faces are drawn. Used for special effects.
    47.             Cull Off
    48.             //Set color channel writing mask. Writing ColorMask 0 turns off rendering to all color channels.
    49.             //Default mode is writing to all channels (RGBA), but for some special effects you might want to leave certain channels unmodified, or disable color writes completely.
    50.             ColorMask GBA
    51.             // push towards camera a bit, so that coord mismatch due to dynamic batching is not affecting us
    52.             Offset -0.02, 0
    53.             CGPROGRAM
    54.             #pragma vertex vert
    55.             #pragma fragment frag
    56.             #pragma target 2.0
    57.             float _ObjectId;
    58.             #define DRAW_COLOR float4(0, 0, 1, 1)
    59.             #include "SceneViewSelected.cginc"
    60.             ENDCG
    61.         }
    62.     }
    63.  
    64. }
    PostOutline.shader - Drag it to the "Post_Outline" slot on the camera that has the OutlinePosteffect.cs

    Code (CSharp):
    1.  
    2. Shader "Hidden/SceneViewSelected"
    3. {
    4.     Properties
    5.     {
    6.         _MainTex ("Main Texture", 2D) = "white" {}
    7.         _Cutoff ("Alpha cutoff", Range(0,1)) = 0.01
    8.     }
    9.     SubShader
    10.     {
    11.         CGINCLUDE
    12.         #include "UnityCG.cginc"
    13.         struct Input
    14.         {
    15.             float4 position : POSITION;
    16.             float2 uv : TEXCOORD0;
    17.             float4 projPos : TEXCOORD1;
    18.         };
    19.         struct Varying
    20.         {
    21.             float4 position : SV_POSITION;
    22.             float2 uv : TEXCOORD0;
    23.             float4 projPos : TEXCOORD1;
    24.         };
    25.         Varying vertex(Input input)
    26.         {
    27.             Varying output;
    28.             output.position = mul(UNITY_MATRIX_MVP, input.position);
    29.             output.uv = input.uv;
    30.             output.projPos = ComputeScreenPos(output.position);
    31.             return output;
    32.         }
    33.         ENDCG
    34.      
    35.         Tags { "RenderType"="Opaque" }
    36.          // #0: separable blur pass, either horizontal or vertical
    37.         Pass
    38.         {
    39.             ZTest Always
    40.             Cull Off
    41.             ZWrite Off
    42.          
    43.             CGPROGRAM
    44.             #pragma vertex vertex
    45.             #pragma fragment fragment
    46.             #pragma target 2.0
    47.             #include "UnityCG.cginc"
    48.             float2 _BlurDirection = float2(1,0);
    49.             sampler2D _MainTex;
    50.             float4 _MainTex_TexelSize;
    51.             // 9-tap Gaussian kernel, that blurs green & blue channels,
    52.             // keeps red & alpha intact.
    53.             static const half4 kCurveWeights[9] = {
    54.                 half4(0,0.0204001988,0.0204001988,0),
    55.                 half4(0,0.0577929595,0.0577929595,0),
    56.                 half4(0,0.1215916882,0.1215916882,0),
    57.                 half4(0,0.1899858519,0.1899858519,0),
    58.                 half4(1,0.2204586031,0.2204586031,1),
    59.                 half4(0,0.1899858519,0.1899858519,0),
    60.                 half4(0,0.1215916882,0.1215916882,0),
    61.                 half4(0,0.0577929595,0.0577929595,0),
    62.                 half4(0,0.0204001988,0.0204001988,0)
    63.             };
    64.             half4 fragment(Varying i) : SV_Target
    65.             {
    66.                 float2 step = _MainTex_TexelSize.xy * _BlurDirection;
    67.                 float2 uv = i.uv - step * 4;
    68.                 half4 col = 0;
    69.                 for (int tap = 0; tap < 9; ++tap)
    70.                 {
    71.                     col += tex2D(_MainTex, uv) * kCurveWeights[tap];
    72.                     uv += step;
    73.                 }
    74.      
    75.                 return col;
    76.             }
    77.             ENDCG
    78.         }
    79.         // #1: final postprocessing pass
    80.         Pass
    81.         {
    82.             ZTest Always
    83.             Cull Off
    84.             ZWrite Off
    85.             Blend SrcAlpha OneMinusSrcAlpha
    86.  
    87.             CGPROGRAM
    88.             #pragma vertex vertex
    89.             #pragma fragment fragment
    90.             #pragma target 2.0
    91.             #include "UnityCG.cginc"
    92.  
    93.             sampler2D _MainTex;
    94.             float4 _MainTex_TexelSize;
    95.             half4 fragment(Varying i) : SV_Target
    96.             {
    97.                 half4 col = tex2D(_MainTex, i.uv.xy);
    98.                 float saturateFac = 10;
    99.      
    100.                 float alpha = saturate((col.b - col.r) * saturateFac);
    101.  
    102.                 half4 outline = half4(1, 0, 0, alpha);
    103.  
    104.                 return outline;
    105.             }
    106.             ENDCG
    107.         }
    108.     }
    109.  
    110. }
    SceneViewSelected.cginc - Paste this code in a text editor and save the file in your project as "SceneViewSelected.cginc"

    Code (CSharp):
    1. #ifndef DRAW_COLOR
    2. #define DRAW_COLOR 1
    3. #endif
    4.  
    5. #include "UnityCG.cginc"
    6.  
    7. sampler2D _MainTex;
    8. float4 _MainTex_ST;
    9. float _DoClip = 0;
    10. fixed _Cutoff = 1.0;
    11.  
    12. struct appdata_t
    13. {
    14.     float4 vertex   : POSITION;
    15.     float2 texcoord : TEXCOORD0;
    16. };
    17.  
    18. struct v2f
    19. {
    20.     float4 vertex        : SV_POSITION;
    21.     float2 texcoord      : TEXCOORD0;
    22. };
    23.  
    24. v2f vert (appdata_t IN)
    25. {
    26.     v2f OUT;
    27.     OUT.vertex = UnityObjectToClipPos(IN.vertex);
    28.     OUT.texcoord = TRANSFORM_TEX(IN.texcoord, _MainTex);
    29.     return OUT;
    30. }
    31.  
    32. fixed4 frag (v2f IN) : SV_Target
    33. {
    34.     if (_DoClip)
    35.     {
    36.         fixed4 col = tex2D( _MainTex, IN.texcoord);
    37.         clip(col.a - _Cutoff);
    38.     }
    39.     return DRAW_COLOR;
    40. }
    41.  
     
  11. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    230
    I'm very near to a deadline at work, I don't have much time to help you but you should create an UnityPackage, it will be much more easy for me or someone else to have a fast check of what you have done.

    As far as I understand, you want to have an Outline rendering when your mesh is behind another mesh.

    I did something similar yesterday on a personal project but it was not an ouline (just changing color):

    IMG_19022017_212923.png

    Please ignore the minecraft textures used for my test...

    The walls are not sprites but meshes generated via a Geometry Shader with ZWrite on
    In this usage the character is a sprite shader with a second pass doing only this:

    Code (CSharp):
    1.      
    2. Pass
    3.         {
    4.             Name "FORWARDOCC"
    5.             Tags
    6.             {
    7.                 "Queue" = "Transparent"
    8.                 "IgnoreProjector" = "True"
    9.                 "RenderType" = "TransparentCutout"
    10.                 "PreviewType" = "Plane"
    11.                 "CanUseSpriteAtlas" = "True"
    12.             }
    13.          
    14.             Cull Off
    15.             Lighting Off
    16.             ZWrite Off
    17.             ZTest Greater
    18.             Blend One OneMinusSrcAlpha
    19.  
    20.             CGPROGRAM
    21.             #pragma vertex vert
    22.             #pragma fragment frag
    23.             #pragma multi_compile _ PIXELSNAP_ON
    24.             #include "UnityCG.cginc"
    25.  
    26.             struct appdata_t
    27.             {
    28.                 float4 vertex   : POSITION;
    29.                 float4 color    : COLOR;
    30.                 float2 texcoord : TEXCOORD0;
    31.             };
    32.  
    33.             struct v2f
    34.             {
    35.                 float4 vertex   : SV_POSITION;
    36.                 fixed4 color    : COLOR;
    37.                 half2 texcoord  : TEXCOORD0;
    38.             };
    39.  
    40.             fixed4 _Color;
    41.             fixed4 _OccludedColor;
    42.             sampler2D _MainTex;
    43.  
    44.  
    45.             v2f vert( appdata_t IN )
    46.             {
    47.                 v2f OUT;
    48.                 OUT.vertex = mul( UNITY_MATRIX_MVP, IN.vertex );
    49.                 OUT.texcoord = IN.texcoord;
    50.                 OUT.color = IN.color * _Color;
    51.                 #ifdef PIXELSNAP_ON
    52.                 OUT.vertex = UnityPixelSnap( OUT.vertex );
    53.                 #endif
    54.  
    55.                 return OUT;
    56.             }
    57.             fixed4 frag( v2f IN ) : SV_Target
    58.             {
    59.                 fixed4 c = tex2D( _MainTex, IN.texcoord );
    60.                 clip( c.a - .5 );
    61.                 return _OccludedColor;
    62.             }
    63.             ENDCG
    64.         }
    Basically what did the trick was this:

    Code (CSharp):
    1.          
    2.             ZWrite Off
    3.             ZTest Greater
    4.             Blend One OneMinusSrcAlpha
    [EDIT]
    Your problem here is the fact that the outline is a PostEffect and not the shader of the object itself.
    I don't know if there is a reasonable trick to achieve this though since your depth buffer only give you the depth in screen-space.

    An outline per object may be a better solution ?
     
    Last edited: Feb 21, 2017
  12. KristoferBoman

    KristoferBoman

    Joined:
    Feb 16, 2016
    Posts:
    58
    The outline is rendering when the mesh is behind another mesh, just as i want it. The problem is that i want to change the saturation or alpha on the outline when that happends (Just like in the editor). In order for me to do that this part needs to work

    // 1. render selected objects into a mask buffer, with different colors for visible vs occluded ones (using existing Z buffer for testing)

    But the second camera that is rendering the mask does not use the "main" cameras depthbuffer for the ZTest, thats why it fails, it always passes the ZTest so no different colors in the mask. I've read numerous other posts about similair problems and found that this should force the mask camera to use the same depth

    Code (CSharp):
    1.  _maskCamera.SetTargetBuffers(_maskRT.colorBuffer, source.depthBuffer);
    But i cant get that to work either :/

    I will prepare a unitypackage so that anyone can easaly test it.

    Thanks
     
  13. TristanCms

    TristanCms

    Joined:
    Mar 17, 2017
    Posts:
    28
    You did not send any package. Were you finally able to recreate the editor effect ?
     
    Polff likes this.
  14. ChristmasEve

    ChristmasEve

    Joined:
    Apr 21, 2015
    Posts:
    30
    I don't get what you guys are doing. I'm trying to get a red outline around a selected object just like you see in the Unity editor. I want it to work regardless of how many materials (or which shaders) an object uses (just like the editor successfully does). I have looked at Kristopher's code. I don't care about saturation or alpha at all. I just want to get an outline. I see nowhere in the script where you give it the object(s) you want outlined. Is it supposed to just do things that are hidden behind something? What if I want the outline around just one object in my MMO? And I do want the outline to be culled by walls, etc.
    I actually thought I got it working at one point when I had the player paused but I had selected my object by accident and Unity had displayed the outline. DANG IT... I WANT that! :)
     
  15. lejean

    lejean

    Joined:
    Jul 4, 2013
    Posts:
    207
    Ye, I tried the above 4 scripts too but there seems to be some more setup required.

    You need to add a Outline layer to the layers cause it gets called in OutlinePosteffect. I don't know where to assign it too tho, the meshes I presume?

    The maskcamera is disabled when I run playmode and I just see a black screen.
    In the editor the meshes that contain the shader are just not visible to the camera either.
     
  16. Jick87

    Jick87

    Joined:
    Oct 21, 2015
    Posts:
    124
    @KristoferBoman I just tried this out too and can't seem to get it working.. Similar issues as others have said.
     
  17. Ciryus

    Ciryus

    Joined:
    Sep 17, 2012
    Posts:
    33
    To answer the last 3 posts you guys must place the objects you want to outline into a Layer named "Outline", you will have to create it via the editor.
     
    richardkettlewell likes this.
  18. Jick87

    Jick87

    Joined:
    Oct 21, 2015
    Posts:
    124
    Yeah, I had done that but it still didn't work for me...
     
  19. Ciryus

    Ciryus

    Joined:
    Sep 17, 2012
    Posts:
    33
    Yeah actually it does'nt work out of the box: you have to change the OutlinePostEffect.cs this way:


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class OutlinePosteffect : MonoBehaviour
    5. {
    6.     Camera _mainCamera;
    7.     Camera _maskCamera;
    8.     RenderTexture _maskRT;
    9.     RenderTexture _blurRT;
    10.  
    11.     public Shader Post_Outline;
    12.     public Shader DrawSimple;
    13.     public Material _postMaterial;
    14.  
    15.     void Awake()
    16.     {
    17.         _blurRT = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.Default);
    18.         _maskRT = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.Default);
    19.  
    20.         _mainCamera = GetComponent<Camera>();
    21.  
    22.         _maskCamera = new GameObject("MaskCamera").AddComponent<Camera>();
    23.         _maskCamera.enabled = false;
    24.  
    25.         _postMaterial = new Material(Post_Outline);
    26.     }
    27.     void OnRenderImage(RenderTexture source, RenderTexture destination)
    28.     {
    29.         _maskCamera.CopyFrom(_mainCamera);
    30.         _maskCamera.backgroundColor = Color.black;
    31.         _maskCamera.clearFlags = CameraClearFlags.Nothing;
    32.  
    33.         _maskCamera.cullingMask = 1 << LayerMask.NameToLayer("Outline");
    34.  
    35.         RenderTexture activeRT = RenderTexture.active;
    36.         RenderTexture.active = _maskRT;
    37.  
    38.         GL.Clear(true, true, Color.clear);
    39.  
    40.         RenderTexture.active = activeRT;
    41.  
    42.         // 1. render selected objects into a mask buffer, with different colors for visible vs occluded ones (using existing Z buffer for testing)
    43.  
    44.         _maskCamera.targetTexture = _maskRT;
    45.         //_maskCamera.SetTargetBuffers(_maskRT.colorBuffer, source.depthBuffer);
    46.         _maskCamera.RenderWithShader(DrawSimple, "");
    47.         // 1. End
    48.  
    49.         // 2. blur the mask information in two separable passes, keeping the mask channels
    50.         _postMaterial.SetVector("_BlurDirection", new Vector2(0, 1));//Vertical
    51.         Graphics.Blit(_maskRT, _blurRT, _postMaterial, 0);
    52.         _postMaterial.SetVector("_BlurDirection", new Vector2(1, 0));//Vertical
    53.         Graphics.Blit(_blurRT, _maskRT, _postMaterial, 0);
    54.         // 2. End
    55.  
    56.         // 3.blend outline over existing scene image.blurred information &mask channels allow computing distance to selected
    57.         // This is the #1: final postprocessing pass in PostOutline.shader. Right now i just substract mask channel(col.r) from blurred channel(col.b) to get the outline
    58.         Graphics.Blit(source, destination);
    59.         Graphics.Blit(_maskRT, destination, _postMaterial, 0);
    60.  
    61.         _maskRT.DiscardContents();
    62.         _blurRT.DiscardContents();
    63.     }
    64. }
    Kristofer forgot to Blit the source image to the destination so it did not render correctly
     
  20. Jick87

    Jick87

    Joined:
    Oct 21, 2015
    Posts:
    124
    Hmm... I'm guessing his code is changed in some way to not work exactly like the editor outline? With your code I am actually able to see the objects but, the background is pure black (no skybox or such), and I can only see the slightest hint of an outline color on the edges, not a bold outline like the editor outline.

    I have attached the bare-minimum of a test project to show what I'm now getting. So, it seems it's getting there, but not quite fully there yet.

    I am even trying to use the unmodified version from this post, but it seems that one just makes the entire screen pink. :p

    Thanks for your help! :)
     

    Attached Files:

  21. winunity

    winunity

    Joined:
    Jun 16, 2015
    Posts:
    1

    Thank you for sharing. After looking at the code you provided, I found that Pass 1 of Post_Outline.Shader didn't execute. Then I changed the third step pass in OutlinePostEffect.cs to 1, and finally realized the effect. I hope you can see this little problem.
     
    asdzxcv777 and Jick87 like this.
  22. astrogee

    astrogee

    Joined:
    Feb 4, 2018
    Posts:
    7
    Thank you everyone who participated in this thread. I've been struggling with creating an outline that would work with any mesh - this thread finally solved that. I went ahead and created a git repo with the result.

    https://github.com/westmark/unity-mesh-outline
     
    xammurapi88 likes this.
  23. Rockylars

    Rockylars

    Joined:
    Dec 5, 2017
    Posts:
    1
    I know im probably asking for much, but is there a way to make the outline be a perfect recreation with the scene one?

    I kinda need it for my game..



    Yes, these are 6 objects, its a special shape that can be turned into a lot of other cube shapes, including this full cube, but the outline will only show the.. well, outline.

    Another solution would probably be mapping a glowline i guess, but that's gonna take me ages to finish for all the objects.
     
    Last edited: May 1, 2018
  24. mcurtiss

    mcurtiss

    Joined:
    Nov 29, 2012
    Posts:
    18
    For all you guys having issues, if you strip out example code without understanding what that code was doing, its going to be difficult to get it working...

    Here is a github repo that implements the shader provided by Unity: https://github.com/michaelcurtiss/UnityOutlineFX

    Comparison : (left is game camera outline, right is Unity's editor outline)

     
    Marrt, ChristmasEve, lrpenn and 2 others like this.
  25. KenjiJU

    KenjiJU

    Joined:
    Dec 31, 2012
    Posts:
    7
    This is excellent.. thank you so much! I've been wanting this for 10 years.
     
  26. theoAstucemedia

    theoAstucemedia

    Joined:
    Jul 24, 2018
    Posts:
    2
    I've tried your mesh outline as well (this one seemed more appropriate for me as I'm trying to apply this outline to a mesh) but unfortunately I didn't manage to make it work either (and I followed the steps you indicated, add the script to the Camera and the shaders to the script) but nothing renders on my screen... Would you know why?
     
  27. theoAstucemedia

    theoAstucemedia

    Joined:
    Jul 24, 2018
    Posts:
    2
    I've been trying to get the same result as you (left side of the screen) but I could not find the right combination of parameters. Could you show in the Inspector what kind of Buffer Draw Event you are using? I've tried them all with different combinations of Downsample and Blur Size but I haven't found the right combo to obtain the outline from the left image.

    PS: I looked at the test scene provided in the github repo but it did not give me the same outline either.
     
  28. mcurtiss

    mcurtiss

    Joined:
    Nov 29, 2012
    Posts:
    18
    It would help if you defined precisely what you are not able to achieve. Is the outline too thick? too thin?

    I just opened the repo and everything is working as intended in the example scene. Perhaps you are trying to get rid of the fill value, in which case you need to change the opacity (alpha) of the outline color on the script that is attached to the camera.
     
    Last edited: Aug 12, 2018
  29. Ekzalphantoss

    Ekzalphantoss

    Joined:
    Sep 27, 2016
    Posts:
    10
    The shader doesn't work well when the Camera is set to Orthographic - it places the shading of overlapping objects at the wrong places (more precisely it produces an upside-down result which looks very weird for complex shapes so maybe that's why theoAstucemedia couldn't describe the problem)

    P.S. Also, having MSAA enabled on any of the cameras in the scene results in the shader becoming lightblue with alpha set to 1, regardless of the settings of the camera that has the script

    P.P.S. This worked for me
     
    Last edited: Sep 5, 2018
  30. lrpenn

    lrpenn

    Joined:
    Sep 30, 2016
    Posts:
    1
    @mcurtiss thank you for the code. I am trying to use it in my project but am getting the following error:

    "unity dimensions of color surface does not match dimensions of depth surface"

    The mesh is being created by code, not sure if that's the problem?
     
    Last edited: Nov 6, 2018
  31. Vadol

    Vadol

    Joined:
    May 28, 2016
    Posts:
    4
    @mcurtiss @Ciryus Sadly, westmark's code isn't working with deferred lighting rendering mode/deferred cameras. I don't know why, But i think it's a shader issue.
     
  32. ChristmasEve

    ChristmasEve

    Joined:
    Apr 21, 2015
    Posts:
    30
    OMGoodness!! Thank you mcurtiss!! I can't believe it took me from May to February the next year to revisit this post! Your script/shader works perfectly!! Now I'm about to modify it so I can get red and/or white outlines on certain renderers in the same scene. This is awesome!! No need to mess with the shaders of my game objects. You're a life saver!

    EDIT: I got a little overly excited when I saw the red outline working so nicely. After looking at UnityOutlineFX.cs and attempting to update it so certain renderers can be outlined in white, I got completely confused. The material is set in a loop but also set outside the loop, globally. I have no idea how I would modify this script to handle red*and* white at the same time. Does anyone know? I'm trying to do a white outline for a user hovering over an object and red outline for a selected object. The user could be hovering over a second object while another object is selected.
     
    Last edited: Feb 20, 2019
  33. ChristmasEve

    ChristmasEve

    Joined:
    Apr 21, 2015
    Posts:
    30
    I ran into an issue with some of my renderers having multiple materials and only the first material was handled. For those of you interested, change it where it loops through your renderers (in UnityOulineFX.cs) to this:
    foreach (var render in collection)
    {
    for(int i=0;i<render.materials.Length;i++) _commandBuffer.DrawRenderer(render, _outlineMaterial, i, 1);
    for(int i=0;i<render.materials.Length;i++) _commandBuffer.DrawRenderer(render, _outlineMaterial, i, 0);
    }

    It will AUTOMATICALLY merge the meshes together so there'll just be ONE outline around the object.

    But, I'm getting that "Dimensions of color surface does not match dimensions of depth surface" error randomly. Someone else mentioned it a while back. If this happens it continues happening until I stop the player. However, when it doesn't happen, it'll never happen even if I run the player for a long time. I can't figure out why it happens only some of the times I run the editor player. Plus, I think it's always happening in the build because, when it happens in the editor, I notice coloring issues with the outlines and, though I can't see the errors in the build, I see that strange color issue every time I run the build. More specifically, a white outline color might look grey and thinner.
     
    Last edited: Feb 20, 2019
    guy_ likes this.
  34. ChristmasEve

    ChristmasEve

    Joined:
    Apr 21, 2015
    Posts:
    30
    This shader / command buffer code from mccurtiss simply does not work right in the standalone player (at least for 2018.2.16). Outlines do not show up above a certain point on the screen, regardless of the correct resolution for
    GetTemporaryRT's being set or not.
     
  35. ChristmasEve

    ChristmasEve

    Joined:
    Apr 21, 2015
    Posts:
    30
    Sorry about all the posts. If anyone runs into the same problem with this shader/ .cs code when running an actual standalone build, I figured out a way to get it working. The problem is with the code that detects if something is in between the outline and the camera. I don't understand it enough to fix it so I edited UnityOutline.shader to just simply get rid of the code that fades the outline when the object is behind a wall, etc.
    Comment out this block towards the end of the shader:
    // if (!inFront)
    // {
    // alpha *= 0.3;
    // }
    Obviously, your line will remain at full alpha, instead of 30%, when something is in the way but at least it works.