万華鏡をつくる。カメラでなくテクスチャ単体に、効果つけたい。


カメラではなくて、テクスチャ単体に対して万華鏡の効果をつけたい。
テクスチャというか、3D空間に置いた、Planeオブジェクトに。

![output.gif](https://qiita-image-store.s3.amazonaws.com/0/365269/2ec4fddd-52cf-07eb-9368-f03bb9391bfb.gif)

* 環境 2018.3.5f1
* ビルドターゲット WebGL
(Android・iOS も動いて欲しいけど、未確認)


## テクスチャの準備しよう。

万華鏡の素材を準備する。

* 幾何学っぽい模様が何かあればいいので
幾何学ジェネレータ的なもので素材作ってDLする。
* [Delaunay triangle pattern maker](https://msurguy.github.io/triangles/)

* DLできたテクスチャは、
1000px 2000px 大きかったので適宜リサイズする。


![triangles-download.png](https://qiita-image-store.s3.amazonaws.com/0/365269/5c9576bc-16cd-f65d-aff4-4972df6b54fd.png)

## カメラに付ける系のポストエフェクト、２つ見かけた。


|  [万華鏡 unity - Google 検索][1]   | 
| ------------- |

* [【Unity】万華鏡のような反射エフェクト「KinoMirror」紹介 - コガネブログ][2]
* [【Unity】【EffectShader】万華鏡のポストエフェクトを使用する - コガネブログ][3]

### 処理の中身を理解したいんだけど...
### 鏡...

[Three.jsのPixel Shaders入門 - 気密インタラクティブ][4]
> ミラーシェーダの例
> ピクセルをある領域から別の領域にコピーする
> 画面の左側を右側にコピーする
> 
> 1. 各ピクセルの、x位置を確認する（px）
> 2. 0.5より大きい場合、ピクセルは画面の右側にある
> 3. gl_FragColorを通常の方法で取得する代わりに、画面の反対側の位置（1.0-px）にあるピクセルのピクセルカラーを取得する

### atan2？？アークタンジェント？

[atan関数とatan2関数の意味と違い - 具体例で学ぶ数学](https://mathwords.net/atan2)
うん。（なんかそういうのがある。）


## 作ろう。
「Create」→「Shader」→「Unlit Shader」


###1 Createした状態
<details><summary>Diff コード</summary><div>


```diff
+﻿Shader "Unlit/NewUnlitShader"
+{
+    Properties
+    {
+        _MainTex ("Texture", 2D) = "white" {}
+    }
+    SubShader
+    {
+        Tags { "RenderType"="Opaque" }
+        LOD 100
+
+        Pass
+        {
+            CGPROGRAM
+            #pragma vertex vert
+            #pragma fragment frag
+            // make fog work
+            #pragma multi_compile_fog
+
+            #include "UnityCG.cginc"
+
+            struct appdata
+            {
+                float4 vertex : POSITION;
+                float2 uv : TEXCOORD0;
+            };
+
+            struct v2f
+            {
+                float2 uv : TEXCOORD0;
+                UNITY_FOG_COORDS(1)
+                float4 vertex : SV_POSITION;
+            };
+
+            sampler2D _MainTex;
+            float4 _MainTex_ST;
+
+            v2f vert (appdata v)
+            {
+                v2f o;
+                o.vertex = UnityObjectToClipPos(v.vertex);
+                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
+                UNITY_TRANSFER_FOG(o,o.vertex);
+                return o;
+            }
+
+            fixed4 frag (v2f i) : SV_Target
+            {
+                // sample the texture
+                fixed4 col = tex2D(_MainTex, i.uv);
+                // apply fog
+                UNITY_APPLY_FOG(i.fogCoord, col);
+                return col;
+            }
+            ENDCG
+        }
+    }
+}

```
</div></details>

<details><summary>Raw コード</summary><div>



```
Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

```
</div></details>

###2 透過オン裏面オン

<details><summary>Diff コード</summary><div>




```diff
     }
     SubShader
     {
-        Tags { "RenderType"="Opaque" }
+        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
         LOD 100
+        Cull off
+        Blend SrcAlpha OneMinusSrcAlpha 
 
         Pass
         {

```
</div></details>

<details><summary>Raw コード</summary><div>




```
Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 100
        Cull off
        Blend SrcAlpha OneMinusSrcAlpha 

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

```
</div></details>




###3 万華鏡表示
上にある、カメラに付ける系のコードを参考にして、
<details><summary>Diff コード</summary><div>



```diff
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
+        _repeat ("Repeat", Float) = 5.0 // _repeat: number of reflections
    }
    SubShader
    {

```
```diff
            sampler2D _MainTex;
            float4 _MainTex_ST;

+            float _repeat;
+
            v2f vert (appdata v)
            {
                v2f o;

```
```diff
 
             fixed4 frag (v2f i) : SV_Target
             {
-                // sample the texture
-                fixed4 col = tex2D(_MainTex, i.uv);
+                half2 p = i.uv - 0.5;
+                float r = length(p);
+                float atn = abs(atan2(p.y, -p.x));
+                
+                float tau = 2.0 * 3.1416 ;
+                float sides = _repeat; 
+                atn = fmod(atn, tau/sides);
+                atn = abs(atn - tau/sides/2.0) ;
+                p = r * float2(cos(atn), sin(atn));
+
+                fixed4 col = tex2D(_MainTex, p+0.5);
                // apply fog
                 UNITY_APPLY_FOG(i.fogCoord, col);
                 return col;
             }

```
</div></details>

<details><summary>Raw コード</summary><div>




```
Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _repeat ("Repeat", Float) = 5.0 // _repeat: number of reflections
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 100
        Cull off
        Blend SrcAlpha OneMinusSrcAlpha 

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            float _repeat;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                half2 p = i.uv - 0.5;
                float r = length(p);
                float atn = abs(atan2(p.y, -p.x));
                
                float tau = 2.0 * 3.1416 ;
                float sides = _repeat; 
                atn = fmod(atn, tau/sides);
                atn = abs(atn - tau/sides/2.0) ;
                p = r * float2(cos(atn), sin(atn));

                fixed4 col = tex2D(_MainTex, p+0.5);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

```
</div></details>


###4 丸くする (丸く切り抜くマスク)

そのままだと四角いので、まあるくしたいです。



<!-- <img width="431" alt="スクリーンショット 2019-02-21 4.01.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/365269/a7e9dea1-c86a-8f62-3966-1a4f41038e41.png"> -->

![スクリーンショット](https://qiita-image-store.s3.amazonaws.com/0/365269/a7e9dea1-c86a-8f62-3966-1a4f41038e41.png)


|  [plane mask unity - Google 検索][5]   | 
| ------------- |

|  [unity shader 切り抜き - Google 検索][6]   | 
| ------------- |

* [Masking a plane object (which has an animated texture offset) - Unity Answers][7]

検索しても、よくわからなかったので
マスク用のテクスチャ用意してアルファ見て
透明だったら透明にしてる（語彙力...）
`col.a = min(col.a, colA.a);`

<details><summary>Diff コード</summary><div>



```diff
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
+        _MainTexA ("TextureA", 2D) = "white" {}
        _repeat ("Repeat", Float) = 5.0 // _repeat: number of reflections
    }
    SubShader

```

```diff
            };

            sampler2D _MainTex;
+            sampler2D _MainTexA;
            float4 _MainTex_ST;

            float _repeat;

```

```diff
                p = r * float2(cos(atn), sin(atn));

                fixed4 col = tex2D(_MainTex, p+0.5);
+                fixed4 colA = tex2D(_MainTexA, i.uv);
+                col.a = min(col.a, colA.a);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;

```
</div></details>

<details><summary>Raw コード</summary><div>





```
Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _MainTexA ("TextureA", 2D) = "white" {}
        _repeat ("Repeat", Float) = 5.0 // _repeat: number of reflections
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 100
        Cull off
        Blend SrcAlpha OneMinusSrcAlpha 

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            sampler2D _MainTexA;
            float4 _MainTex_ST;

            float _repeat;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                half2 p = i.uv - 0.5;
                float r = length(p);
                float atn = abs(atan2(p.y, -p.x));
                
                float tau = 2.0 * 3.1416 ;
                float sides = _repeat; 
                atn = fmod(atn, tau/sides);
                atn = abs(atn - tau/sides/2.0) ;
                p = r * float2(cos(atn), sin(atn));

                fixed4 col = tex2D(_MainTex, p+0.5);
                fixed4 colA = tex2D(_MainTexA, i.uv);
                col.a = min(col.a, colA.a);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

```
</div></details>



<details><summary>[追記] マスク用のテクスチャ用意しなくてもできた。</summary><div>

```diff
                 p = r * float2(cos(atn), sin(atn));
 
                 fixed4 col = tex2D(_MainTex, p+0.5);
-                fixed4 colA = tex2D(_MainTexA, i.uv);
-                col.a = min(col.a, colA.a);
+                fixed radius = 0.45;
+                fixed rr = distance(i.uv, fixed2(0.5,0.5));
+                fixed4 colA = smoothstep(radius, radius+0.02, rr);
+                col.a = min(col.a, abs(1-colA.a));
                // apply fog
                 UNITY_APPLY_FOG(i.fogCoord, col);
                 return col;
             }

```

</div></details>



###5 動かす用の準備 （アニメーション。くるくるくる。）
ここも 上にある、カメラに付ける系のコードを参考にして、
<details><summary>Diff コード</summary><div>





```diff
        _MainTex ("Texture", 2D) = "white" {}
        _MainTexA ("TextureA", 2D) = "white" {}
        _repeat ("Repeat", Float) = 5.0 // _repeat: number of reflections
+        _rotation ("Rotation", Float) = 0.0 //  _rotation: initial angle in radians
    }
    SubShader
    {

```

```diff
            float4 _MainTex_ST;

            float _repeat;
+            float _rotation;

            v2f vert (appdata v)
            {

```

```diff
                float sides = _repeat; 
                atn = fmod(atn, tau/sides);
                atn = abs(atn - tau/sides/2.0) ;
+                atn += _rotation;
                p = r * float2(cos(atn), sin(atn));

                fixed4 col = tex2D(_MainTex, p+0.5);

```
</div></details>

<details><summary>Raw コード</summary><div>





```
Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _MainTexA ("TextureA", 2D) = "white" {}
        _repeat ("Repeat", Float) = 5.0 // _repeat: number of reflections
        _rotation ("Rotation", Float) = 0.0 //  _rotation: initial angle in radians
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 100
        Cull off
        Blend SrcAlpha OneMinusSrcAlpha 

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            sampler2D _MainTexA;
            float4 _MainTex_ST;

            float _repeat;
            float _rotation;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                half2 p = i.uv - 0.5;
                float r = length(p);
                float atn = abs(atan2(p.y, -p.x));
                
                float tau = 2.0 * 3.1416 ;
                float sides = _repeat; 
                atn = fmod(atn, tau/sides);
                atn = abs(atn - tau/sides/2.0) ;
                atn += _rotation;
                p = r * float2(cos(atn), sin(atn));

                fixed4 col = tex2D(_MainTex, p+0.5);
                fixed4 colA = tex2D(_MainTexA, i.uv);
                col.a = min(col.a, colA.a);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

```
</div></details>

###6 動かす

ここも 上にある、カメラに付ける系のコードを参考にして、
<details><summary>C#</summary><div>

```csharp
using UnityEngine;

namespace Kaleidoscope
{
    [ExecuteInEditMode]
    public class KaleidoscopeScript : MonoBehaviour
    {
        [SerializeField] int _repeat;
        [Range(0, 6.28319f)] [SerializeField] float _rotation;
        [SerializeField] Shader _shader;
        Material _material;

        //Set these Textures in the Inspector
        public Texture m_MainTexture, m_Alpha;

        void OnRenderObject()
        {
            if (_material == null)
            {
                _material = new Material(_shader);
                _material.hideFlags = HideFlags.DontSave;
                GetComponent<Renderer>().material = _material;
            }


            _material.SetFloat("_repeat", _repeat);
            _material.SetFloat("_rotation", _rotation);

            _material.SetTexture("_MainTex", m_MainTexture);
            _material.SetTexture("_MainTexA", m_Alpha);
        }
    }
}

```

</div></details>


この、_rotation の値をアニメーションします。

AnimationClip

<!-- <img width="473" alt="スクリーンショット 2019-02-21 3.22.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/365269/f8f6d211-316a-8a17-5d96-c0e99da345ac.png"> -->
![スクリーンショット](https://qiita-image-store.s3.amazonaws.com/0/365269/f8f6d211-316a-8a17-5d96-c0e99da345ac.png)

| time | 0 | 4 | 12 | 16 |
|:-:|:-:|:-:|:-:|:-:|
|  value |  0 |  6.2832 |  -6.2832 |  0 |



 6.2832 は、2π です。
 （2 × 3.14 ）
 

おしまい。

[1]:[https://www.google.com/search?ei=xzxqXJHEIYbQ8wWt7bnwBA&q=%E4%B8%87%E8%8F%AF%E9%8F%A1+unity&oq=%E4%B8%87%E8%8F%AF%E9%8F%A1+unity&gs_l=psy-ab.3..0i8i30.1436780.1437448..1437986...0.0..0.83.399.5......0....1..gws-wiz.......0i4j0i30j0i4i30.QTWj9S-xp1M]
[2]:[http://baba-s.hatenablog.com/entry/2018/01/18/085700]
[3]:[http://baba-s.hatenablog.com/entry/2018/11/22/085000]
[4]:[https://www.airtightinteractive.com/2013/02/intro-to-pixel-shaders-in-three-js/]
[5]:[https://www.google.com/search?q=plane+mask+unity&oq=plane+mask+unity&aqs=chrome..69i57.7857j0j1&sourceid=chrome&ie=UTF-8]
[6]:[https://www.google.com/search?q=unity+shader+切り抜き&sa=X&ved=2ahUKEwiznNTk6MTgAhWsIaYKHa6hAO4Q1QIoCXoECAYQCg&biw=1235&bih=698]
[7]:[https://answers.unity.com/questions/451868/masking-a-plane-object-which-has-an-animated-textu.html]