【Unity】オブジェクトを虹色に光らせよう！

- この記事ではアタッチするだけでオブジェクトをゲーミング化させるスクリプトを作成・解説します。
- アセット使うことはせず、Unityに初めから搭載されている機能のみを使って実装します。（動けば良いの精神でお願いします）
- ※本記事では、虹色（1,680万色）に光らせることを「ゲーミング化」と呼ぶことにします。

#初期準備

1. Unity 3D でプロジェクトを作成する。(プロジェクト名はなんでも良い)
1. アタッチするオブジェクトを配置
1. 新しくマテリアルを作成
1. (3) で作ったマテリアルを(2)で作ったオブジェクトにアタッチ

#実装方針
オブジェクトをゲーミング化させるにあたり、その振る舞いをどう表現するか考えます。（ソースを見たい人は飛ばしてもOK！）

さて、あなたはUnityにおいて、オブジェクトの色を変更すると言ったら「**どのような規格**」を使って変更しますか？

ほとんどの人は**RGBモデル**による変更を思い浮かべると思います。

しかし、このRGBモデルはオブジェクトをゲーミング化させるにあたり少々使い勝手が悪いです。

####RGBモデルはなぜ使い勝手が悪いのか

ではここで 初期準備(4) で用意したマテリアル選択し、Albedo項目のカラーを開きましょう。

カラーウインドウが開けたら上画面の虹色に光っているリングをマウスでグリグリ動かしてみてください。

オブジェクトが虹色に光り、ゲーミング化されました。

これをスクリプトで制御したいのですが、リングの下の部分のRGBの各値の動きを見てください。

複雑な動きをしていますね。

これをスクリプトで制御するとなれば、場合分けが6つほど発生しスクリプトが長くなります。

これがRGBモデルがゲーミング化に向いていない理由です。

####HSVモデルを使う

ここでカラーウィンドウの[ RGB 0-255 ] を [ HSV ] に変更して、また上のリングをグリグリ動かしてください。

今度は、一番上の Hの要素が0から360の範囲で変化していますね。

これだと場合分けは１つで済むので、スクリプトの制御はRGBモデルと比べて格段に楽になります。

#HSVについて

HSVは色相・彩度・明度の三要素で定義される色です。

- 色相（Hue）``` 0 <= Hue <= 360```
- 彩度（Saturation・Chroma）```0% <= Saturation <= 100%```
- 明度（Value・Brightness） ```0% <= Value <= 100%```

の範囲で表現されます。

（余談）HSVモデルは人間の色認知と非常に似ている規格で、デザイナーの世界ではRGBモデルよりもHSVモデルが使われることが多いそうです。



#HSVからRGBへの変換

ゲーミング化にはHSVモデルを使うのが最適だと分かりましたが、**なんとUnityはRGBモデル以外での色の指定はできません。**

なのでHSVモデルをRGBモデルに変換しなければなりません。~~なんとも面倒ですね。~~

真面目に変換しようとすると以下の数式で表すことができます。
> [Wikipedia HSV色空間 HSVからRGBへの変換](https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93#HSV%E3%81%8B%E3%82%89RGB%E3%81%B8%E3%81%AE%E5%A4%89%E6%8F%9B)

数式を見るだけでイヤになりますね！(´；ω；｀)

でも、安心してください！

なんとUnityには標準でHSVをRGBに変換してくれる機能があります。

それが「**HSVtoRGB**」です。

```c#:HSVtoRGB
Color.HSVToRGB(m_Hue, m_Saturation, m_Value);
```

第一引数に色彩を、第二引数に彩度を、第三引数に明度を格納するとUnityが自動でRGBモデルに変換してくれます。

#ゲーミング化スクリプト

それではスクリプトを見てみましょう。
スクリプト名は「Gaming_Material_2」です。
コピペして保存してください。

```c#:Gaming_Material_2
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Gaming_Material_2 : MonoBehaviour
{
    Material material = null;

    [Header("色変更スパン")]
    public float Chnge_Color_Time = 0.1f;

    [Header("変更の滑らかさ")]
    public float Smooth = 0.01f;

    [Header("色彩")]
    [Range(0, 1)] public float HSV_Hue = 1.0f;// 0 ~ 1

    [Header("彩度")]
    [Range(0, 1)] public float HSV_Saturation = 1.0f;// 0 ~ 1

    [Header("明度")]
    [Range(0, 1)] public float HSV_Brightness = 1.0f;// 0 ~ 1

    [Header("色彩 MAX")]
    [Range(0, 1)] public float HSV_Hue_max = 1.0f;// 0 ~ 1

    [Header("色彩 MIN")]
    [Range(0, 1)] public float HSV_Hue_min = 0.0f;// 0 ~ 1

    // Start is called before the first frame update
    void Start()
    {
        material =  GetComponent<Renderer>().material;
        HSV_Hue = HSV_Hue_min;
        StartCoroutine("Change_Color");
    }

    IEnumerator Change_Color()
    {
        HSV_Hue += Smooth;

        if (HSV_Hue >= HSV_Hue_max)
        {
            HSV_Hue = HSV_Hue_min;
        }
   
        material.color = Color.HSVToRGB(HSV_Hue, HSV_Saturation, HSV_Brightness);

        yield return new WaitForSeconds(Chnge_Color_Time);

        StartCoroutine("Change_Color");
    }
}
```
#コードの解説
###宣言部分
```c#
    Material material = null;

    [Header("色変更スパン")]
    public float Chnge_Color_Time = 0.1f;

    [Header("変更の滑らかさ")]
    public float Smooth = 0.01f;

    [Header("色彩")]
    [Range(0, 1)] public float HSV_Hue = 1.0f;// 0 ~ 1

    [Header("彩度")]
    [Range(0, 1)] public float HSV_Saturation = 1.0f;// 0 ~ 1

    [Header("明度")]
    [Range(0, 1)] public float HSV_Brightness = 1.0f;// 0 ~ 1

    [Header("色彩 MAX")]
    [Range(0, 1)] public float HSV_Hue_max = 1.0f;// 0 ~ 1

    [Header("色彩 MIN")]
    [Range(0, 1)] public float HSV_Hue_min = 0.0f;// 0 ~ 1
```
宣言部分です。
マテリアルや色彩・彩度・明度など必要な情報と、少し拡張したゲーミング化スクリプトにするための情報を宣言しています。

```c#
    [Header("色変更スパン")]
    public float Chnge_Color_Time = 0.1f;

    [Header("変更の滑らかさ")]
    public float Smooth = 0.01f;
```
特にこの二つが重要で、前者は次の色に変更するまでの時間を、後者は色変更の細かさを表しています。

###Start関数内部
```c#
    // Start is called before the first frame update
    void Start()
    {
        material =  GetComponent<Renderer>().material;
        HSV_Hue = HSV_Hue_min;
        StartCoroutine("Change_Color");
    }
```
Start関数内部では、マテリアルを取得する、色彩を設定した最小値に変更する、"Change_Color"というコルーチンを呼び出す、ことをしています。
特に難しくはありませんね。

###コルーチン内部

```c#
    IEnumerator Change_Color()
    {
        HSV_Hue += Smooth;

        if (HSV_Hue >= HSV_Hue_max)
        {
            HSV_Hue = HSV_Hue_min;
        }
        
        material.color = Color.HSVToRGB(HSV_Hue, HSV_Saturation, HSV_Brightness);

        yield return new WaitForSeconds(Chnge_Color_Time);

        StartCoroutine("Change_Color");
    }
```
コルーチン内部です。

コルーチンが呼ばれるごとに、float型のHSV_HueにSmoothで宣言した分加算します。

また、HSV_Hueが宣言したHSV_max以上になると、HSV_Hueに宣言したHSV_minを代入します。
つまり、色彩のリセットを行っています。

そしてHSVtoRGBを用いて、マテリアルに色を設定します。

ここで宣言したfloat型のChnge_Color_Time秒待ちます。

最後は自身であるコルーチンを呼び出しています。まるで再帰関数のようですね。

#ゲーミング化できるか確かめる

コピペして保存、そしてオブジェクトにアタッチ出来たら早速ゲームを再生してみましょう！

オブジェクトが虹色（1,680万色）に光れば成功です。お疲れさまでした。( ◠‿◠ )

#参考資料
>Wikipedia HSV色空間　（アクセス日：2021/5/20）
https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93

>naichilab RGBではなくHSVによる色指定（アクセス日：2021/5/20）
https://naichilab.blogspot.com/2013/11/unitycrgbhsv.html?m=1

>おもちゃラボ スクリプトでRGBとHSVを相互に変換する方法（アクセス日：2021/5/20）
https://nn-hokuson.hatenablog.com/entry/2017/04/12/194631

>Unity DOCUMENTION Color.HSVToRGB（アクセス日：2021/5/20）
https://docs.unity3d.com/ja/current/ScriptReference/Color.HSVToRGB.html