How add support to alpha on this shader ?

I got this shader from asset store, but need to change it to support alpha, it is possible someone help me ?

Shader “Toon/Lit” {
Properties {
_Color (“Main Color”, Color) = (0.5,0.5,0.5,1)
_MainTex (“Base”, 2D) = “white” {}
_Ramp (“Ramp”, 2D) = “gray” {}
}

SubShader {
Tags { “RenderType”=“Opaque” }
LOD 200

CGPROGRAM
#pragma surface surf ToonRamp

sampler2D _Ramp;

// custom lighting function that uses a texture ramp based
// on angle between light direction and normal
#pragma lighting ToonRamp exclude_path:prepass
inline half4 LightingToonRamp (SurfaceOutput s, half3 lightDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif

half d = dot (s.Normal, lightDir) * 0.5 + 0.5;
half3 ramp = tex2D (_Ramp, float2(d,d)).rgb;

half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
c.a = 0;
return c;
}

sampler2D _MainTex;
float4 _Color;

struct Input {
float2 uv_MainTex : TEXCOORD0;
};

void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG

}

Fallback “Diffuse”
}

Give this a try

Shader "Toon/Lit"
{
    Properties
    {
        _Color ("Main Color", Color) = (0.5,0.5,0.5,1)
        _MainTex ("Base", 2D) = "white" {}
        _Ramp ("Ramp", 2D) = "gray" {}
        _Alpha ("Alpha", range(0.0, 1.0)) = 1.0
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Transparent"
            "Queue" = "Transparent"
        }
        LOD 200

        CGPROGRAM
            #pragma surface surf ToonRamp alpha:fade

            // Input Properties
            uniform float _Alpha;
            uniform float4 _Color;
            uniform sampler2D _Ramp;
            uniform sampler2D _MainTex;

            // Input Structs
            struct Input
            {
                float2 uv_MainTex : TEXCOORD0;
            };

            // Lighting function
            inline half4 LightingToonRamp (SurfaceOutput s, half3 lightDir, half atten)
            {
                #ifndef USING_DIRECTIONAL_LIGHT
                lightDir = normalize(lightDir);
                #endif

                half d = dot (s.Normal, lightDir) * 0.5 + 0.5;
                half3 ramp = tex2D (_Ramp, float2(d,d)).rgb;

                half4 c;
                c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
                c.a = _Alpha;
                return c;
            }

            // Surface shader
            void surf (Input IN, inout SurfaceOutput o)
            {
                o.Albedo = (tex2D(_MainTex, IN.uv_MainTex) * _Color).rgb;
            }
        ENDCG
    }
    Fallback "Diffuse"
}
1 Like

@ellioman

Really thanks for your time and for the change.
This shader work as I need, but it has one thing that I can change if is possible.

The pink cube works fine, the first requirement was draw the entire mesh with alpha support.

The selected mesh has a texture with alpha support (transparent), it is possible do this shader has support for alpha channel from 2D texture used on ‘base’ map ?

Most certainly :slight_smile:

See if this works for you.
I changed the Alpha slider to be a Alpha multiplier so you can have a little bit more control over the output.

Shader "Toon/Lit"
{
    Properties
    {
        _Color ("Main Color", Color) = (0.5,0.5,0.5,1)
        _MainTex ("Base", 2D) = "white" {}
        _Ramp ("Ramp", 2D) = "gray" {}
        _AlphaMultiplier("Alpha Multiplier", range(0.0, 10.0)) = 1.0
    }

    SubShader
    {
        Tags
        {
            "RenderType" = "Transparent"
            "Queue" = "Transparent"
        }
        LOD 200

        CGPROGRAM
            #pragma surface surf ToonRamp alpha:fade

            // Input Properties
            uniform float _AlphaMultiplier;
            uniform float4 _Color;
            uniform sampler2D _Ramp;
            uniform sampler2D _MainTex;

            // Input Structs
            struct Input
            {
                float2 uv_MainTex : TEXCOORD0;
            };

            inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
            {
                #ifndef USING_DIRECTIONAL_LIGHT
                lightDir = normalize(lightDir);
                #endif

                half d = dot (s.Normal, lightDir) * 0.5 + 0.5;
                half3 ramp = tex2D (_Ramp, float2(d,d)).rgb;

                half4 c;
                c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
                c.a = s.Alpha;
                return c;
            }

            void surf (Input IN, inout SurfaceOutput o)
            {
                fixed4 mainTexColor = tex2D(_MainTex, IN.uv_MainTex);
                o.Albedo = mainTexColor.rgb * _Color;
                o.Alpha = mainTexColor.a * _AlphaMultiplier;
            }
        ENDCG
    }

    Fallback "Diffuse"
}

@ellioman
Men, really, I don’t have words to express myself !
Thanks thanks thanks thanks !!!

Now I have two options for shader toon, alpha for the model or to mask texture, thanks again !

@ellioman during my tests I notice that alpha component (when 100%) not receive shadows, is possible change this (the first shader that you sent) ?

Nope.

You can search the forums if you want for the multitude of threads complaining about this. TLDR; It’s possible for transparent objects to receive shadows, but Unity doesn’t support it with their built in lighting systems.

The “easy fixes” are all bad hacks that have unintended consequences, like setting your shader to use “Queue”=“AlphaTest” and “RenderType”=“Opaque”. That will make them receive shadows, but stop objects behind them from receiving shadows and cause those transparent objects to render in the wrong order.

The only real solution, apart from completely replacing Unity’s lighting system, is to swap your materials from transparent to opaque once the alpha is at 100%.

@bgolus in this case, can I use something like renderer.material.SetFloat(“_Alpha”, f); (ok setFloat is only an example) for change it at runtime after detect collision ?

I don’t now if is possible (or there is a method to call on material that change the shader at runtime for this case), what you think ?

I mean you can do material.shader = theTransparentShader, but I wouldn’t necessarily suggest that. It is easier to have two separate materials and swap between them, one opaque and one transparent.

public Material transparentMaterial;
private Material originalMaterial;

void Start() {
  originalMaterial = renderer.sharedMaterial;
}

void OnEnable() {
  renderer.sharedMaterial = transparentMaterial;
}

void OnDisable() {
  renderer.sharedMaterial = originalMaterial;
}

This is the best option to keep batching working too. For something similar that I do on my current project I copy the material parameters of the original material onto the transparent material. I do this manually (just the _MainTex and a few other custom settings) since there aren’t any runtime functions for listing the variables.

The other option is do what the Standard shader does and toggle transparency using SetOverrideTag() along with the material queue, zwrite, and blend mode at runtime. That’s not necessarily any easier or better than shader or material swapping, but could let you use one shader for everything.


Thanks a lot for share your idea, I did something as you suggest, using the events to replace the material at runtime, works fine !

Thanks again for share ideas !

Any way you can add transparency for the main texture on this shader?

Shader "poiyomi/Rainbow"
{
  
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Texture", 2D) = "white" {}
        _Mask ("Red Mask", 2D) = "white" {}
        _Saturation("Saturation", Range(0.0, 2.0)) = 0.8
        _Luminosity("Luminosity", Range(0.0, 1.0)) = 0.5
        _RainbowEmission("Rainbow Emission", Range(0,5)) = 0
        _XWiggle("XWiggle", Range(0.0, 1000.0)) = 1.0
        _ZWiggle("ZWiggle", Range(0.0, 1000.0)) = 1.0
        _Spread("Spread", Range(0.1, 10.0)) = 3.8
        _Speed("Speed", Range(-10.0, 10.0)) = 2.4
        _TimeOffset("TimeOffset", Range(0.0, 6.28318531)) = 0.0
      
    }
    SubShader
    {
    Cull Off
    Pass
    {
        Tags {
        "LightMode"="ForwardBase"
        }

        ZWrite On

        CGPROGRAM

        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"
        #include "Lighting.cginc"
        #include "AutoLight.cginc"

        float4 _Color;
        sampler2D _MainTex;
        sampler2D _Mask;
        fixed _Saturation;
        fixed _Luminosity;
        half _Spread;
        half _Speed;
        half _TimeOffset;
        half _XWiggle;
        half _ZWiggle;
        half _RainbowEmission;



        inline fixed4 RGBtoHSL(fixed4 rgb)
        {
            fixed4 hsl = fixed4(0.0, 0.0, 0.0, rgb.w);
          
            fixed vMin = min(min(rgb.x, rgb.y), rgb.z);
            fixed vMax = max(max(rgb.x, rgb.y), rgb.z);
            fixed vDelta = vMax - vMin;
          
            hsl.z = (vMax + vMin) / 2.0;
          
            if (vDelta == 0.0)
            {
                hsl.x = hsl.y = 0.0;
            }
            else
            {
                if (hsl.z < 0.5) hsl.y = vDelta / (vMax + vMin);
                else hsl.y = vDelta / (2.0 - vMax - vMin);
              
                float rDelta = (((vMax - rgb.x) / 6.0) + (vDelta / 2.0)) / vDelta;
                float gDelta = (((vMax - rgb.y) / 6.0) + (vDelta / 2.0)) / vDelta;
                float bDelta = (((vMax - rgb.z) / 6.0) + (vDelta / 2.0)) / vDelta;
              
                if (rgb.x == vMax) hsl.x = bDelta - gDelta;
                else if (rgb.y == vMax) hsl.x = (1.0 / 3.0) + rDelta - bDelta;
                else if (rgb.z == vMax) hsl.x = (2.0 / 3.0) + gDelta - rDelta;
              
                if (hsl.x < 0.0) hsl.x += 1.0;
                if (hsl.x > 1.0) hsl.x -= 1.0;
            }
            return hsl;
        }

        inline fixed hueToRGB(float v1, float v2, float vH)
        {
            if (vH < 0.0) vH+= 1.0;
            if (vH > 1.0) vH -= 1.0;
            if ((6.0 * vH) < 1.0) return (v1 + (v2 - v1) * 6.0 * vH);
            if ((2.0 * vH) < 1.0) return (v2);
            if ((3.0 * vH) < 2.0) return (v1 + (v2 - v1) * ((2.0 / 3.0) - vH) * 6.0);
            return v1;
        }

        inline fixed4 HSLtoRGB(fixed4 hsl)
        {
            fixed4 rgb = fixed4(0.0, 0.0, 0.0, hsl.w);
      
            if (hsl.y == 0) {
                rgb.xyz = hsl.zzz;
            }
            else
            {
                float v1;
                float v2;
              
                if (hsl.z < 0.5) v2 = hsl.z * (1 + hsl.y);
                else v2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);
              
                v1 = 2.0 * hsl.z - v2;
              
                rgb.x = hueToRGB(v1, v2, hsl.x + (1.0 / 3.0));
                rgb.y = hueToRGB(v1, v2, hsl.x);
                rgb.z = hueToRGB(v1, v2, hsl.x - (1.0 / 3.0));
            }
            return rgb;
        }

        float3 LightingFunction( float3 normal )
        {
            return ShadeSH9(half4(normal, 1.0));
        }


        struct vertexInput
        {
            float4 vertex : POSITION;
            float4 texcoord0 : TEXCOORD0;
        };

        struct fragmentInput
        {
            float4 position : SV_POSITION;
            float4 texcoord0 : TEXCOORD0;
            fixed3 localPosition : TEXCOORD1;
        };

        fragmentInput vert(vertexInput i)
        {
            fragmentInput o;
            o.position = UnityObjectToClipPos(i.vertex);
            o.texcoord0 = i.texcoord0;
            o.localPosition = i.vertex.xyz; +fixed3(0.5, 0.5, 0.5);
            return o;
        }


        fixed4 frag(fragmentInput i) : SV_TARGET
        {


            half time = (_Time.y * _Speed + sin(sin(i.localPosition.x*_XWiggle) + sin(i.localPosition.z * _ZWiggle))) / _Spread;
            half timeWithOffset = time + _TimeOffset;
            fixed2 lPos = fixed2(i.localPosition.x / _Spread, i.localPosition.y / _Spread);
            fixed sine = sin(timeWithOffset);
            fixed cosine = cos(timeWithOffset);
            fixed hue = (-lPos.y) / 2.0;
            hue += time;
            while (hue < 0.0) hue += 1.0;
            while (hue > 1.0) hue -= 1.0;
            fixed4 hsl = fixed4(hue, _Saturation, _Luminosity, 1.0);
            //hsl *= tex2D(_Mask, i.texcoord0);
            //return HSLtoRGB(hsl);
            half mask = tex2D(_Mask, i.texcoord0).r;
            fixed4 col = lerp(tex2D(_MainTex, i.texcoord0) * _Color, HSLtoRGB(hsl), mask);

          
            float attenuation = LIGHT_ATTENUATION(i) / SHADOW_ATTENUATION(i);
            float3 FlatLighting = saturate((LightingFunction( float3(0,1,0) )+(_LightColor0.rgb*attenuation))) + mask*_RainbowEmission;
            col.rgb *= FlatLighting;

            return col;
        }
        ENDCG
    }
    }
        FallBack "Diffuse"
}