Unity取色器实现

  1. Unity编辑器的取色器很好用,但是如何在项目中使用,这就难倒了我,查查找找,终于完成了功能。于是在这里简单记录一下。

一、简单介绍

在这里插入图片描述

演示

如上所示,一个简单的取色功能,加上一个反向定位取色板功能

二、原理

首先通过一个色环图片,获取到色环上的基础颜色,再通过分辨率,对内部色盘进行HSV转化,最后通过内部色盘获取最终颜色

三、实现

1、取色

  1. 通过鼠标的点击、拖拽更新色环所需要的颜色
	public void OnPointerDown(PointerEventData eventData)
    {
        CircleMove(eventData);
    }


    public void OnDrag(PointerEventData eventData)
    {
        CircleMove(eventData);
    }
     public void CircleMove(PointerEventData eventData)
    {

        //计算选色环的位置
        //Vector2 o = new Vector2(Screen.width / 1920f * m_ColorWheel.rectTransform.rect.width / 2, Screen.height / 1080f * m_ColorWheel.rectTransform.rect.height / 2);
        Vector2 o = new Vector2(m_ColorWheel.rectTransform.rect.width / 2, m_ColorWheel.rectTransform.rect.height / 2);
        float r = m_ColorWheel.rectTransform.rect.width / 2 - m_SelectorWheel.rect.width / 2;

        //鼠标位置 - 圆形位置 = 圆心指向鼠标位置的向量
        Vector3 mousepos = transform.parent.InverseTransformPoint(eventData.position) -
                           transform.parent.InverseTransformPoint(transform.position + (Vector3)o);
        Vector3 rightPos = transform.parent.InverseTransformVector(m_ColorWheel.rectTransform.right);

        o = new Vector2(m_ColorWheel.rectTransform.rect.width / 2, m_ColorWheel.rectTransform.rect.height / 2);
        angle = VectorAngle(mousepos, rightPos);
        newV2.x = o.x + r * Mathf.Cos(angle * Mathf.Deg2Rad);
        newV2.y = o.y + r * Mathf.Sin(angle * Mathf.Deg2Rad);
        m_SelectorWheel.localPosition = newV2;

        //获取调色板图片
        Texture2D tex = m_ColorWheel.sprite.texture;
        //1.计算选色环在Image上的位置占比 (0~1)
        //2.通过位置占比,映射获取到要获取的贴图像素位置
        int x = (int)(m_SelectorWheel.localPosition.x / m_ColorWheel.rectTransform.rect.width * tex.width);
        int y = (int)(m_SelectorWheel.localPosition.y / m_ColorWheel.rectTransform.rect.height * tex.height);
        //通过Texture2D.GetPixel这个方法来获取该位置下的像素的颜色值
        Color color = tex.GetPixel(x,y);        RGBToHSV(color);
        UpdateSaturation(currentColorHSV);
        m_SubColorSelector.UpdateColor(eventData);
        
    }
    float VectorAngle(Vector2 from, Vector2 to)
    {
        float angle;
        Vector3 cross=Vector3.Cross(from, to);
        angle = Vector2.Angle(from, to);
        return cross.z > 0 ? -angle : angle;
    }
  1. 通过色环的颜色转化成HSV
    private void UpdateSaturation(Vector4 hsv)
    {
        for (int y = 0; y < piexlHeight; y++)
        {
            for (int x = 0; x < piexlWidth; x++)
            {
                Color pixColor = GetSaturation(hsv, x / piexlWidth, y / piexlHeight);
                saturationTexture2D.SetPixel(x, y, pixColor);
            }
        }

        saturationTexture2D.Apply();
        m_ColorSaturation.texture = saturationTexture2D;
    }
    private Color GetSaturation(Vector4 hsv, float x, float y)
    {
        Vector4 saturationHSV = hsv;
        saturationHSV.y = x;
        saturationHSV.z = y;
        saturationHSV.w = 1;
        return HSVToRGB(saturationHSV);
    }
    private Color HSVToRGB(Vector4 hsv)
    {
        Color color = Color.HSVToRGB(hsv.x, hsv.y, hsv.z);
        color.a = hsv.w;
        return color;
    }
  1. 通过鼠标的点击、拖拽更新内部色盘最终选择出来的颜色
	public void OnPointerDown(PointerEventData eventData)
    {
        OnDrag(eventData);
    }
    

    public void OnDrag(PointerEventData eventData)
    {

        //需要将背景调色板的中心点改为左下角(0,0)
        //PointerEventData.position返回的是当前指针的位置,左下角为原点(0,0),右上角(屏幕宽,屏幕高),根据分辨率来算
        Vector3 selectorWheelPos = transform.InverseTransformPoint(eventData.position);
        
        selectorWheelPos.x = Mathf.Clamp(selectorWheelPos.x,0,m_ColorPickPanel.rectTransform.rect.width - 1);
        selectorWheelPos.y = Mathf.Clamp(selectorWheelPos.y,0,m_ColorPickPanel.rectTransform.rect.height - 1);
        m_SelectorWheel.localPosition = selectorWheelPos;

        //获取调色板图片
        Texture2D tex = (Texture2D)m_ColorPickPanel.texture;
        //获取鼠标(smallIcon)在调色板上的x,y轴上的比例
        float xtemp = m_SelectorWheel.localPosition.x / m_ColorPickPanel.rectTransform.rect.width;
        float ytemp = m_SelectorWheel.localPosition.y / m_ColorPickPanel.rectTransform.rect.height;
        
        //设置圆圈颜色分类
        if (ytemp <= 0.5f || xtemp >= 0.5f) m_SelectorWheelImage.color = Color.white;
        else m_SelectorWheelImage.color = Color.black;
        
        //通过鼠标在调色板的位置比例,获取鼠标在调色板上的具体(X,Y)坐标
        int x = (int)(xtemp * tex.width);
        int y = (int)(ytemp * tex.height);

        //通过Texture2D.GetPixel这个方法来获取该位置下的像素的颜色值
        Color color = tex.GetPixel(x, y);
        //设置颜色
        FinalColor = color;
        ColorPlate.color = FinalColor;
    }

2、根据颜色设置取色器

  1. 根据颜色计算HSV
Color.RGBToHSV(color, out float hue, out float saturation, out float brightness);
  1. 计算色环的选取位置
 		//获取内部色盘的最亮色
        RGBToHSV(Color.HSVToRGB(hue, 1, 1));
        //计算色环小圈的位置
        Vector2 o = new Vector2(m_ColorWheel.rectTransform.rect.width / 2, m_ColorWheel.rectTransform.rect.height / 2);
        float r = m_ColorWheel.rectTransform.rect.width / 2 - m_SelectorWheel.rect.width / 2;
        newV2.x = o.x + r * Mathf.Cos(hue*360 * Mathf.Deg2Rad);
        newV2.y = o.y + r * Mathf.Sin(hue*360 * Mathf.Deg2Rad);
        m_SelectorWheel.localPosition = newV2;
  1. 更新内部色盘图片
    private void UpdateSaturation(Vector4 hsv)
    {
        for (int y = 0; y < piexlHeight; y++)
        {
            for (int x = 0; x < piexlWidth; x++)
            {
                Color pixColor = GetSaturation(hsv, x / piexlWidth, y / piexlHeight);
                saturationTexture2D.SetPixel(x, y, pixColor);
            }
        }

        saturationTexture2D.Apply();
        m_ColorSaturation.texture = saturationTexture2D;
    }
  1. 计算内部色盘选取位置

        //计算内部色盘小圈位置
        m_SubColorSelector.m_SelectorWheel.transform.localPosition = new Vector2(saturation * m_SubColorSelector.RectTransform.rect.width, brightness * m_SubColorSelector.RectTransform.rect.height);

四、完整代码

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

public class ColorSelector : MonoBehaviour,  IPointerDownHandler, IDragHandler
{

    public SubColorSelector m_SubColorSelector;
    //色环
    public Image m_ColorWheel;
    //调色板
    public RawImage m_ColorSaturation;
    //选择图标
    public RectTransform m_SelectorWheel;
    
    //调色板图片
    private Texture2D saturationTexture2D;

    private readonly float piexlWidth = 256.0f;
    private readonly float piexlHeight = 256.0f;
    private readonly float huePiexWidth = 50.0f;
    //当前HSV
    private Vector4 currentColorHSV = new Vector4(0, 1, 1, 1);
    

    void Awake()
    {
        saturationTexture2D = new Texture2D((int)piexlWidth, (int)piexlHeight);
        m_ColorSaturation.texture = saturationTexture2D;
    }
    
    void Start()
    {
        Init();
    }
    public void SetSelectorWheel(Image Ima)
    {
        //计算传入颜色的HSV
        Color.RGBToHSV(Ima.color, out float hue, out float saturation, out float brightness);
        //获取内部色盘的最亮色
        RGBToHSV(Color.HSVToRGB(hue, 1, 1));
        //计算色环小圈的位置
        Vector2 o = new Vector2(m_ColorWheel.rectTransform.rect.width / 2, m_ColorWheel.rectTransform.rect.height / 2);
        float r = m_ColorWheel.rectTransform.rect.width / 2 - m_SelectorWheel.rect.width / 2;
        newV2.x = o.x + r * Mathf.Cos(hue*360 * Mathf.Deg2Rad);
        newV2.y = o.y + r * Mathf.Sin(hue*360 * Mathf.Deg2Rad);
        m_SelectorWheel.localPosition = newV2;
        //更新内部色盘图片
        UpdateSaturation(currentColorHSV);
        //计算内部色盘小圈位置
        m_SubColorSelector.m_SelectorWheel.transform.localPosition = new Vector2(saturation * m_SubColorSelector.RectTrans.rect.width, brightness * m_SubColorSelector.RectTrans.rect.height);

        m_SubColorSelector.ColorPlate.color = Ima.color;
    }
    public void Init()
    {
        //计算选色环的位置
        Vector2 o = new Vector2(m_ColorWheel.rectTransform.rect.width / 2, m_ColorWheel.rectTransform.rect.height / 2);
        float r = m_ColorWheel.rectTransform.rect.width / 2 - m_SelectorWheel.rect.width / 2;

        //鼠标位置 - 圆形位置 = 圆心指向鼠标位置的向量
        Vector3 mousepos = transform.parent.InverseTransformPoint(m_SelectorWheel.position) -
                           transform.parent.InverseTransformPoint(transform.position + (Vector3)o);
        Vector3 rightPos = transform.parent.InverseTransformVector(m_ColorWheel.rectTransform.right);

        angle = VectorAngle(mousepos, rightPos);
        newV2.x = o.x + r * Mathf.Cos(angle * Mathf.Deg2Rad);
        newV2.y = o.y + r * Mathf.Sin(angle * Mathf.Deg2Rad);
        m_SelectorWheel.localPosition = newV2;

        //获取调色板图片
        Texture2D tex = m_ColorWheel.sprite.texture;
        //1.计算选色环在Image上的位置占比 (0~1)
        //2.通过位置占比,映射获取到要获取的贴图像素位置
        int x = (int)(m_SelectorWheel.localPosition.x / m_ColorWheel.rectTransform.rect.width * tex.width);
        int y = (int)(m_SelectorWheel.localPosition.y / m_ColorWheel.rectTransform.rect.height * tex.height);
        //通过Texture2D.GetPixel这个方法来获取该位置下的像素的颜色值
        Color color = tex.GetPixel(x, y);
        RGBToHSV(color);
        UpdateSaturation(currentColorHSV);
        m_SubColorSelector.UpdateColor();
    }

    /// <summary>
    /// 更新调色板
    /// </summary>
    /// <param name="hsv"></param>
    private void UpdateSaturation(Vector4 hsv)
    {
        for (int y = 0; y < piexlHeight; y++)
        {
            for (int x = 0; x < piexlWidth; x++)
            {
                Color pixColor = GetSaturation(hsv, x / piexlWidth, y / piexlHeight);
                saturationTexture2D.SetPixel(x, y, pixColor);
            }
        }

        saturationTexture2D.Apply();
        m_ColorSaturation.texture = saturationTexture2D;
    }

    /// <summary>
    /// 根据设置分辨率转化HSV
    /// </summary>
    /// <param name="hsv"></param>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    private Color GetSaturation(Vector4 hsv, float x, float y)
    {
        Vector4 saturationHSV = hsv;
        saturationHSV.y = x;
        saturationHSV.z = y;
        saturationHSV.w = 1;
        return HSVToRGB(saturationHSV);
    }

    private Color HSVToRGB(Vector4 hsv)
    {
        Color color = Color.HSVToRGB(hsv.x, hsv.y, hsv.z);
        color.a = hsv.w;
        return color;
    }

    private void RGBToHSV(Color color)
    {
        Color.RGBToHSV(color, out currentColorHSV.x, out currentColorHSV.y, out currentColorHSV.z);
        // 更新调色板的位置
    }

    

    public void OnPointerDown(PointerEventData eventData)
    {
        CircleMove(eventData);
    }


    public void OnDrag(PointerEventData eventData)
    {
        CircleMove(eventData);
    }

    public float angle;
    private Vector2 newV2 =  Vector2.zero;
    
    public void CircleMove(PointerEventData eventData)
    {

        //计算选色环的位置
        //Vector2 o = new Vector2(Screen.width / 1920f * m_ColorWheel.rectTransform.rect.width / 2, Screen.height / 1080f * m_ColorWheel.rectTransform.rect.height / 2);
        Vector2 o = new Vector2(m_ColorWheel.rectTransform.rect.width / 2, m_ColorWheel.rectTransform.rect.height / 2);
        float r = m_ColorWheel.rectTransform.rect.width / 2 - m_SelectorWheel.rect.width / 2;

        //鼠标位置 - 圆形位置 = 圆心指向鼠标位置的向量
        Vector3 mousepos = transform.parent.InverseTransformPoint(eventData.position) -
                           transform.parent.InverseTransformPoint(transform.position + (Vector3)o);
        Vector3 rightPos = transform.parent.InverseTransformVector(m_ColorWheel.rectTransform.right);

        o = new Vector2(m_ColorWheel.rectTransform.rect.width / 2, m_ColorWheel.rectTransform.rect.height / 2);
        angle = VectorAngle(mousepos, rightPos);
        newV2.x = o.x + r * Mathf.Cos(angle * Mathf.Deg2Rad);
        newV2.y = o.y + r * Mathf.Sin(angle * Mathf.Deg2Rad);
        m_SelectorWheel.localPosition = newV2;

        //获取调色板图片
        Texture2D tex = m_ColorWheel.sprite.texture;
        //1.计算选色环在Image上的位置占比 (0~1)
        //2.通过位置占比,映射获取到要获取的贴图像素位置
        int x = (int)(m_SelectorWheel.localPosition.x / m_ColorWheel.rectTransform.rect.width * tex.width);
        int y = (int)(m_SelectorWheel.localPosition.y / m_ColorWheel.rectTransform.rect.height * tex.height);
        //通过Texture2D.GetPixel这个方法来获取该位置下的像素的颜色值
        //Debug.Log(m_SelectorWheel.localPosition + "!!!!!!!!!!!!!!!!");
        Color color = tex.GetPixel(x,y);
        //Debug.Log("+++++++图片中当前像素的颜色值:" + color);
        RGBToHSV(color);
        UpdateSaturation(currentColorHSV);
        m_SubColorSelector.UpdateColor(eventData);
        
    }
    
    float VectorAngle(Vector2 from, Vector2 to)
    {
        float angle;
        Vector3 cross=Vector3.Cross(from, to);
        angle = Vector2.Angle(from, to);
        return cross.z > 0 ? -angle : angle;
    }
}


using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class SubColorSelector : MonoBehaviour,  IPointerDownHandler, IDragHandler
{

    //显示板
    public Image ColorPlate;
    //最终颜色
    public Color FinalColor;
    //调色板
    public RawImage m_ColorPickPanel;
    //选择图标
    public RectTransform m_SelectorWheel;
    public RectTransform RectTrans;

    private RawImage m_SelectorWheelImage;
    //记录之前的位置
    Vector3 oldposition;


    void Awake()
    {
        RectTrans = transform as RectTransform;
        oldposition = m_SelectorWheel.position;
        m_SelectorWheelImage = m_SelectorWheel.GetComponent<RawImage>();
    }

    

    public void OnPointerDown(PointerEventData eventData)
    {
        OnDrag(eventData);
    }
    

    public void OnDrag(PointerEventData eventData)
    {

        //需要将背景调色板的中心点改为左下角(0,0)
        //PointerEventData.position返回的是当前指针的位置,左下角为原点(0,0),右上角(屏幕宽,屏幕高),根据分辨率来算
        Vector3 selectorWheelPos = transform.InverseTransformPoint(eventData.position);
        
        selectorWheelPos.x = Mathf.Clamp(selectorWheelPos.x,0,m_ColorPickPanel.rectTransform.rect.width - 1);
        selectorWheelPos.y = Mathf.Clamp(selectorWheelPos.y,0,m_ColorPickPanel.rectTransform.rect.height - 1);
        m_SelectorWheel.localPosition = selectorWheelPos;

        //获取调色板图片
        Texture2D tex = (Texture2D)m_ColorPickPanel.texture;
        //获取鼠标(smallIcon)在调色板上的x,y轴上的比例
        float xtemp = m_SelectorWheel.localPosition.x / m_ColorPickPanel.rectTransform.rect.width;
        float ytemp = m_SelectorWheel.localPosition.y / m_ColorPickPanel.rectTransform.rect.height;
        
        //设置圆圈颜色分类
        if (ytemp <= 0.5f || xtemp >= 0.5f) m_SelectorWheelImage.color = Color.white;
        else m_SelectorWheelImage.color = Color.black;
        
        //通过鼠标在调色板的位置比例,获取鼠标在调色板上的具体(X,Y)坐标
        int x = (int)(xtemp * tex.width);
        int y = (int)(ytemp * tex.height);

        //通过Texture2D.GetPixel这个方法来获取该位置下的像素的颜色值
        Color color = tex.GetPixel(x, y);
        //设置颜色
        FinalColor = color;
        ColorPlate.color = FinalColor;
    }

    /// <summary>
    /// 更新颜色
    /// </summary>
    /// <param name="eventData"></param>
    public void UpdateColor(PointerEventData eventData = null)
    {
        //获取调色板图片
        Texture2D tex = (Texture2D)m_ColorPickPanel.texture;
        float xtemp = m_SelectorWheel.localPosition.x / m_ColorPickPanel.rectTransform.rect.width;
        float ytemp = m_SelectorWheel.localPosition.y / m_ColorPickPanel.rectTransform.rect.height;
        int x = (int)(xtemp * tex.width);
        int y = (int)(ytemp * tex.height);
        Color color = tex.GetPixel(x, y);
        FinalColor = color;
        ColorPlate.color = FinalColor;
    }
}

五、示例资源

后续更新

已更新
示例场景

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
首先,Unity是一款跨平台的游戏引擎,适用于多个平台,包括PC、手机、主机等。利用Unity游戏引擎,可以实现各种类型的游戏设计和开发。 Unity游戏设计与实现涉及到几个关键方面。首先,需要有一定的编程知识,理解基本的编程逻辑和语法。其次,需要具备一定的美术设计能力,包括对色彩、图形、布局等方面的理解和运用。另外,还需要了解游戏设计原理和用户体验,以便设计出富有趣味性和可玩性的游戏。 在Unity实现彩色版PDF下载功能,可以通过以下步骤进行: 1. 首先,在Unity中创建一个新的项目,并选择适当的模板,如2D或3D游戏。 2. 然后,导入相关的资源,如PDF文件和彩色版文档。 3. 在Unity的场景中创建一个UI界面,包括一个按钮用于触发下载功能。 4. 编写下载功能的代码。可以使用Unity的网络功能或外部资源库来实现文件下载的功能。 5. 设计界面的交互逻辑,当用户点击按钮时,触发下载功能。 6. 在下载完成后,将下载的PDF文件保存到指定的路径,并显示下载完成。 7. 最后,进行测试和调试,确保下载功能正常运行。 Unity游戏设计与实现需要综合运用多个技能和知识,包括编程、美术设计、游戏设计和用户体验等方面。通过充分利用Unity引擎的各种功能和资源,可以实现丰富多样的游戏设计和功能实现,包括彩色版PDF下载功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值