【Unity(C#)】Skyboxをスクリプトで操作(切り替え、回転)する方法

　　
　　
　　
この記事は

**『プログラミング完全未経験からUnityでの開発現場に迎え入れてもらえた世界一の幸せ者』**

の記事です。そのつもりでお読みください。 


##スクリプトでSkyboxを切り替える

今回使わせていただいたフリーアセット→[お気に入りです！いつもお世話になってます！](https://assetstore.unity.com/packages/2d/textures-materials/sky/free-hdr-sky-61217)

```C#
public Material sky;

//切り替えたいタイミングでこれを書く
RenderSettings.skybox = sky;
```

はい、これだけらしいです。

やっていることとしては、`Lighting Settings`の
![LightingWindow.png](https://qiita-image-store.s3.amazonaws.com/0/244071/16c92f97-a2ed-b98b-757f-663a88b41842.png)
`Skybox Material`を変更しているだけです。
![SkyboxMaterial.png](https://qiita-image-store.s3.amazonaws.com/0/244071/65a48df0-1039-1ab4-7e64-eec161d24178.png)



実際にテストしてみます。

```C#
public Material sky;

    void Update()
    {
        //キー押してない間はreturn
        if (Input.anyKey == false)
        {
            return;
        }


        //テスト用 Change
        if (Input.GetKeyDown(KeyCode.C))
        {
            //切り替えたいタイミングでこれを書く
            RenderSettings.skybox = sky;
        }
    }
```

![GifCapture-201903021531068329.gif](https://qiita-image-store.s3.amazonaws.com/0/244071/b1e362ce-f0ef-ada5-1c8c-e41bfe39032e.gif)

いけました。

##Skyboxを回転させる

![SkyboxRotationDattime.png](https://qiita-image-store.s3.amazonaws.com/0/244071/409d9840-0eb5-eddb-c123-2d6c375797de.png)
Materiaを見るとRotationという項目があるのでそこをスクリプトでいじるだけです。

```C#
    //回転スピード
    [Range(0.01f,0.1f)]
    public float rotateSpeed;

    public Material sky;

    float rotationRepeatValue;

    void Update()
    {

        rotationRepeatValue = Mathf.Repeat(sky.GetFloat("_Rotation") + rotateSpeed , 360f);

        sky.SetFloat("_Rotation",rotationRepeatValue);

        //キー押してない間はreturn
        if (Input.anyKey == false)
        {
            return;
        }


        //テスト用 Change
        if (Input.GetKeyDown(KeyCode.C))
        {
            //切り替えたいタイミングでこれを書く
            RenderSettings.skybox = sky;
        }
    }
```
##Mathf.Repeat
`Mathf.Repeat`は第一引数と第二引数の剰余(割った余り)を返します。
なので` Mathf.Repeat(sky.GetFloat("_Rotation") + rotateSpeed , 360f)`は
仮に`sky.GetFloat("_Rotation")は0`、`rotateSpeedは0.1`とすると

1フレーム目　→ 0.1 % 360 → **0.1**
2フレーム目　→ 0.2 % 360 → **0.2**
3フレーム目　→ 0.3 % 360 → **0.3**
　　　　　　・
　　　　　　・
　　　　　　・
3599フレーム目 → 359.9 % 360 → **359.9**
3600フレーム目 → 360.0 % 360 → **0**
3600フレーム目 → 360.1 % 360 → **0.1**
　　　　　　・
　　　　　　・
　　　　　　・

みたいな感じで永遠に繰り返してくれます。
![GifCapture-201903031705189567.gif](https://qiita-image-store.s3.amazonaws.com/0/244071/c377e98f-e701-23d7-b0fe-4ed77868a1e2.gif)


##回転の方向を変えたい
今はY軸を中心に回転しているので、真上の雲にあまり動きはないです。
![GifCapture-201903031709247690.gif](https://qiita-image-store.s3.amazonaws.com/0/244071/df7f3d08-74f5-83b1-ea33-16684b6e2d0f.gif)
この画像は動きがわかり易いように大げさに動かしていますので、
もう少しゆっくりな回転速度に調節すればそこまで違和感を感じることはないです。

しかし、回転の方向を変えてあげれば本来の雲の流れが再現できるのでは？と思い試してみました。

##ビルトインシェーダー
Unityには組み込み済みのシェーダが山ほどあります。
今回利用したSkyboxにもそのうちの1つが使われています。

ですが、それを利用するには[ビルトインシェーダー](https://unity3d.com/jp/get-unity/download/archive)というものを使用しなければなりません。

自分の使用しているUnityのバージョンに対応しているビルトインシェーダーをダウンロードします。
![ビルトインシェーダー.png](https://qiita-image-store.s3.amazonaws.com/0/244071/c8c13e1d-00b0-0d6b-f8d1-f1e69df05e45.png)


Zipを解凍して
`DefaultResourcesExtra`＞`Skybox-Cubed.shader`
を開きます。


既存のShaderと表示名が被るので
変更します。

回転について書かれた部分も変えてプロジェクトに保存します。

```C++
//ここを変更↓
Shader "Skybox/MyCubeMap" {
Properties {
    _Tint ("Tint Color", Color) = (.5, .5, .5, .5)
    [Gamma] _Exposure ("Exposure", Range(0, 8)) = 1.0
    _Rotation ("Rotation", Range(0, 360)) = 0
    [NoScaleOffset] _Tex ("Cubemap   (HDR)", Cube) = "grey" {}
}

SubShader {
    Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
    Cull Off ZWrite Off

    Pass {

        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma target 2.0

        #include "UnityCG.cginc"

        samplerCUBE _Tex;
        half4 _Tex_HDR;
        half4 _Tint;
        half _Exposure;
        float _Rotation;

        float3 RotateAroundYInDegrees (float3 vertex, float degrees)
        {
            float alpha = degrees * UNITY_PI / 180.0;
            float sina, cosa;
            sincos(alpha, sina, cosa);
            float2x2 m = float2x2(cosa, -sina, sina, cosa);
                                             //ここを変更↓
            return float3(mul(m, vertex.xz), vertex.y).zxy;
        }

        struct appdata_t {
            float4 vertex : POSITION;
            UNITY_VERTEX_INPUT_INSTANCE_ID
        };

        struct v2f {
            float4 vertex : SV_POSITION;
            float3 texcoord : TEXCOORD0;
            UNITY_VERTEX_OUTPUT_STEREO
        };

        v2f vert (appdata_t v)
        {
            v2f o;
            UNITY_SETUP_INSTANCE_ID(v);
            UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
            float3 rotated = RotateAroundYInDegrees(v.vertex, _Rotation);
            o.vertex = UnityObjectToClipPos(rotated);
            o.texcoord = v.vertex.xyz;
            return o;
        }

        fixed4 frag (v2f i) : SV_Target
        {
            half4 tex = texCUBE (_Tex, i.texcoord);
            half3 c = DecodeHDR (tex, _Tex_HDR);
            c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
            c *= _Exposure;
            return half4(c, 1);
        }
        ENDCG
    }
}
```

![Mycubemap.png](https://qiita-image-store.s3.amazonaws.com/0/244071/44f836f0-ed67-5441-53e3-8c4e732fa0c9.png)

これで設定完了です。

![GifCapture-201903031810402775.gif](https://qiita-image-store.s3.amazonaws.com/0/244071/5d3dd4ac-dee9-669d-7524-142e5742b5c8.gif)
うん、まあそうなりますよね。

なんかTexture上手いことしてなんとかならないんでしょうか。
誰かやってみてください。私はやりません。