Unity 取色板

1、 简介

功能分区为四部分:

在这里,介绍一下颜色空间吧:

1.1 RGB

RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是运用最广的颜色系统之一。

1.2 HSV

HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。HSV颜色模型是指H、S、V三维颜色空间中的一个可见光子集,它包含某个颜色域的所有颜色。

每一种颜色都是由色相(Hue,简H),饱和度(Saturation,简S)和色明度(Value,简V)所表示的。这个模型中颜色的参数分别是:色调(H),饱和度(S),亮度(V)。

色调H参数表示色彩信息,即所处的光谱颜色的位置。该参数用一角度量来表示,取值范围为0°~360°。若从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,紫色为300°;

饱和度S:取值范围为0.0~1.0;

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

1.3 Hexadecimal

十六进制颜色对照表:https://www.ysdaima.com/tools/hexbiao

转换原理,可参见:https://blog.csdn.net/f_957995490/article/details/120727626

2、功能实现

2.1 Slider

背景图自己P了一张,然后Slider的value为h,s=1,v=1,算出色板右上角的颜色:

C# 复制代码
imageSliderXYBG.material.color = Color.HSVToRGB(1 - v, 1, 1);

2.2 SliderXY

2.2.1 渐变色

以Shader的方式实现,其中有个问题,算出来的颜色值需要转为liner

ShaderLab 复制代码
Shader "GradientXY"
{
    Properties
    {
        _Color("Color", Color) = (1,1,1,1)
    }

    SubShader
    {
        Tags 
        { 
            "RenderType" = "Transparent" 
            "Queue" = "Transparent"
            "IgnoreProjector" = "True" 
            "RenderPipeline" = "UniversalPipeline"
        }

        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode" = "UniversalForward" }

            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            Cull Off

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes
            {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
                half4  color : COLOR;
            };

            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                half4  color : COLOR;
                float3 positionWS : TEXCOORD1;
            };

            CBUFFER_START(UnityPerMaterial)
                half4 _Color;
            CBUFFER_END

            Varyings vert(Attributes v)
            {
                Varyings o;
                VertexPositionInputs vertexInput = GetVertexPositionInputs(v.positionOS.xyz);
                o.positionCS = vertexInput.positionCS;
                o.uv = v.uv;             
                o.color = v.color * _Color;
                o.positionWS = vertexInput.positionWS;
                return o;
            }

            half4 gamma2liner(half4 gamma)
            {
                return gamma * (gamma * (gamma * 0.305306011h + 0.682171111h) + 0.012522878h);
            }

            half4 frag(Varyings i) : SV_Target
            {
                half4 colorWhite = half4(1,1,1,1);
                half4 colorBlack = half4(0,0,0,1);
                half4 color0 = lerp(colorWhite, _Color, i.uv.x);
                color0 = lerp(colorBlack, color0, i.uv.y);
                color0 = gamma2liner(color0);
                return color0;
            }   
            ENDHLSL
        }
    }
}

2.2.2 SliderXY实现

使用IPointerDownHandler, IDragHandler处理鼠标事件,UnityEvent处理回调事件

C# 复制代码
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class SliderXY : MonoBehaviour, IPointerDownHandler, IDragHandler
{
    [SerializeField]
    private Vector2 value = Vector2.zero;

    private RectTransform self;
    private RectTransform handle;

    private UnityEvent<Vector2> callback = new UnityEvent<Vector2>();
    private Vector4 boundary = Vector4.zero;

    public UnityEvent<Vector2> onValueChanged
    {
        get 
        {
            return callback;
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        OnMouseMoving(eventData.position);
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        OnMouseMoving(eventData.position);
    }

    private void Awake()
    {
        self = transform.GetComponent<RectTransform>();
        handle = transform.Find("Handle").GetComponent<RectTransform>();

        boundary = new Vector4(
            self.position.x - self.rect.width * 0.5f,
            self.position.x + self.rect.width * 0.5f,
            self.position.y - self.rect.height * 0.5f,
            self.position.y + self.rect.height * 0.5f
        );
    }

    private void OnMouseMoving(Vector2 pos) 
    {
        pos.x = Mathf.Clamp(pos.x, boundary[0], boundary[1]);
        pos.y = Mathf.Clamp(pos.y, boundary[2], boundary[3]);
        handle.position = pos;

        CalculateValue(pos);
        OnValueChanged();
    }

    private void CalculateValue(Vector2 mousePos)
    {
        value.x = mousePos.x - self.position.x + self.rect.width * 0.5f;
        value.y = mousePos.y - self.position.y + self.rect.height * 0.5f;
        value.x /= self.rect.width;
        value.y /= self.rect.height;
    }

    private void OnValueChanged()
    {
        callback.Invoke(value);
    }

    public void SetValue(Vector2 value)
    {
        this.value = value;
        Vector2 pos = value;
        pos.x *= self.rect.width;
        pos.y *= self.rect.height;
        pos.x = pos.x - self.rect.width *0.5f + self.position.x;
        pos.y = pos.y - self.rect.height *0.5f + self.position.y;
        handle.position = pos;
    }

    public Vector2 GetValue()
    {
        return value;
    }
}

2.3 Hexadecimal

使用color.ToHexString()处理Color转Hex,ColorUtility.TryParseHtmlString处理Hex转Color

3、整体处理逻辑

C# 复制代码
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

public class Palette : MonoBehaviour
{
    private Slider slider;
    private Image imageSliderXYBG;
    private SliderXY sliderXY;
    private TMP_InputField inputFieldHex;
    private Image imagePreview;

    private void Awake()
    {
        slider = transform.Find("Slider").GetComponent<Slider>();
        imageSliderXYBG = transform.Find("SliderXY/Background").GetComponent<Image>();
        sliderXY = transform.Find("SliderXY").GetComponent<SliderXY>();
        inputFieldHex = transform.Find("Hexadecimal/InputField (TMP)").GetComponent<TMP_InputField>();
        imagePreview = transform.Find("Preview").GetComponent<Image>();
    }

    private void Start()
    {
        slider.onValueChanged.AddListener(v =>
        {
            imageSliderXYBG.material.color = Color.HSVToRGB(1 - v, 1, 1);
            OnColorChanged(GetTargetColor());
        });

        sliderXY.onValueChanged.AddListener(v =>
        {
            OnColorChanged(GetTargetColor(v));
        });

        inputFieldHex.onEndEdit.AddListener(v =>
        {
            UnityEngine.ColorUtility.TryParseHtmlString("#" + v, out Color color);
            OnColorChanged(color);
        });

        slider.onValueChanged.Invoke(slider.value);
    }

    private Color GetTargetColor()
    {
        Vector2 value = sliderXY.GetValue();
        return GetTargetColor(value);
    }

    private Color GetTargetColor(Vector2 value)
    {
        return Color.HSVToRGB(1 - slider.value, value.x, value.y);
    }

    private void OnColorChanged(Color color)
    {
        inputFieldHex.text = color.ToHexString()[..6];
        imagePreview.color = color;
		//dosomthing
    }
}
相关推荐
虾球xz17 分钟前
游戏引擎学习第146天
学习·ffmpeg·游戏引擎
小沙盒33 分钟前
godot在_process()函数实现非阻塞延时触发逻辑
javascript·游戏引擎·godot
无敌最俊朗@3 小时前
Unity大型游戏开发全流程指南
unity·游戏引擎
虾米神探4 小时前
Unity InputField + ScrollRect实现微信聊天输入框功能
unity·游戏引擎
咩咩觉主5 小时前
C# &Unity 唐老狮 No.7 模拟面试题
开发语言·unity·c#
咩咩觉主6 小时前
Unity网络开发基础 (2) 网络协议基础
网络·unity·c#
Tatalaluola6 小时前
Unity实现在镜子间反射光柱
unity·c#·游戏引擎
ccloud1111 小时前
OpenGL实现场景编辑器
qt·游戏引擎
Octopus207712 小时前
【Godot】实现对话系统
游戏引擎·godot·游戏程序