Unity Gradient Lerp 颜色渐变

最近改插件,本来如果有Gradient的lerp方法,改起来会非常方便。因为插件的更改入口是这个Gradient。运行时候手动调节inspector面板可以直接更改效果。那么此时只要在代码中更改Gradient即可。

但是找了几遍Color,ColorUtility,Gradient都没有Gradient的Lerp的方法。网上也没有。

此时的思路就变成了获取Gradient中的某个点的颜色值,用颜色值去lerp来代替当前的颜色,赋值到材质。代替比例接近1的时候,再直接更改Gradient。

调试到后面快要完成的时候发现,Gradient关联的部分太多了,单纯改材质的某个颜色达不到改变的效果,只有直接更改Gradient才可以,因为不知道他的材质里面还写了什么其他逻辑计算。

之前的思路需要改到插件内部逻辑的部分, 再做下去就会再改下去,会更不稳定, 为了不再出其他岔子。还是自己写个Gradient的Lerp的方法,从插件给到的入口去进行更改,免得面对太多内部逻辑,更改时候引起各种不正常情况导致更改困难。

一开始感觉难,了解了Gradient暴露的属性和方法之后,感觉还是简单的。
思路是将Gradient关键点的位置的值lerp过去即可。关键点取源Gradient或者目标Gradient都可以。结果是一样的。 取关键点较多的Gradient来lerp,因为这样才能正确映射到关键点多的Gradient,或者从关键点多的Gradient映射到关键点少的Gradient。

一般的做法是每个Lerp的过程都会产生一个Gradient。他是类,使用的次数过多会导致GC和内存上升。优化的方法是,设置序号,每个序号对应一个Gradient,更新的时候只更新这个Gradient的值。 使用方有自己的序号,用自己的序号去操作即可。

因为不论Gradient的Evaluate还是colorKeys,里面的存储的颜色的a都是1,所以透明度渐变只能通过位置接近的alphaKeys之间lerp,在两个Gradient的透明关键点位置大概一致的时候做到准确的透明度渐变。为了简化代码,要求一下两个gradient的透明关键点的位置和个数一致,还是可以的。

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

public class GradientUtil
{
    
    
    private static  Dictionary<int, Gradient> gradientDict = new Dictionary<int, Gradient>();
    
    static List<GradientColorKey> lerpGradientColorKeys = new List<GradientColorKey>();
    static List<GradientAlphaKey> lerpGradientAlphaKeys = new List<GradientAlphaKey>();
 
    
    /// <summary>
    /// 要求两个Gradient之间
    /// </summary>
    /// <param name="origin"></param>
    /// <param name="target"></param>
    /// <param name="lerpValue"></param>
    /// <param name="operedGradientID"></param>
    /// <param name="operGradientID"></param>
    /// <returns></returns>
     public static Gradient Lerp(Gradient origin, Gradient target, float lerpValue,  
         out int operedGradientID, int operGradientID = -1 )
     {
    
    
         Gradient gradient =  GetMatchGradient(out operedGradientID, operGradientID);
         
         GradientColorKey[] soruceGradientColorKeys = origin.colorKeys;
         GradientAlphaKey[] soruceGradientAlphaKeys = origin.alphaKeys;
         GradientAlphaKey[] targetGradientAlphaKeys = target.alphaKeys;

         if (soruceGradientAlphaKeys.Length != targetGradientAlphaKeys.Length)
         {
    
    
             Debug.LogError("渐变失败: 两个gradient的透明关键点的位置和个数需要一致 ");
             return gradient;
         }
         
         
         lerpGradientColorKeys.Clear();
         lerpGradientAlphaKeys.Clear();
         
         // Debug.LogError(" gradientDict.Count " + gradientDict.Count );
         
         GetColorKeys(target, origin, lerpValue, soruceGradientColorKeys);

         GetAlphaKeys(targetGradientAlphaKeys, lerpValue, soruceGradientAlphaKeys );
         
         gradient.SetKeys(lerpGradientColorKeys.ToArray(), lerpGradientAlphaKeys.ToArray());

         return gradient;
     }
     
     
     

     private static void GetAlphaKeys(GradientAlphaKey[] targetGradientAlphaKeys, float lerpValue,
         GradientAlphaKey[] sourceGradientAlphaKeys)
     {
    
    
         GradientAlphaKey targetGradientAlphaKey, sourceGradientAlphaKey;

         GradientAlphaKey lerpedGradientAlphaKey;
         for (int i = 0; i < sourceGradientAlphaKeys.Length; i++)
         {
    
    
             if (targetGradientAlphaKeys.Length > i )
             {
    
    
                 targetGradientAlphaKey = targetGradientAlphaKeys[i];
                 sourceGradientAlphaKey = sourceGradientAlphaKeys[i];

                 lerpedGradientAlphaKey = new GradientAlphaKey();
                 
                 lerpedGradientAlphaKey.alpha = Mathf.Lerp(sourceGradientAlphaKey.alpha,
                     targetGradientAlphaKey.alpha, lerpValue);
                 
                 lerpedGradientAlphaKey.time = targetGradientAlphaKey.time;
                 
                 lerpGradientAlphaKeys.Add(lerpedGradientAlphaKey);
             }
         }
          
     }

     private static void GetColorKeys(Gradient target, Gradient source, float lerpValue, 
         GradientColorKey[] soruceGradientColorKeys)
     {
    
    
         GradientColorKey[] targetGradientColorKeys = target.colorKeys;

         bool targetMoreColorKey = targetGradientColorKeys.Length > soruceGradientColorKeys.Length;
         
         int operCount = targetMoreColorKey
             ? targetGradientColorKeys.Length
             : soruceGradientColorKeys.Length;

         //分开两个for循环会比较容易维护而不是for循环里面进行分支
         if (targetMoreColorKey)
         {
    
    
             foreach (var targetColorKey in targetGradientColorKeys)
             {
    
    
                 Color colorInSource = source.Evaluate(targetColorKey.time);
                 
                 Color lerpedColor = Color.Lerp( colorInSource,  targetColorKey.color, lerpValue);

                 GradientColorKey gradientColorKey = new GradientColorKey();
                 
                 gradientColorKey.time = targetColorKey.time;
                 
                 gradientColorKey.color = lerpedColor;

                 lerpGradientColorKeys.Add(gradientColorKey);
             }
         }
         else
         {
    
    
             foreach (var sourceColorKey in soruceGradientColorKeys)
             {
    
    
                 Color colorInTarget = target.Evaluate(sourceColorKey.time);
                 Color lerpedColor = Color.Lerp(sourceColorKey.color, colorInTarget, lerpValue);

                 GradientColorKey gradientColorKey = new GradientColorKey();
                 gradientColorKey.time = sourceColorKey.time;
                 gradientColorKey.color = lerpedColor;

                 lerpGradientColorKeys.Add(gradientColorKey);
             }
         }
           
         
     }

     private static  Gradient GetMatchGradient(out int operedGradientID, int operGradientID)
     {
    
    
         Gradient gradient;
         if (operGradientID == -1)
         {
    
    
             gradient = new Gradient();
             operedGradientID = gradientDict.Count;
             gradientDict.Add(gradientDict.Count, gradient);
         }
         else
         {
    
    
             if (gradientDict.ContainsKey(operGradientID))
             {
    
    
                 operedGradientID = operGradientID;
                 gradient = gradientDict[operGradientID];
             }
             else
             {
    
    
                 Debug.LogError(" 不存在此id序号,重新创建Graident ");
                 gradient = new Gradient();
                 operedGradientID = gradientDict.Count;
                 gradientDict.Add(gradientDict.Count, gradient);
             }
         }

         return gradient;
     }
}

using System.Collections;
using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine;

public class TestGradientLerp : MonoBehaviour
{
    
    
    public Gradient _gradientA;
    public Gradient _gradientB;
    
    public float lerpSpeed;

    public Gradient lerpGradient;

    private float totalLerp;

    private int lerpGradientID = -1;
    
   
    
    // Start is called before the first frame update
    void Start()
    {
    
    
        totalLerp = 0;
        lerpSpeed =  lerpSpeed / 10 * Time.deltaTime;
    }

    // Update is called once per frame
    void Update()
    {
    
    
        totalLerp += lerpSpeed;

        lerpGradient = GradientUtil.Lerp(_gradientA, _gradientB, 
            totalLerp, out lerpGradientID, lerpGradientID);
        
        
        
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43149049/article/details/128320188