【Unity】关于调色板的简单制作

1.调色板的主要组成

通常调色板主要基于HSV颜色空间实现,其中HSV(Hue, Saturation, Value)分别表示:

色相(Hue):表示色彩信息,即所处的光谱颜色的位置。该参数用一角度量来表示,取值范围为0°~360°,在Unity中的取值范围为0~1

饱和度(Saturation):取值范围为0.0~1.0。

灰度(Value):取值范围为0.0(黑色)~1.0(白色)。

HSV颜色空间模型,如下图所示:

一般HSV颜色空间的实现,如下图所示:

2.色相的实现

主要通过逐像素更改rawImage的颜色实现,代码如下

/// <summary>
    /// 初始化Texture
    /// </summary>
    private void HandleTextureColor()
    {
        tex2d = new Texture2D(TextureWdith, TextureHeight, TextureFormat.RGB24, true);
        List<Color> listColor = new List<Color>();
        for (int x = 0; x <= TextureWdith; x++)
        {
            for (int y = 0; y < TextureHeight; y++)
            {
                Color pixColor = Color.HSVToRGB((float)x / (float)TextureWdith, 1, 1);
                tex2d.SetPixel(x, y, pixColor);
            }
        }
        tex2d.Apply();
        rawImage.texture = tex2d;
        rawImage.texture.wrapMode = TextureWrapMode.Clamp;
    }

 通过Slider值获取对应的颜色,代码如下

    /// <summary>
    /// 获取颜色
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public Color GetColorBySliderValue(float value)
    {
        float clampValue = Mathf.Clamp(value, 0.001f, 0.999f);
        Color getColor = tex2d.GetPixel((int)((TextureWdith - 1) * clampValue), 0);
        return getColor;
    }

 整体脚本以及效果如下:

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

public class ColorHue : MonoBehaviour
{
    private RawImage rawImage;
    private Texture2D tex2d;

    private int TextureWdith = 270;
    private int TextureHeight = 8;

    private void Awake()
    {
        rawImage = gameObject.GetComponent<RawImage>();
        HandleTextureColor();
    }

    /// <summary>
    /// 初始化Texture
    /// </summary>
    private void HandleTextureColor()
    {
        tex2d = new Texture2D(TextureWdith, TextureHeight, TextureFormat.RGB24, true);
        List<Color> listColor = new List<Color>();
        for (int x = 0; x <= TextureWdith; x++)
        {
            for (int y = 0; y < TextureHeight; y++)
            {
                Color pixColor = Color.HSVToRGB((float)x / (float)TextureWdith, 1, 1);
                tex2d.SetPixel(x, y, pixColor);
            }
        }
        tex2d.Apply();
        rawImage.texture = tex2d;
        rawImage.texture.wrapMode = TextureWrapMode.Clamp;
    }

    /// <summary>
    /// 获取颜色
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public Color GetColorBySliderValue(float value)
    {
        float clampValue = Mathf.Clamp(value, 0.001f, 0.999f);
        Color getColor = tex2d.GetPixel((int)((TextureWdith - 1) * clampValue), 0);
        return getColor;
    }
}

 3.颜色板的实现

以色相选择红色为例,颜色板左上角应为白色,右上角为红色,底部为黑色,对应RGB数值如下图所示:

 颜色的生成依旧根据逐像素修改RawImage实现,首先计算texture顶端每一像素的颜色,以红色为例公式如下图:

而后根据texture顶端的每一像素,计算该像素所在列的所有像素,公式如下图所示:

代码如下所示:

       //设置板子的颜色
        public void SetColorPanel(Color endColor)
        {
            //计算texture最顶端各个像素点的颜色
            Color value = (endColor - Color.white) / (TexPixelLength - 1);
            for (int i = 0; i < TexPixelLength; i++)
            {
                arrayColor[i, TexPixelHeight - 1] = Color.white + value * i;
            }
            //根据texture最顶端各个像素的颜色,计算每列像素的颜色
            for (int i = 0; i < TexPixelLength; i++)
            {
                value = (arrayColor[i, TexPixelHeight - 1] - Color.black) / (TexPixelHeight - 1);
                for (int j = 0; j < TexPixelHeight; j++)
                {
                    arrayColor[i, j] = Color.black + value * j;
                }
            }

            List<Color> listColor = new List<Color>();
            for (int i = 0; i < TexPixelHeight; i++)
            {
                for (int j = 0; j < TexPixelLength; j++)
                {
                    listColor.Add(arrayColor[j, i]);
                }
            }
            Color[] CalcArray = listColor.ToArray();
            //给颜色板子填入颜色,并且应用
            tex2d.SetPixels(CalcArray);
            tex2d.Apply();
        }

 整体脚本如下:

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

namespace CSharp.UI.ColorBoard
{
    public class ColorBoard : MonoBehaviour, IPointerClickHandler, IDragHandler
    {
        //显示颜色的Texture
        private Texture2D tex2d;
        private RawImage rawImage;

        private int TexPixelLength = 256;
        private int TexPixelHeight = 256;

        public Slider sliderA;
        public ColorHue colorHSV;

        private Color[,] arrayColor;
        private RectTransform rectTrans;
        [Header("光标")]
        public RectTransform circleRect;

        public delegate void ColorChangeDelegate(Color color);
        public event ColorChangeDelegate OnColorChanged;

        private void Awake()
        {
            rawImage = GetComponent<RawImage>();
            rectTrans = GetComponent<RectTransform>();
            circleRect = transform.Find("光标").GetComponent<RectTransform>();

            TexPixelLength = (int)rectTrans.sizeDelta.x;
            TexPixelHeight = (int)rectTrans.sizeDelta.y;
            
            arrayColor = new Color[TexPixelLength, TexPixelHeight];
            tex2d = new Texture2D(TexPixelLength, TexPixelHeight, TextureFormat.RGB24, true);
            rawImage.texture = tex2d;
            rawImage.texture.wrapMode = TextureWrapMode.Clamp;
            //初始化为红色
            SetColorPanel(Color.red);
            
            sliderA.onValueChanged.AddListener(OnRGBValueChanged);
        }


        //颜色发生变化的监听
        private void OnRGBValueChanged(float value)
        {
            Color endColor = colorHSV.GetColorBySliderValue(value);
            SetColorPanel(endColor);
            var color = GetColorByPosition(circleRect.anchoredPosition);
            OnColorChanged?.Invoke(color);
        }

        //设置板子的颜色
        public void SetColorPanel(Color endColor)
        {
            //计算texture最顶端各个像素点的颜色
            Color value = (endColor - Color.white) / (TexPixelLength - 1);
            for (int i = 0; i < TexPixelLength; i++)
            {
                arrayColor[i, TexPixelHeight - 1] = Color.white + value * i;
            }
            //根据texture最顶端各个像素的颜色,计算每列像素的颜色
            for (int i = 0; i < TexPixelLength; i++)
            {
                value = (arrayColor[i, TexPixelHeight - 1] - Color.black) / (TexPixelHeight - 1);
                for (int j = 0; j < TexPixelHeight; j++)
                {
                    arrayColor[i, j] = Color.black + value * j;
                }
            }

            List<Color> listColor = new List<Color>();
            for (int i = 0; i < TexPixelHeight; i++)
            {
                for (int j = 0; j < TexPixelLength; j++)
                {
                    listColor.Add(arrayColor[j, i]);
                }
            }
            Color[] CalcArray = listColor.ToArray();
            //给颜色板子填入颜色,并且应用
            tex2d.SetPixels(CalcArray);
            tex2d.Apply();
        }


        /// <summary>
        /// 通过坐标获取颜色
        /// </summary>
        /// <param name="pos"></param>
        /// <returns></returns>
        public Color GetColorByPosition(Vector2 pos)
        {
            Texture2D tempTex2d = (Texture2D)rawImage.texture;
            Color getColor = tempTex2d.GetPixel((int)pos.x, (int)pos.y);
            return getColor;
        }

        /// <summary>
        /// 限制光标位置
        /// </summary>
        /// <param name="touchPos"></param>
        /// <returns></returns>
        public Vector2 GetClampPosition(Vector2 touchPos)
        {
            Vector2 vector2 = new Vector2(touchPos.x, touchPos.y);
            vector2.x = Mathf.Clamp(vector2.x, 0.001f, rectTrans.sizeDelta.x);
            vector2.y = Mathf.Clamp(vector2.y, 0.001f, rectTrans.sizeDelta.y);
            return vector2;
        }

        public void OnPointerClick(PointerEventData eventData)
        {
            Vector3 wordPos; 
            if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTrans, eventData.position, eventData.pressEventCamera, out wordPos))
                circleRect.position = wordPos;
            circleRect.anchoredPosition = GetClampPosition(circleRect.anchoredPosition);
            //获取当前光标位置的颜色
            var color = GetColorByPosition(circleRect.anchoredPosition);
            OnColorChanged?.Invoke(color);
        }

        public void OnDrag(PointerEventData eventData)
        {
            Vector3 wordPos;

            if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTrans, eventData.position, eventData.pressEventCamera, out wordPos))
                circleRect.position = wordPos;
            circleRect.anchoredPosition = GetClampPosition(circleRect.anchoredPosition);
            //获取当前光标位置的颜色
            var color = GetColorByPosition(circleRect.anchoredPosition);
            OnColorChanged?.Invoke(color);
        }
    }
}

 4.透明度以及颜色更改的实现

主要包括颜色更改事件的订阅,颜色透明度的更改,整体代码如下:

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

public class UIColorDemo : MonoBehaviour
{
    private Image curColorImage;

    private ColorBoard colorBoard;

    private Slider alphaSlider;

    private void Start()
    {
        curColorImage = transform.Find("Image").GetComponent<Image>();
        colorBoard = transform.Find("当前颜色板").GetComponent<ColorBoard>();
        alphaSlider = transform.Find("透明度").GetComponent<Slider>();

        curColorImage.color = Color.black;

        //订阅事件
        colorBoard.OnColorChanged += ChangeCurImageColor;
        alphaSlider.onValueChanged.AddListener(ChangeCurImageAlpha);

    }

    private void ChangeCurImageColor(Color color)
    {
        var rawColor = curColorImage.color;
        curColorImage.color = new Color(color.r, color.g, color.b, rawColor.a);
        //PortAndLineManager.Instance.lineMatColor = curColorImage.color;
    }

    private void ChangeCurImageAlpha(float value)
    {
        var rawColor = curColorImage.color;
        curColorImage.color = new Color(rawColor.r, rawColor.g, rawColor.b, value);
    }
}

 5.效果展示

整体效果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值