[unity]カラーのRGBとHSV値をスクリプトで変換する

プログラマーであれば色指定は RGB だ、それ以外は許さん、という RGB 信者は多いでしょう。
ではこの動画のような 12 色が必要になった時、RGB ですぐに作れるでしょうか?

これが unity 純正カラーパレット。
RGB のスライダーを動かしてチャッチャと作成できる人は、まずいないでしょう。
普通はその上の円から色を選び、■の部分で明るさや鮮やかさを選ぶんじゃないでしょうか。

これが HSV です。

Hue .. 色相(どんな色か) 0~360
Satuation .. 彩度(色の鮮やかさ) 0~100
Value .. 明度(色の明るさ) 0~100

HSB という言い方をすることもありますが、HSV と同じです。
HSL というものについては HSV と異なります。ここでは紹介しません。

この unity が提供してくれた優秀なカラーパレットを使って HSV を変更し色を作成、RGB 値をプログラムに入れる。
これで 12 色ならなんとかなりそうです。

では、こんなのはどうでしょう。

このような、動的な虹色変化は RGB だと作り出すのが困難です。
HSV であれば、H の値をスライドしていくだけでこういう色変化が作れます。

ColorEx.cs

というわけで本題。HSV ←→RGB に変換するクラスです。

using UnityEngine;

public class ColorEx
{
    /// <summary>
    /// HSV を RGB に変換する
    /// </summary>
    /// <param name="h">0-359</param>
    /// <param name="s">0-100</param>
    /// <param name="v">0-100</param>
    /// <returns>RGB(0~1) エラーの場合、全て 0</returns>
    public static (float R, float G, float B) HSVtoRGB(float h, float s, float v)
    {
        if (h < 0.0f || h >= 360.0f)
        {
            Debug.LogError($"[H] out of range] {h}");
            return (0, 0, 0);
        }
        if (s < 0.0f || s > 100.0f)
        {
            Debug.LogError($"[S] out of range] {s}");
            return (0, 0, 0);
        }
        if (v < 0.0f || v > 100.0f)
        {
            Debug.LogError($"[V] out of range] {v}");
            return (0, 0, 0);
        }

        float hmax = v;
        float hmin = hmax - ((s / 255) * hmax);
        float r    = 0;
        float g    = 0;
        float b    = 0;
   
        s = s / 100.0f;
        v = v / 100.0f;
   
        if (s == 0)
        {
            r = v;
            g = v;
            b = v;
        }
        else
        {
            float dh = Mathf.Floor(h / 60.0f);
            float p  = v * (1 - s);
            float q  = v * (1 - s * (h / 60.0f - dh));
            float t  = v * (1 - s * (1 - (h / 60.0f - dh)));
   
            switch (dh)
            {
                case 0  : r = v; g = t; b = p; break;
                case 1  : r = q; g = v; b = p; break;
                case 2  : r = p; g = v; b = t; break;
                case 3  : r = p; g = q; b = v; break;
                case 4  : r = t; g = p; b = v; break;
                default : r = v; g = p; b = q; break;
            }
        }
        
        return (r, g, b);
    }

    /// <summary>
    /// RGB を HSV に変換する
    /// </summary>
    /// <param name="r"></param>
    /// <param name="g"></param>
    /// <param name="b"></param>
    /// <returns>H(0-359), S(0-100), V(0-100) エラーの場合、全て 0</returns>
    public static (int H, int S, int V) RGBtoHSV(float r, float g, float b)
    {
        if (r < 0.0f || r > 1.0f)
        {
            Debug.LogError($"[R] out of range] {r}");
            return (0, 0, 0);
        }
        if (g < 0.0f || g > 1.0f)
        {
            Debug.LogError($"[G] out of range] {g}");
            return (0, 0, 0);
        }
        if (b < 0.0f || b > 1.0f)
        {
            Debug.LogError($"[B] out of range] {b}");
            return (0, 0, 0);
        }

        float max  = Mathf.Max(r, g, b);
        float min  = Mathf.Min(r, g, b);   
        float diff = max - min;

        float h    = 0.0f;
        float s    = 0.0f;
        float v    = 0.0f;
   
        if (max != min)
        {
            // H(色相)  
            if (max == r)
            {
                h = 60.0f * (g - b) / diff;
            }
            else
            if (max == g)
            {
                h = 60.0f * (b - r) / diff + 120.0f;
            }
            else
            {
                h = 60.0f * (r - g) / diff + 240.0f;
            }
     
            // S(彩度)
            s = diff / max;
        }
 
        if (h < 0)
        {
            h += 360.0f;
        }
        h = Mathf.Round(h);
        if (h >= 360.0f)
        {
            h -= 360.0f;
        }

        s = s   * 100.0f;
        v = max * 100.0f;

        return ((int)h, (int)s, (int)v);
    }
}

Exsample.cs(サンプルコード)

動画のサンプルコードも紹介しておきます。(一部はしょりましたが)

ヒエラルキーに TextMeshProUGUI を一つ配置し、合わせて生成された Canvas に次のコードをアタッチします。
ColorEx.cs もプロジェクトに配置しておいてください。

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

public class Exsample : MonoBehaviour
{
    const int CIRCLE_MAX = 12;

    List<TextMeshProUGUI>   texts;

    // Start is called before the first frame update
    void Start()
    {
        var baseText = GetComponentInChildren<TextMeshProUGUI>();
        texts = new List<TextMeshProUGUI>();

        // 12 個の●を配置
        for (int i = 0; i < CIRCLE_MAX; i++)
        {
            var angle = 360 * i / CIRCLE_MAX;

            var text = Instantiate(baseText, this.transform);

            text.SetText("●");
            text.fontSize = 100;

            var position = Quaternion.Euler(0, 0, angle) * new Vector3(0, 200, 0);

            var rect = text.GetComponent<RectTransform>();
            rect.localPosition = position;

            texts.Add(text);
        }

        StartCoroutine(color());
    }

    IEnumerator color()
    {
        var hsv = ColorEx.RGBtoHSV(texts[0].color.r, texts[0].color.g, texts[0].color.b);

        while (true)
        {
            for (int i = 0; i < CIRCLE_MAX; i++)
            {
                // 12 個の色相を等間隔に変化させる
                int _h = hsv.H + i * (360 / CIRCLE_MAX);
                if (_h >= 360)
                {
                    _h -= 360;
                }

                var text = texts[i];
                var rgb  = ColorEx.HSVtoRGB(_h, hsv.S, hsv.V);
                text.color = new Color(rgb.R, rgb.G, rgb.B, 1);
            }

            // 少しずつ H(色相)だけ変化させる。SV はそのまま
            hsv.H += 2;
            if (hsv.H >= 360)
            {
                hsv.H -= 360;
            }

            yield return null;
        }
    }
}

HSV は便利! 覚えておこう

プログラマーといえど、デザインに片足を突っ込むムーブは必要です。(大手だと、分業が進んでいて不要かもしれませんが)

こういうちょっとした事を知ってるだけで表現の幅は広がります。是非活用してください。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA