13
\$\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\$
  • \$\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\$ – Steve Harding Jun 8 '17 at 2:44
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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.