unity-game-engineshaderunity3d-2dtools

Unity3D Sprite ... but single sided?


Unity's excellent Sprites (Unity's excellent new sprites), among other worthy advantages, are in fact double-sided.

In a 2D or 3D use case, you can flip the little bastards around and still see them from behind - they are rendered from both sides.

I also love the unlit shader used on them (ie, Sprite-Default, not Sprite-Diffuse).

However, I have need for an old-fashioned single-sided Sprite.

Fortunately, you can freely download the source of the excellent shader used by Unity ... confusingly, you can't just open it in the Editor, but see here and thence here.

After considerable sustained effort involving inexpensive whisky, I made two (2) modifications to the shader.

  1. I changed the name in the first line of the file to "DefaultSingle" rather than "Default"

  2. I commented away the line Cull Off

(I then made a new Material, called it "Sprite Single Sided", set the shader to this new one, and on Sprites I replace the material slot with that new material.)

in fact, have I screwed-up anything in the shader by making this modification? Can one gaily comment out "Cull off" without causing further problems? Is there some gotchya in changing that usual material used by Sprite (you can't "see" it so I don't know). More broadly, is there a more correct way to achieve single-sided Sprite?

// file "Sprites-DefaultSingle.shader"
Shader "Sprites/DefaultSingle"
{
  Properties
  {
    [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    _Color ("Tint", Color) = (1,1,1,1)
    [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
  }

  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;

      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;

      fixed4 SampleSpriteTexture (float2 uv)
      {
        fixed4 color = tex2D (_MainTex, uv);

#if ETC1_EXTERNAL_ALPHA
        // get the color from an external texture ..
        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;
        c.rgb *= c.a;
        return c;
      }
    ENDCG
    }
  }
}

Solution

  • That won't cause any problems and is the correct way of doing things. If you want to be really explicit about it you could change the line to Cull Back instead of commenting it out, but back-face culling is defined as the default behaviour so just removing it is fine.