最近改插件,本来如果有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[] colorKeys = 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, lerpValue, colorKeys);
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, float lerpValue, GradientColorKey[] colorKeys)
{
foreach (var colorKey in colorKeys)
{
Color colorInTarget = target.Evaluate(colorKey.time);
Color lerpedColor = Color.Lerp(colorKey.color, colorInTarget, lerpValue);
GradientColorKey gradientColorKey = new GradientColorKey();
gradientColorKey.time = colorKey.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);
}
}