You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity ShaderLab中如何用lerp与deltaTime实现向目标值的动画过渡?

嘿,我来帮你搞定这两个问题,先说说你给出的示例代码为什么没法正常运行——原因很简单:currrentAlpha是着色器的内部局部变量,每帧执行surf函数时都会被重新初始化(默认值为0),所以每次都是从0开始lerp到targetAlpha,根本没法累积变化实现平滑过渡。下面是正确的实现方式:

1. 在Unity ShaderLab中用lerp和deltaTime实现向目标值的动画过渡

核心要点是必须维护一个可以跨帧保留的当前值,因为Shader本身没有持久化状态,通常有两种可靠的做法:

方法一:C#脚本驱动(推荐,可控性强)

在C#脚本里维护当前值,逐帧计算过渡后传递给Shader,这种方式灵活性最高:

Shader代码片段

Shader "Custom/BasicLerpTransition"
{
    Properties
    {
        _TargetValue ("Target Value", Range(0,1)) = 0.5
        _CurrentValue ("Current Value", Range(0,1)) = 0.5 // 由C#脚本更新
        _TransitionSpeed ("Transition Speed", Float) = 2.0
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            float _TargetValue;
            float _CurrentValue;

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

            fixed4 frag (v2f i) : SV_Target
            {
                // 直接使用C#传递的已完成过渡计算的值
                return fixed4(_CurrentValue, _CurrentValue, _CurrentValue, 1.0);
            }
            ENDCG
        }
    }
}

配套C#脚本(挂载在使用该Shader的物体上)

using UnityEngine;

public class LerpTransitionController : MonoBehaviour
{
    public Material targetMaterial;
    public float transitionSpeed = 2f;
    private float currentValue;

    void Start()
    {
        // 初始化当前值为Shader的初始TargetValue
        currentValue = targetMaterial.GetFloat("_TargetValue");
    }

    void Update()
    {
        float targetValue = targetMaterial.GetFloat("_TargetValue");
        // 使用lerp结合deltaTime实现平滑过渡,speed参数控制过渡快慢
        currentValue = Mathf.Lerp(currentValue, targetValue, Time.deltaTime * transitionSpeed);
        targetMaterial.SetFloat("_CurrentValue", currentValue);
    }
}

方法二:Shader内部基于时间的过渡(无需C#,但触发逻辑受限)

如果不想依赖C#,可以通过传递触发时间戳给Shader,结合Unity内置的_Time变量计算过渡进度:

Shader "Custom/ShaderInternalLerp"
{
    Properties
    {
        _TargetValue ("Target Value", Range(0,1)) = 0.5
        _StartTransitionTime ("Start Time (Seconds)", Float) = 0.0
        _TransitionDuration ("Duration (Seconds)", Float) = 1.0
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            float _TargetValue;
            float _StartTransitionTime;
            float _TransitionDuration;

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

            fixed4 frag (v2f i) : SV_Target
            {
                // 计算当前过渡进度,saturate确保值在0-1范围内
                float progress = saturate((_Time.y - _StartTransitionTime) / _TransitionDuration);
                // 从初始值(这里假设为0)lerp到目标值
                float currentValue = lerp(0, _TargetValue, progress);
                return fixed4(currentValue, currentValue, currentValue, 1.0);
            }
            ENDCG
        }
    }
}
2. 使用自定义标准表面着色器实现向目标值的动画过渡

标准表面着色器的逻辑类似,核心还是要维护跨帧的当前值,下面是针对Alpha过渡的完整修复实现:

完整Shader代码

Shader "Custom/AnimatedAlphaStandardSurface"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _TargetAlpha ("Target Alpha", Range(0,1)) = 1.0
        _CurrentAlpha ("Current Alpha", Range(0,1)) = 1.0 // 由C#脚本更新
        _TransitionSpeed ("Transition Speed", Float) = 2.0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 200

        CGPROGRAM
        // 声明为支持透明的标准表面着色器
        #pragma surface surf Standard alpha:fade

        #pragma target 3.0

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;
        float _TargetAlpha;
        float _CurrentAlpha;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = _Color;
            o.Albedo = c.rgb;
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            // 使用C#传递的已完成过渡的当前Alpha值
            o.Alpha = _CurrentAlpha;
        }
        ENDCG
    }
    FallBack "Standard"
}

配套C#脚本

using UnityEngine;

public class SurfaceShaderAlphaController : MonoBehaviour
{
    public Material surfaceMaterial;
    public float transitionSpeed = 2f;
    private float currentAlpha;

    void Start()
    {
        // 初始化当前Alpha为材质的初始值
        currentAlpha = surfaceMaterial.GetFloat("_CurrentAlpha");
    }

    void Update()
    {
        float targetAlpha = surfaceMaterial.GetFloat("_TargetAlpha");
        // 平滑过渡到目标Alpha
        currentAlpha = Mathf.Lerp(currentAlpha, targetAlpha, Time.deltaTime * transitionSpeed);
        surfaceMaterial.SetFloat("_CurrentAlpha", currentAlpha);
    }
}

内容的提问来源于stack exchange,提问作者Jethro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:14:20