11
\$\begingroup\$

I want to achieve in Unity a see through effect like the one in these examples:

In my specific scenario there are a couple of requirements:

  • Sprites are using alpha blending, and sprites have transparent areas.
  • There are 2 kind of elements that occlude the character. One should create the silhouette effect, and the other one should behave like normal.

For occluding elements that create the silhouette I enable ZWrite, and disable it for elements that doesn't.

For the character I tried setting the queue of the shader to transparent+1, and added this pass:

Pass
{
    ZTest Greater
    Lighting Off
    Color [_Color]
}

And the effect works partially:

  • The silhouette is drawn all over the character, even the parts that are transparent. Transparent parts shouldn't create a silhouette.

  • The silhouette is created when the character is behind a sprite, even if that part of the sprite is transparent. Being behind a transparent part of the sprite shouldn't create the silhouette.

  • The character appears infront the rest of the elements, even if it is behind them. I guess this is because setting the queue to Transparent+1. But if I leave it as Transparent, the character is drawn in the correct order, but the silhouette is never seen.

I tried to follow these tips someone gave me, but I'm unable to get it to work:

1) Leave the pass that renders the sprites as is.

2) Add a pass that writes to the z-buffer, but has a shader that uses clip() to discard pixels based on alpha. You can't use the z-buffer to make soft z-tests without using MSAA and alpha-to coverage. The quality of that won't be great, but it's the best you can do. A faster alternative is a pattern or noise dither, or a good old fashioned threshold if your sprites all have fairly sharp edges.

3) Add third pass to occludable objects that draws the occlusion color using the z-test and make sure it's drawn as a final pass.

I'm kind of new to shaders, specially in Unity, and I just can't figure out how to make it work properly.

\$\endgroup\$
1
  • \$\begingroup\$ Your 2nd example simply looks a translucent green sprite placed over the character. You may want to get rid of that one and just leave the 2nd, if that's what you're looking for. \$\endgroup\$ Jun 8, 2017 at 2:44

1 Answer 1

1
\$\begingroup\$

Does this video cover the basics? It's an illustration of creating a few different styles of outline and silhouette from the shaders that people have already published.

https://www.youtube.com/watch?v=00qMZlacZQo

It's an example of using a shader published in the Unity Wiki to do pretty much what you're after. Content of the shader is below, although I think the outlining part of the shader may not be functioning as expected in U5.

Shader "Outlined/Silhouetted Diffuse" {
Properties {
    _Color ("Main Color", Color) = (.5,.5,.5,1)
    _OutlineColor ("Outline Color", Color) = (0,0,0,1)
    _Outline ("Outline width", Range (0.0, 0.03)) = .005
    _MainTex ("Base (RGB)", 2D) = "white" { }
}

CGINCLUDE
#include "UnityCG.cginc"

struct appdata {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
};

struct v2f {
    float4 pos : POSITION;
    float4 color : COLOR;
};

uniform float _Outline;
uniform float4 _OutlineColor;

v2f vert(appdata v) {
// just make a copy of incoming vertex data but scaled according to normal direction
    v2f o;
    o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

    float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
    float2 offset = TransformViewToProjection(norm.xy);

    o.pos.xy += offset * o.pos.z * _Outline;
    o.color = _OutlineColor;
    return o;
}
ENDCG

SubShader {
    Tags { "Queue" = "Transparent" }

    // note that a vertex shader is specified here but its using the one above
    Pass {
        Name "OUTLINE"
        Tags { "LightMode" = "Always" }
        Cull Off
        ZWrite Off
        ZTest Always
        ColorMask RGB // alpha not used

        // you can choose what kind of blending mode you want for the outline
        Blend SrcAlpha OneMinusSrcAlpha // Normal
        //Blend One One // Additive
        //Blend One OneMinusDstColor // Soft Additive
        //Blend DstColor Zero // Multiplicative
        //Blend DstColor SrcColor // 2x Multiplicative

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

half4 frag(v2f i) :COLOR {
    return i.color;
}
ENDCG
    }

    Pass {
        Name "BASE"
        ZWrite On
        ZTest LEqual
        Blend SrcAlpha OneMinusSrcAlpha
        Material {
            Diffuse [_Color]
            Ambient [_Color]
        }
        Lighting On
        SetTexture [_MainTex] {
            ConstantColor [_Color]
            Combine texture * constant
        }
        SetTexture [_MainTex] {
            Combine previous * primary DOUBLE
        }
    }
}

SubShader {
    Tags { "Queue" = "Transparent" }

    Pass {
        Name "OUTLINE"
        Tags { "LightMode" = "Always" }
        Cull Front
        ZWrite Off
        ZTest Always
        ColorMask RGB

        // you can choose what kind of blending mode you want for the outline
        Blend SrcAlpha OneMinusSrcAlpha // Normal
        //Blend One One // Additive
        //Blend One OneMinusDstColor // Soft Additive
        //Blend DstColor Zero // Multiplicative
        //Blend DstColor SrcColor // 2x Multiplicative

        CGPROGRAM
        #pragma vertex vert
        #pragma exclude_renderers gles xbox360 ps3
        ENDCG
        SetTexture [_MainTex] { combine primary }
    }

    Pass {
        Name "BASE"
        ZWrite On
        ZTest LEqual
        Blend SrcAlpha OneMinusSrcAlpha
        Material {
            Diffuse [_Color]
            Ambient [_Color]
        }
        Lighting On
        SetTexture [_MainTex] {
            ConstantColor [_Color]
            Combine texture * constant
        }
        SetTexture [_MainTex] {
            Combine previous * primary DOUBLE
        }
    }
}

Fallback "Diffuse"
}
\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .