2

How can a Custom Standard Surface Shader be used to animate a value towards a target value?

For Example:

...
float targetAlpha; //Set by the property block, or a C# script
float currrentAlpha; //Used internally only.

void surf (Input IN, inout SurfaceOutputStandard o)
{
    currrentAlpha = lerp(currrentAlpha, targetAlpha, unity_DeltaTime.x);

    o.Alpha = currrentAlpha;
}

This code does not work but should demonstrate what the goal is: when targetAlpha is set, the shader will fade towards that value.

Jethro
  • 3,029
  • 3
  • 27
  • 56
  • 1
    I would have to dicker around with ShaderLab to see what I can do with builtin values, but it should be noted that `deltaTime` won't be correct. What you *can* do is set up a property value that you then modify from a `MonoBehavior` script. – Draco18s no longer trusts SE May 19 '18 at 21:10
  • 1
    https://forum.unity.com/threads/using-the-surf-function-to-lerp-a-value-by-deltatime.532216/#post-3502927 This helped me understand why my approach was incorrect – Jethro May 19 '18 at 22:26

2 Answers2

3

There are few ways this can be done. One of them is using built-in shader variables:

    Shader "Custom/Test" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _TargetAlpha ("TargetAlpha", Range(0, 1)) = 0.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows alpha:fade

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        half _Alpha;
        fixed4 _Color;
        half _TargetAlpha;


        void surf (Input IN, inout SurfaceOutputStandard o) 
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Alpha = lerp(o.Alpha, _TargetAlpha, clamp(_SinTime.w, 0, 1));
        }
        ENDCG
    }
    FallBack "Diffuse"
 }
Hamid Yusifli
  • 9,688
  • 2
  • 24
  • 48
  • 2
    `_SinTime` will cause the property to oscillate back and forth, which may not work for the asker's purposes, but it's a decent starting point. The problem is making sure it clamps in the desired manner (i.e. starts at 1 and stops at 0). – Draco18s no longer trusts SE May 20 '18 at 00:12
3

The shader in the answer above still works in Unity 2018.2. However, _SinTime oscillates between -1 and 1, while we want the range to be between 0 and 1. The code clamp(_SinTime.w, 0, 1) clamps onto the desired values, however the alpha stays at zero too long. So we need the absolute value, like so: abs(_SinTime.w).

The modified shader:

    Shader "Custom/Test" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _TargetAlpha ("TargetAlpha", Range(0, 1)) = 0.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows alpha:fade

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        half _Alpha;
        fixed4 _Color;
        half _TargetAlpha;


        void surf (Input IN, inout SurfaceOutputStandard o) 
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Alpha = lerp(o.Alpha, _TargetAlpha, abs(_SinTime.w));
        }
        ENDCG
    }
    FallBack "Diffuse"
 }
live627
  • 397
  • 4
  • 18