Unity Gradient Lerp 颜色渐变

news2025/1/24 17:59:54

最近改插件,本来如果有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);
        
        
        
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/92064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么去图片水印?三招让你快速学会图片去水印

上大学的时候&#xff0c;老师让我们每人写一个关于“阅读”的主题报告。写这个主题报告的时候&#xff0c;我发现在网上找的图片素材大多带有水印&#xff0c;十分影响报告的展示效果。于是&#xff0c;我就上网找了一些怎么去图片水印的方法&#xff0c;对这些方法进行试验后…

Redis持久化(RDBAOF)

持久化简介&#xff1a; 不知道大家有没有遇见过&#xff0c;就是正工作的时候停电了&#xff0c;如果你用的是笔记本电脑还好&#xff0c;你有电池&#xff0c;但如果你用的是台式机呢&#xff0c;那恐怕就比较灾难了&#xff0c;假如你现在正在写一个比较重要的文档&#xf…

Java集合——Map

Map集合 Map用于保存具有映射关系的数据&#xff0c;以键值对的形式存储&#xff0c;支持通过key来访问value&#xff0c;因此key不能重复。 Map接口下主要有Hashtable、HashMap、LinkedHashMap、ConcurrentHashMap 四个主要的实现类&#xff0c;实现的基本原理类似&#xff0…

【图像处理】Hough变换检测直线与圆的原理

霍夫变换的基本原理 霍夫变换(Hough Transform)可以理解为图像处理中的一种特征提取技术&#xff0c;通过投票算法检测具有特定形状的物体。霍夫变换运用两个坐标空间之间的变换将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间中的一个点形成峰值&#xff0c;从而…

菜菜学paddle第七篇:目标检测的基本概念

一、什么是目标检测&#xff1f; 在前面的几篇中&#xff0c;我们学习了使用卷积神经网络进行图像分类&#xff0c;比如手写数字识别是用来识别0~9这十个数字。与图像分类处理单个物体的识别不同&#xff0c;目标检测它识别的不仅是物体&#xff0c;还是多个物体&#xff0c;…

[附源码]Python计算机毕业设计高校教务管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

Spring之IOC

IoC&#xff08;Inverse of Control:控制反转&#xff09;是一种设计思想&#xff0c;就是 将原本在程序中手动创建对象的控制权&#xff0c;交由Spring框架来管理。 IoC 在其他语言中也有应用&#xff0c;并非 Spirng 特有。 IoC 容器是 Spring 用来实现 IoC 的载体&#xff0…

服务攻防-应用协议RsyncSSHRDPFTP漏洞批扫口令猜解

目录 测试思路 &#xff08;一&#xff09;口令猜解——SSH&RDP&FTP Demo: &#xff08;二&#xff09;配置不当-未授权访问-Rsync 文件备份 尝试读取src文件 &#xff08;三&#xff09;协议漏洞-应用软件-FTP&Proftpd 搭建 &#xff08;四&#xff09;协议漏…

音视频- iOS使用metal渲染图像(一)

概要 本文主要总结一下Metal的基本使用&#xff0c;用来渲染拍照的到的图像&#xff0c;其中涉及到的有UIKit中的MTKView&#xff0c;Metal中负责渲染的几个类&#xff0c;使用MSL&#xff08;Metal Shading Language&#xff09;编写着色器&#xff0c;最终将图片渲染出来…

Python 绘制极坐标图(玫瑰花图优化)

风速的玫瑰花图可见 Matlab 绘制风速、风向统计玫瑰花图 在今天的这边博文,选用Python工具,绘制玫瑰花图,并对图进行优化。 example 1 【不规则宽度】N = 20 theta = np.linspace(0.0,2*np.pi,N,endpoint=False)

Jmeter(十五):jmeter场景的运行方式(GUI运行和命令行运行)命令行相关参数

jmeter场景的运行方式(GUI运行和命令行运行) 运行方式&#xff1a; GUI运行&#xff1a;通过图形界面方式运行&#xff0c;该运行方式的可视化界面及监听器动态展示 结果都比较消耗负载机资源&#xff0c;建议大并发时不用&#xff0c;一般进行脚本调试&#xff1b; 命令行运…

【PTA-训练day17】L2-029 特立独行的幸福 + L1-071 前世档案

L2-029 特立独行的幸福 - 递归/模拟 判断素数 PTA | 程序设计类实验辅助教学平台 思路&#xff1a; 第一层循环是边界循环 for(int il;i<r;i)枚举每一个i 第二层循环是判断这个i是不是幸福数st数组 判定 i 这个数在迭代过程中是否出现循环 如果出现循环及时跳出比如&…

【TypeScript系列】【一篇就够】TypeScript知识点总结(二)

12 面向对象简介 简而言之&#xff0c;面向对象就是程序之中所有的操作都需要通过对象来完成。 举例来说&#xff0c; 操作浏览器要使用windows对象&#xff1b;操作网页要使用document对象&#xff1b;操作控制台要使用console对象。一切操作都要通过对象&#xff0c;也就是…

nacos--扩展--03--系统参数

nacos–扩展–03–系统参数 1、Nacos Server 配置参数位置&#xff1a;{nacos.home}/conf/application.properties里注意&#xff1a;如果参数名后标注了(-D)的&#xff0c;则表示是 JVM 的参数&#xff0c;需要在{nacos.home}/bin/startup.sh里进行相应的设置。 案例&#xf…

测试用例等级怎么划分?别再傻傻的一脸懵逼

我们都知道测试工程师最基本的能力便是编写测试用例&#xff0c;可是看似简单的用例&#xff0c;后面其实蕴含这个很多人忽略的细节&#xff0c;今天就来说测试里面所蕴含的很多细节。 很多时候不只是测试和测试用例息息相关&#xff0c;开发&#xff0c;产品也有的时候对于测试…

C/C++程序的断点调试 - CodeBlocks

本文以CodeBlocks为例&#xff0c;简述C/C程序断点调试的基本方法和过程。其它的IDE环境&#xff0c;大同小异。 本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载&#xff0c;但需要注明原作者"海洋饼干叔 叔"&#xff1b;本文不允许…

单链表翻转-链表篇

leetcode206单链表的翻转 题目&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出…

如何指定标签在页面中显示的位置

如何指定标签在页面中显示的位置 在HTML页面设计中常常需要调整标签&#xff08;元素&#xff09;的位置&#xff0c;那么&#xff0c;如何指定标签在页面中显示的位置呢&#xff1f; 使用标签的align属性指定标签在页面中显示的位置&#xff0c;如align"left|right|cen…

02加锁源码分析-ReentrantReadWriteLock原理-AQS-并发编程(Java)

文章目录3.1 加锁3.1.1 读锁加锁3.1.1.1 tryAcquireShared()3.1.1.2 readerShouldBlock()3.1.1.3 fullTryAcquireShared()3.1.1.4 doAcquireShared()3.1.2 写锁加锁3.1.2.1 tryAcquire()3.1.2.2 acquireQueued()3.2 加锁示意图3.2.1 先写锁在读锁3.2.2 先读锁在写锁后记3.1 加锁…

全网惟一面向软件测试人员的Python基础教程-Python数据类型中有那些故事呢?

全网惟一面向软件测试人员的Python基础教程 起点&#xff1a;《python软件测试实战宝典》介绍 第一章 为什么软件测试人员要学习Python 第二章 学Python之前要搞懂的道理 第三章 你知道Python代码是怎样运行的吗&#xff1f; 第四章 Python数据类型中有那些故事呢&#xff1f;…