1
\$\begingroup\$

I'm trying to create a shader that will make the object invisible and then with a script a fade in/out effect between invisible and visible.

What I tried:

Shader "InsideVisible" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Color ("Color (RGBA)", Color) = (1, 1, 1, 1) // add _Color property
    }

    SubShader {
        Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha
        Cull front    // ADDED BY BERNIE, TO FLIP THE SURFACES
        LOD 100

        Pass {
            CGPROGRAM

                #pragma vertex vert alpha
                #pragma fragment frag alpha

                #include "UnityCG.cginc"

                struct appdata_t {
                    float4 vertex : POSITION;
                    float2 texcoord : TEXCOORD0;
                };

                struct v2f {
                    float4 vertex : SV_POSITION;
                    half2 texcoord : TEXCOORD0;
                };

                sampler2D _MainTex;
                float4 _MainTex_ST;
                float4 _Color;

                v2f vert (appdata_t v)
                {
                    v2f o;
                    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                    // ADDED BY BERNIE:
                    v.texcoord.x = 1 - v.texcoord.x;
                    o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                    return o;
                }

                fixed4 frag (v2f i) : SV_Target
                {
                    fixed4 col = tex2D(_MainTex, i.texcoord) * _Color; // multiply by _Color
                    return col;
                }
            ENDCG
        }
    }
}

I added this shader to my cube's material But it's not invisible at all not even close.

Invi

Sorry for the confusion.

The shader that I need is not to be based on distance from the camera but to be based on fade in/out effect so it will change between visible/invisible slowly depending on speed value.

Update:

This script seems to be working on Standard shader but for some reason it's not fading smooth it's fading a bit each time but not smooth flow. Why is that ?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InsideVisible : MonoBehaviour
{
    private void Start()
    {
        Coroutine _currentFade = StartCoroutine(FadeTo(0f, 10.0f));
    }

    IEnumerator FadeTo(float aValue, float aTime)
    {
        float alpha = transform.GetComponent<Renderer>().material.color.a;
        for (float t = 0.0f; t < 1.0f; t += Time.deltaTime / aTime)
        {
            Color newColor = new Color(1, 1, 1, Mathf.Lerp(alpha, aValue, t));
            transform.GetComponent<Renderer>().material.color = newColor;
            yield return null;
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ Your shader looks correct to me. You tried reducing the alpha of the Color parameter in the material inspector? \$\endgroup\$ – DMGregory Feb 11 '18 at 14:38
  • \$\begingroup\$ "depending on speed value" what is this speed value? Ca you elaborate please? \$\endgroup\$ – user100681 Feb 11 '18 at 22:25
  • \$\begingroup\$ @GabrieleVierti The speed of the fading in/out. Maybe I should say time and not speed. For example if the value is 1 it will take 1 second to fade in or out and if the value is 60 then 60 seconds. \$\endgroup\$ – Daniel Lip Feb 11 '18 at 22:30
  • \$\begingroup\$ @GabrieleVierti And the fading in/out should not be at once after 60 seconds for example, it should take fading in/out 60 seconds so you will see the cube slowly being invisible/visible. \$\endgroup\$ – Daniel Lip Feb 11 '18 at 22:32
2
\$\begingroup\$

I've verified that the shader in the question works just fine for creating transparency.

For the fade script, it looks like you want something more like this:

// Local storage for the material instance we're modifying.
Material _materialCopy;

IEnumerator FadeTo(float endAlpha, float durationSeconds)
{
    // Cache the material so we don't need to re-get it all the time,
    // and can clean it up when we're done with it.
    if(_materialCopy == null)
        _materialCopy = GetComponent<Renderer>().material;

    // Record the starting colour so we can preserve it.
    Color color = _materialCopy.color;
    // Record the starting alpha so we know where we're fading from.
    float startAlpha = color.a;

    for (float t = 0.0f; t < 1.0f; t += Time.deltaTime / durationSeconds)
    {
        // Lerp between start and end, not between current and end.
        color.a = Mathf.Lerp(startAlpha, endAlpha, t);
        _materialCopy.color = color;
        yield return null;
    }

    // Ensure we end exactly where we want, not off by any fraction.
    color.a = endAlpha;
    _materialCopy.color = color;
}

// Add a method to clean up our local material copy when we're done with it,
// so it doesn't clutter up memory until the next scene change.
void OnDestroy() 
{
    if(_materialCopy != null)
        Destroy(_materialCopy);
}
\$\endgroup\$
  • 1
    \$\begingroup\$ As an aside, the style of Lerp you were using, current = Lerp(current, goal, sharpness) is a legitimate way to create an exponential ease-out blend, when used deliberately for that goal. It's just commonly misused. \$\endgroup\$ – DMGregory Feb 11 '18 at 23:25
  • \$\begingroup\$ In the script I added Start and inside I did: StartCoroutine(FadeTo(0f, 3f)); And it's working fine. But now I want to make: StartCoroutine(FadeTo(1f, 3f)); The problem is how can I make with the shader in the question to create transparency ? Maybe with [ExecuteInEditMode] but the idea is to make the cube from transparency to visible. \$\endgroup\$ – Daniel Lip Feb 11 '18 at 23:53
  • 1
    \$\begingroup\$ The same thing you do in the script. Grab the exposed Color property in the material inspector (that coloured swatch next to the label "Color (RGBA)") and drag its alpha slider A down to zero. \$\endgroup\$ – DMGregory Feb 12 '18 at 0:01
  • 1
    \$\begingroup\$ before he edit his question I hadn't clue.so I update my answer.I believe my solution is better because code should be clean.this isn't task of c# and shader is better here :) \$\endgroup\$ – Seyed Morteza Kamali Feb 12 '18 at 7:10
  • 1
    \$\begingroup\$ That depends on what causes the fade / what purpose it serves. If it's a continuous background effect, I'd agree keeping it all shader-side is best. But if it's tightly linked to gameplay, say an invisibility power activating and deactivating, or possibly transitioning & reversing mid-fade, then we'll need a simple way for C# scripts to control when the fade starts/reverses, and a color parameter steered by a corourmtine accomplishes that quite robustly. \$\endgroup\$ – DMGregory Feb 12 '18 at 8:30
2
\$\begingroup\$

To Invisible the object you can use alpha value in your shader.

so instead of return col; try this return 0;

Fading Effect

fade

To fading your object you can use linear interpolation and clamping time by absolution function. try this abs(clamp(x,0,50)) on graphtoy.

absolution

try this shader and play the game.you can see fading effect :)

Shader "Smkgames/Fading"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _EndAlpha("EndAlpha",Float) = 0
        _Duration("Duration",Float) = 1
        [MaterialToggle]_Fade("Start Fading",Int) = 1
    }
    SubShader
    {
    Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"}
    Blend SrcAlpha OneMinusSrcAlpha Cull Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            float _EndAlpha,_Duration;
            int _Fade;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);

                float duration = abs(clamp(_Time.y,0,_Duration));//Clamp Time
                duration = duration/_Duration;// convert Time to number between 0 and 1
                float Alpha = lerp(col.a,_EndAlpha,duration);//linear interpolation between values
                float4 colFade = float4(col.rgb,Alpha);//linear interpolation Alpha
                float4 result = lerp(col,colFade,_Fade);//Check Condition
                return result;
            }
            ENDCG
        }
    }
}

here is C# code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class FadeEffect : MonoBehaviour {
    private Material mat;
    public Texture2D image;
    public float _EndAlpha,_Duration;
    public bool Fade = true;
    public Color color = Color.white;

    void Awake()
    {
        mat = GetComponent<MeshRenderer>().material;
        int fade = Fade ? 1 : 0;
        mat.SetInt("_Fade",fade);
        mat.SetFloat("_EndAlpha",_EndAlpha);
        mat.SetFloat("_Duration",_Duration);
        mat.SetTexture("_MainTex",image);
    }
}

Fading based on distance from the camera

I wrote a shader that you can determine range of fading effect and manage visibility:

record_2018_02_11_16_53_59_525

Shader "Smkgames/InsideVisible"
    {
      Properties
      {
        _MainTex ("Texture", 2D) = "white" {}
        [MaterialToggle]_Fade("Fade",int) = 1
        [MaterialToggle]_Visible("Visibility",int) = 1
        _MinVisDistance("MinDistance",Float) = 0
        _MaxVisDistance("MaxDistance",Float) = 20
        _Color("Color",Color) = (0,0,0,1)
      }
      SubShader
      {
          ZWrite Off
          Blend SrcAlpha OneMinusSrcAlpha
          Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"}
          LOD 100

        Pass
        {
          CGPROGRAM
          #pragma vertex vert
          #pragma fragment frag 
          // make fog work
          #pragma multi_compile_fog

          #include "UnityCG.cginc"

        struct v2f
      {
        half4 pos       : POSITION;
        fixed4 color : COLOR0;
        half2 uv        : TEXCOORD0;
      };


      sampler2D  _MainTex;
      half   _MinVisDistance,_MaxVisDistance;
      float4 _Color;
      int _Fade,_Visible;



      v2f vert(appdata_full v)
      {
        v2f o;

        o.pos = UnityObjectToClipPos(v.vertex);
        o.uv = v.texcoord.xy;
        o.color = v.color*_Color;

        half3 viewDirW = _WorldSpaceCameraPos - mul((half4x4)unity_ObjectToWorld, v.vertex);
        half viewDist = length(viewDirW);
        half falloff = saturate((viewDist - _MinVisDistance) / (_MaxVisDistance - _MinVisDistance));
        o.color.a *= (1.0f - falloff);
        return o;
      }


      fixed4 frag(v2f i) : COLOR
      {
        //I could declare condition here but in shader it's better to prevent if else statement so I use lerp
        //if (_Fade == 1){ color = tex2D(_MainTex, i.uv) * i.color }
        //else{color = tex2D(_MainTex, i.uv); }
        fixed4 color = tex2D(_MainTex, i.uv) * lerp(i.color,1,(1-_Fade))*_Visible;
      return color;
      }
          ENDCG
        }
      }
    }

also you can change these variables through code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class InsideVisible : MonoBehaviour {
    private Material mat;
    public Texture2D image;
    public bool _Fade = false,_Visible = true;
    public float MinVisDistance = 0,MaxVisDistance = 5;
    public Color color = Color.white;

    void Awake()
    {
        mat = GetComponent<MeshRenderer>().material;
    }
    void Update () {
        int fade = _Fade ? 1 : 0;
        int visible = _Visible ? 1 : 0;
        mat.SetInt("_Fade",fade);
        mat.SetInt("_Visible",visible);
        mat.SetFloat("_MinVisDistance",MinVisDistance);
        mat.SetFloat("_MaxVisDistance",MaxVisDistance);
        mat.SetTexture("_MainTex",image);
    }
}
\$\endgroup\$
  • \$\begingroup\$ Sorry for the confusion. The shader that I need is not to be based on distance from the camera but to be based on fade in/out effect so it will change between visible/invisible slowly depending on speed value. \$\endgroup\$ – Daniel Lip Feb 11 '18 at 22:12

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.