【Unity / ARFoundation】 AR空間の変形のつなぎ目を滑らかにする

# 1. はじめに
以前、[ARKit3を使ってAR空間上のカメラ映像の一部分を変形させる](https://qiita.com/koyoarai_/items/dc61d966f9abcf675c69)という記事を書きました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">カメラ映像をテクスチャにするやつやっとできた<a href="https://twitter.com/hashtag/arkit3?src=hash&amp;ref_src=twsrc%5Etfw">#arkit3</a> <a href="https://twitter.com/hashtag/ARFoundation?src=hash&amp;ref_src=twsrc%5Etfw">#ARFoundation</a> <a href="https://t.co/gRDyynsN6O">pic.twitter.com/gRDyynsN6O</a></p>&mdash; koyo arai (@koyoarai_) <a href="https://twitter.com/koyoarai_/status/1254392097286664192?ref_src=twsrc%5Etfw">April 26, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この記事を書いた時点ではあまり気にならなかったですが、よく見てみると変形のつなぎ目が目立ってしまい、あまり空間に溶け込んでいません。

![Pasted_Image_2020_11_29_15_13.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139949/76ea17f4-1a3f-47bc-6815-97ce7f9b5870.jpeg)

そこで、今回 AR空間の変形のつなぎ目を滑らかにするようにシェーダーを書き換えてみたので、そのテクニックを紹介します。



# 2. 準備

基本準備は、[ARKit3を使ってAR空間上のカメラ映像の一部分を変形させる](https://qiita.com/koyoarai_/items/dc61d966f9abcf675c69)に記載しているので、そちらをご覧ください。

# 3. 実装

変形処理のつなぎ目を滑らかにするため、シェーダー (CameraPlane.shader)を書き換えます。
Planeの中心から遠ざかるにつれ、パラメタを小さくし、つなぎ目では変形させないようにします。
そこで、tex2Dlodを使って、テクスチャ情報から頂点をいじる処理を追加します。
下記の画像をインポートし、_ScopeTexとして利用します。

![hole.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139949/976587a0-2955-c9ca-cb14-7357249dc570.png)

また、Thresholdによって変形のパラメータを調整できるようにします。
追加する処理はこのような感じです。

```
float4 deform = tex2Dlod (_ScopeTex, float4(IN.uv.xy,0,0));
float ratio = _Threshold * deform;
float4 _vertex = IN.vertex;
float ampX = 0.1f * sin(_Time * 100 + IN.vertex.x) * ratio;
float ampZ = 0.1f * sin(_Time * 100 + IN.vertex.z) * ratio;
_vertex.xyz = float3(IN.vertex.x + ampX, IN.vertex.y, IN.vertex.z + ampZ);
```

全文はこちら

```CameraPlane.shader
Shader "Custom/CameraPlane"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        // _ScopeTexと_Thresholdを追加
        _ScopeTex ("Texture", 2D) = "white" {}
        _Threshold("Threshold", Range(0,10))= 0.0
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma target 3.0
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex : POSITION;
                float4 color : COLOR;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : POSITION;
                float4 color : COLOR;
                float2 uv : TEXCOORD0;
                float2 screenpos : TEXCOORD1;
            };

            sampler2D _MainTex;
            sampler2D _ScopeTex;
            float _Threshold;

            v2f vert(appdata_t IN)
            {
                v2f OUT;
                // --------- : 追加
                float4 deform = tex2Dlod (_ScopeTex, float4(IN.uv.xy,0,0));
                float ratio = _Threshold * deform;
                float4 _vertex = IN.vertex;
                float ampX = 0.1f * sin(_Time * 100 + IN.vertex.x) * ratio;
                float ampZ = 0.1f * sin(_Time * 100 + IN.vertex.z) * ratio;
                // ---------
                _vertex.xyz = float3(IN.vertex.x + ampX, IN.vertex.y, IN.vertex.z + ampZ);

                OUT.vertex = UnityObjectToClipPos(_vertex);
                OUT.uv = IN.uv;
                OUT.color = IN.color;

                float4 objectToClipPos = UnityObjectToClipPos(IN.vertex);
                float4 spreenPos = ComputeScreenPos(objectToClipPos);
                float2 uv = spreenPos.xy/spreenPos.w;

                OUT.screenpos = uv;
                return OUT;
            }

            fixed4 frag(v2f IN) : COLOR
            {
                float2 xy = IN.screenpos.xy;
                half4 c = tex2D(_MainTex, xy);
                return c;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}
```

## 4. 実行結果

### 処理を入れる前
変形のつなぎ目がわかる状態になっています。
![Nov-29-2020 16-58-00.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139949/1dbbabd4-5d38-3349-918f-2f2355abbd0d.gif)

## 処理を入れた後
変形のつなぎ目がわからない✨
![Nov-29-2020 16-59-02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139949/ab6364ef-c944-75e0-445e-3a7c38c3a89c.gif)

## 5. おわりに

今回はARFoundation向けのシェーダーを紹介しましたが、その他のプラットフォームでも適用できそうなテクニックの紹介でした🍎

## おまけ
変形処理をちょっと変えたやつです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">AR空間の変形のつなぎ目を滑らかにする<a href="https://twitter.com/hashtag/ARKit?src=hash&amp;ref_src=twsrc%5Etfw">#ARKit</a> <a href="https://twitter.com/hashtag/ARFoundation?src=hash&amp;ref_src=twsrc%5Etfw">#ARFoundation</a> <a href="https://t.co/i8FTS5U9vO">pic.twitter.com/i8FTS5U9vO</a></p>&mdash; koyo arai (@koyoarai_) <a href="https://twitter.com/koyoarai_/status/1332964210943291393?ref_src=twsrc%5Etfw">November 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 参考

- [ARKit3を使ってAR空間上のカメラ映像の一部分を変形させる](https://qiita.com/koyoarai_/items/dc61d966f9abcf675c69)
- [【Unity】テクスチャ情報から頂点イジるシェーダーを作ってみる【頂点テクスチャフェッチ（VTF）】
](https://qiita.com/guru_taka/items/46ace162fd1887a9e772)
-  [UnityARKitPluginを使ったAR顔変形
](https://qiita.com/kitasenjudesign/items/5463c67f1d92f6c4df18)