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

Unity中如何将运行时自定义颜色渐变应用到单个UI Image

Unity 运行时自定义渐变平滑显示在UI Image上的实现方法

问题场景

我正在Unity中使用颜色渐变功能,相关代码实现如下:

Gradient gradient = new Gradient();
GradientColorKey[] gck = new GradientColorKey[5];
float rgb = 255;

gck[0].color = new Color(65 / rgb, 105 / rgb, 255 / rgb); 
gck[0].time = 0f;
gck[1].color = new Color(135 / rgb, 206 / rgb, 250 / rgb);
gck[1].time = .25f;
gck[2].color = new Color(60 / rgb, 179 / rgb, 113 / rgb); 
gck[2].time = 0.50F;
gck[3].color = new Color(255 / rgb, 230 / rgb, 0);  
gck[3].time = 0.75F;
gck[4].color = new Color(180 / rgb, 0, 0); 
gck[4].time = 1f;

GradientAlphaKey[] alphaKey = new GradientAlphaKey[2];
alphaKey[0].alpha = 1.0f;
alphaKey[0].time = 0.0f;
alphaKey[1].alpha = 0.0f;
alphaKey[1].time = 1.0f;
gradient.SetKeys(gck, alphaKey);

上述代码中的渐变仅为示例,渐变固定包含5个颜色键,具体颜色值支持用户在运行时自定义修改。

当前通过5张分别设置单个颜色键对应纯色的图片拼接实现,效果为分块显示:
分块纯色显示效果

需要实现单张UI Image展示平滑渐变过渡效果,目标效果参考:
平滑渐变目标效果


可行实现方案

以下两种方案均支持运行时动态修改渐变键值、自动兼容自定义Alpha透明度过渡,按需选择即可:

方案1:自定义Image组件重写网格生成(性能最优,无额外内存开销)

直接继承UGUI的Image类,根据渐变的所有色键/Alpha键时间点生成对应网格顶点,顶点颜色直接采样Gradient赋值,由GPU完成段内线性插值,和Unity原生Gradient插值逻辑完全一致,顶点数量极少,性能消耗可以忽略。
代码可直接挂载使用:

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

public class UIGradientImage : Image
{
    private Gradient _runtimeGradient;
    // 0=水平从左到右 1=垂直从下到上,可自行扩展对角、径向等方向
    [SerializeField] private int _gradientDirection = 0;

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();
        if (_runtimeGradient == null)
        {
            base.OnPopulateMesh(vh);
            return;
        }

        Rect rect = rectTransform.rect;
        Vector2 pivotOffset = rectTransform.pivot;
        float rectW = rect.width;
        float rectH = rect.height;

        // 合并所有颜色键、Alpha键的时间点,避免插值偏差
        HashSet<float> timePoints = new HashSet<float>();
        foreach (var colorKey in _runtimeGradient.colorKeys) timePoints.Add(colorKey.time);
        foreach (var alphaKey in _runtimeGradient.alphaKeys) timePoints.Add(alphaKey.time);
        List<float> sortedTimes = new List<float>(timePoints);
        sortedTimes.Sort();

        // 按时间点生成顶点
        for (int i = 0; i < sortedTimes.Count; i++)
        {
            float t = sortedTimes[i];
            Color vertexColor = _runtimeGradient.Evaluate(t);
            
            if (_gradientDirection == 0) // 水平渐变
            {
                float x = (t - pivotOffset.x) * rectW;
                vh.AddVert(new Vector3(x, -pivotOffset.y * rectH, 0), vertexColor, new Vector2(t, 0));
                vh.AddVert(new Vector3(x, (1 - pivotOffset.y) * rectH, 0), vertexColor, new Vector2(t, 1));
            }
            else // 垂直渐变
            {
                float y = (t - pivotOffset.y) * rectH;
                vh.AddVert(new Vector3(-pivotOffset.x * rectW, y, 0), vertexColor, new Vector2(0, t));
                vh.AddVert(new Vector3((1 - pivotOffset.x) * rectW, y, 0), vertexColor, new Vector2(1, t));
            }

            // 相邻时间点组成矩形面
            if (i > 0)
            {
                int baseIdx = (i - 1) * 2;
                vh.AddTriangle(baseIdx, baseIdx + 1, baseIdx + 2);
                vh.AddTriangle(baseIdx + 1, baseIdx + 3, baseIdx + 2);
            }
        }
    }

    /// <summary>
    /// 运行时更新渐变后调用,刷新显示效果
    /// </summary>
    public void RefreshGradient(Gradient newGradient)
    {
        _runtimeGradient = newGradient;
        SetVerticesDirty();
    }
}

使用时将该脚本挂载到需要显示渐变的UI物体上,运行时用户修改完渐变参数后,调用RefreshGradient(你的渐变实例)即可立刻刷新显示。

方案2:运行时生成渐变纹理(兼容性最好,无需自定义组件逻辑)

如果不想重写UI组件,可以在每次渐变更新时生成一张1像素高、宽度256的2D纹理,逐像素采样Gradient颜色赋值后转为Sprite赋值给Image,Bilinear过滤会自动实现平滑过渡,256像素宽度足够保证人眼看不到颜色断层。
实现代码:

using UnityEngine;
using UnityEngine.UI;

public static class GradientTextureGenerator
{
    private const int GradientTexWidth = 256;
    private static Texture2D _cachedGradientTex;

    public static void ApplyGradientToImage(Image targetImg, Gradient gradient)
    {
        // 回收旧纹理避免内存泄漏
        if (_cachedGradientTex != null) Object.Destroy(_cachedGradientTex);
        
        _cachedGradientTex = new Texture2D(GradientTexWidth, 1, TextureFormat.RGBA32, false)
        {
            wrapMode = TextureWrapMode.Clamp,
            filterMode = FilterMode.Bilinear
        };

        for (int i = 0; i < GradientTexWidth; i++)
        {
            float t = i / (float)(GradientTexWidth - 1);
            _cachedGradientTex.SetPixel(i, 0, gradient.Evaluate(t));
        }
        _cachedGradientTex.Apply();

        targetImg.sprite = Sprite.Create(_cachedGradientTex, 
            new Rect(0, 0, GradientTexWidth, 1), 
            new Vector2(0.5f, 0.5f));
    }
}

渐变更新时直接调用GradientTextureGenerator.ApplyGradientToImage(目标Image组件, 渐变实例)即可。

两种方案都不需要额外美术资源,完全支持运行时动态修改色键、Alpha键参数,显示效果和原生渐变预览一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:09:09