序
- Unity编辑器的取色器很好用,但是如何在项目中使用,这就难倒了我,查查找找,终于完成了功能。于是在这里简单记录一下。
一、简单介绍
演示
如上所示,一个简单的取色功能,加上一个反向定位取色板功能
二、原理
首先通过一个色环图片,获取到色环上的基础颜色,再通过分辨率,对内部色盘进行HSV转化,最后通过内部色盘获取最终颜色
三、实现
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;
}
- 通过色环的颜色转化成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;
}
- 通过鼠标的点击、拖拽更新内部色盘最终选择出来的颜色
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、根据颜色设置取色器
- 根据颜色计算HSV
Color.RGBToHSV(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;
- 更新内部色盘图片
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;
}
- 计算内部色盘选取位置
//计算内部色盘小圈位置
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;
}
}
五、示例资源
后续更新文章来源:https://www.toymoban.com/news/detail-775437.html
已更新
示例场景文章来源地址https://www.toymoban.com/news/detail-775437.html
到了这里,关于Unity取色器实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!