【Unity】HSVカラーピッカーとカラー選択ボタンの作成方法

Unity

前回の記事でUnityにおけるカラーピッカーとUIパーツの役割と機能を概要を説明しました。今回はさらに深く掘り下げ、具体的なHSVカラーピッカーの作成とカラー選択ボタンの実装方法について解説します。これらの機能は、ユーザーが色を直感的に選択し、アプリケーションやゲーム内のオブジェクトに適用する際に不可欠です。

今回の記事の手順を踏んで作成したいものは下記↓

カラーマネージャーの作成

まずはオブジェクトを選択するためのドロップダウンと、オブジェクトの色やプロパティ(次回以降の記事で作成するメタリック、スムーズネス、エミッションなど)を管理するための機能を作成していきます。

スクリプトの作成(CubeColorManager.cs)

今回は「CubeColorManager.cs」という名前のスクリプトを作成します。具体的なスクリプトの中身は下記です。(※次回以降の記事で作成する予定のメタリック、スムーズネス、エミッションなどのプロパティも更新するためのメソッドも含まれています。)

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class CubeColorManager : MonoBehaviour
{
    public TMP_Dropdown cubeDropdown; // Cubeを選択するためのドロップダウン
    public Renderer[] cubeRenderers; // CubeオブジェクトのRenderer配列
    private int selectedCubeIndex = 0; // 選択されたCubeのインデックス

    // 外部からアクセス可能な選択されたRendererを取得するプロパティ
    public Renderer SelectedCubeRenderer
    {
        get
        {
            if (selectedCubeIndex >= 0 && selectedCubeIndex < cubeRenderers.Length)
            {
                return cubeRenderers[selectedCubeIndex];
            }
            return null;
        }
    }

    void Start()
    {
        cubeDropdown.onValueChanged.AddListener(OnCubeSelectionChanged);
    }

    void OnCubeSelectionChanged(int index)
    {
        selectedCubeIndex = index;
    }

    // 他のスクリプトでCubeの色を更新するためのメソッド
    public void UpdateSelectedCubeColor(Color color)
    {
        Renderer renderer = SelectedCubeRenderer;
        if (renderer != null)
        {
            renderer.material.color = color;
        }
    }

    // 選択されたCubeのメタリックを更新するためのメソッド(必要に応じて追加)
    public void UpdateSelectedCubeMetallic(float metallic)
    {
        Renderer renderer = SelectedCubeRenderer;
        if (renderer != null)
        {
            renderer.material.SetFloat("_Metallic", metallic);
        }
    }

    // 選択されたCubeのスムーズネスを更新するためのメソッド(必要に応じて追加)
    public void UpdateSelectedCubeSmoothness(float smoothness)
    {
        Renderer renderer = SelectedCubeRenderer;
        if (renderer != null)
        {
            renderer.material.SetFloat("_Glossiness", smoothness);
        }
    }

    // 選択されたCubeのエミッションを更新するためのメソッド(必要に応じて追加)
    public void UpdateSelectedCubeEmission(float emission)
    {
        Renderer renderer = SelectedCubeRenderer;
        if (renderer != null)
        {
            Color currentColor = renderer.material.color;
            Color emissionColor = new Color(currentColor.r * emission, currentColor.g * emission, currentColor.b * emission);
            renderer.material.SetColor("_EmissionColor", emissionColor);
        }
    }
}

このスクリプトは、前回の記事で作成した「UIManager」オブジェクトにドラッグ&ドロップでアタッチします。

UIManagerにアタッチすると、UIManagerのインスペクタウィンドウに項目が表示されるので、それぞれの項目にドロップダウンと色を変えたいオブジェクトを設定していきましょう。(※具体的な操作方法は後述します。)

ドロップダウンの作成

次に、色を変更するオブジェクトを選択するためのドロップダウンを作成します。

下記の動画のようにヒエラルキーウィンドウにドロップダウンを追加しましょう。

ドロップダウンを作成できたら、下記の動画のように、先ほどのスクリプトをアタッチしたUIManagerのインスペクタウィンドウを設定すれば、カラーマネージャーの作成は完了です。

HSVカラーピッカーの作成

次に、HSVカラーピッカーとスクリプトを作成していきます。

HSVカラーピッカーとは?
色を選択するためのユーザーインターフェイスの一種であり、「Hue(色相)」「Saturation(彩度)」「Value(明度)」の3つの要素で色を定義します。HSVカラーピッカーの利点として、ユーザーは色相環を見て直感的に色を選び、彩度と明度のスライダーで細かい調整が可能です。

HSVとは?
Hue(色相): 色相は、色の種類を表します(例:赤、青、緑など)。色相は通常、0°から360°の範囲で表され、色相環(カラーホイール)上の位置によって異なる色が定義されます。
Saturation(彩度): 彩度は、色の鮮やかさや純度を表します。低い彩度は色が薄くなり、高い彩度は色が鮮やかになります。彩度が0の場合、色はグレースケール(白から黒)になります。
Value(明度): 明度は、色の明るさを表します。低い明度は暗い色(黒に近い)、高い明度は明るい色(白に近い)を意味します。

スクリプトの作成(ColorPicker.cs)

今回は「ColorPicker.cs」という名前のスクリプトを作成します。具体的なスクリプトの中身は下記です。

using UnityEngine;
using UnityEngine.UI;

public class ColorPicker : MonoBehaviour
{
    public Slider hueSlider;
    public Slider saturationSlider;
    public Slider valueSlider;
    public Image hueSliderBackground;
    public Image saturationSliderBackground;
    public Image valueSliderBackground;
    public CubeColorManager cubeColorManager; // CubeColorManagerへの参照
    private const int GradientTextureWidth = 256; // グラデーションテクスチャの幅

    void Start()
    {
        // スライダーの背景テクスチャを更新
        UpdateHueSliderBackground();
        UpdateSaturationValueSliderBackgrounds(hueSlider.value);

        // スライダーの値が変更されたときのイベントリスナーを追加
        hueSlider.onValueChanged.AddListener(delegate { OnHueValueChanged(hueSlider.value); });
        saturationSlider.onValueChanged.AddListener(delegate { OnColorChanged(); });
        valueSlider.onValueChanged.AddListener(delegate { OnColorChanged(); });
    }

    void OnHueValueChanged(float hue)
    {
        UpdateSaturationValueSliderBackgrounds(hue);
        OnColorChanged();
    }

    void OnColorChanged()
    {
        if (cubeColorManager != null)
        {
            Color newColor = Color.HSVToRGB(hueSlider.value, saturationSlider.value, valueSlider.value);
            cubeColorManager.UpdateSelectedCubeColor(newColor);
        }
    }

    void UpdateHueSliderBackground()
    {
        hueSliderBackground.sprite = Sprite.Create(CreateHueGradient(), new Rect(0, 0, GradientTextureWidth, 1), new Vector2(0.5f, 0.5f));
    }

    void UpdateSaturationValueSliderBackgrounds(float hue)
    {
        saturationSliderBackground.sprite = Sprite.Create(CreateSaturationGradient(hue), new Rect(0, 0, GradientTextureWidth, 1), new Vector2(0.5f, 0.5f));
        valueSliderBackground.sprite = Sprite.Create(CreateValueGradient(hue), new Rect(0, 0, GradientTextureWidth, 1), new Vector2(0.5f, 0.5f));
    }

    Texture2D CreateHueGradient()
    {
        Texture2D texture = new Texture2D(GradientTextureWidth, 1, TextureFormat.RGB24, false);
        for (int i = 0; i < GradientTextureWidth; i++)
        {
            Color color = Color.HSVToRGB(i / (float)GradientTextureWidth, 1f, 1f);
            texture.SetPixel(i, 0, color);
        }
        texture.Apply();
        return texture;
    }

    Texture2D CreateSaturationGradient(float hue)
    {
        Texture2D texture = new Texture2D(GradientTextureWidth, 1, TextureFormat.RGB24, false);
        for (int i = 0; i < GradientTextureWidth; i++)
        {
            Color color = Color.HSVToRGB(hue, i / (float)GradientTextureWidth, 1f);
            texture.SetPixel(i, 0, color);
        }
        texture.Apply();
        return texture;
    }

    Texture2D CreateValueGradient(float hue)
    {
        Texture2D texture = new Texture2D(GradientTextureWidth, 1, TextureFormat.RGB24, false);
        for (int i = 0; i < GradientTextureWidth; i++)
        {
            Color color = Color.HSVToRGB(hue, 1f, i / (float)GradientTextureWidth);
            texture.SetPixel(i, 0, color);
        }
        texture.Apply();
        return texture;
    }
}

このスクリプトも、前回の記事で作成した「UIManager」オブジェクトにドラッグ&ドロップでアタッチします。

UIManagerにアタッチすると、UIManagerのインスペクタウィンドウに項目が表示されるので、それぞれの項目に対応するスライダーを作成していきましょう。(※具体的な操作方法は後述します。)

スライダーの作成

次に、ユーザーがシーンを再生しているときに、「Hue(色相)」「Saturation(彩度)」「Value(明度)」それぞれを調整できるようにスライダーを作成します。

下記の動画のようにヒエラルキーウィンドウにスライダーを3つ追加しましょう。

上記の動画の後半部分で、作成したスライダーオブジェクトの中を見ていくと、[Fill Area]→[Fill]という構造になっていると思います。これはスライダーを左から右にスライドさせた時に出てくる横棒の設定になります。人それぞれの好みになりますが、操作した時にHSVスライダーを隠してしまわないように、今回はFillを透明にしておきました。

スライダーを作成できたら、下記の動画のように、先ほどのスクリプトをアタッチしたUIManagerのインスペクタウィンドウを設定すれば、カラーピッカーの作成は完了です。

カラー選択ボタンの作成

次はカラー選択ボタンと、そのスクリプトを作成していきます。
このボタンはあらかじめ指定した色を即座に扱えるようにするために作成します。

スクリプトの作成(ColorButtonController.cs)

今回は「ColorButtonController.cs」という名前のスクリプトを作成します。具体的なスクリプトの中身は下記です。

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class ColorButtonController : MonoBehaviour
{
    public TMP_Dropdown cubeDropdown; // Cubeを選択するためのドロップダウン
    public CubeColorManager cubeColorManager; // CubeColorManagerスクリプトへの参照
    public ButtonMaterialPair[] buttonMaterialPairs; // ボタンとマテリアルのペアを格納する配列

    [System.Serializable]
    public struct ButtonMaterialPair
    {
        public Button button; // ボタンの参照
        public Color color; // 割り当てる色
        public float metallic; // 割り当てるメタリック値
        public float smoothness; // 割り当てるスムーズネス値
        public float emission; // 割り当てるエミッション値
    }

    void Start()
    {
        // 各ボタンのOnClickイベントにマテリアルのプロパティを適用するメソッドを追加
        foreach (var pair in buttonMaterialPairs)
        {
            pair.button.onClick.AddListener(() => ApplyMaterialPropertiesToSelectedCube(pair));
        }
    }

    void ApplyMaterialPropertiesToSelectedCube(ButtonMaterialPair pair)
    {
        // 選択されたCubeにマテリアルのプロパティを設定
        cubeColorManager.UpdateSelectedCubeColor(pair.color);
        cubeColorManager.UpdateSelectedCubeMetallic(pair.metallic);
        cubeColorManager.UpdateSelectedCubeSmoothness(pair.smoothness);
        cubeColorManager.UpdateSelectedCubeEmission(pair.emission);
    }
}

このスクリプトも、先ほどから使っている「UIManager」オブジェクトにドラッグ&ドロップでアタッチします。

UIManagerにアタッチすると、UIManagerのインスペクタウィンドウに項目が表示されるので、それぞれの項目を設定していきましょう。(※具体的な操作方法は後述します。)

UIボタンの作成

次に、あらかじめ用意していた色をオブジェクトに即座に適用できるようにするためのUIボタン(色選択ボタン)を複数個作成します。今回はとりあえず8色分のボタンを用意します。

下記の動画のように、ヒエラルキーウィンドウにUIボタンを8つ追加しましょう。

※上記の動画で作成した8つのボタンを、それぞれのボタンが何色用のボタンなのか、わかりやすい名前とボタンの見た目に変えたら下記のような画面になります。

8つのボタンを作成できたら、下記の動画のように、先ほどのスクリプトをアタッチしたUIManagerのインスペクタウィンドウを設定すれば、カラー選択ボタンの作成は完了です。(※下記の動画では、yellowボタンとredボタンのみを設定していますが、他の色についても同様に設定していきます。)

作成結果の確認

今回は「カラーピッカー」と「カラー選択ボタン」を作成しました。実際にシーンを再生してみると、ドロップダウンで指定されたオブジェクトの色を変更できていることがわかります。

まとめ

HSVカラーピッカーとカラー選択ボタンの作成を通じて、Unityでの色の管理と操作がいかに柔軟であるかを示しました。これらのコンポーネントはユーザーに対して直感的な色選択のインターフェイスを提供し、アプリケーションのビジュアルアピアランスを大幅に向上させます。

コメント