ARFoundation 色を反転するShader、デバイスに合わせて背景を切り替える

ARFoundation3.0.1
ARKit3.0.1
ARCore3.0.1　で動作可能。

Packages→ARKitXRPlugin→ARKitBackgroundをコピーする
![43E61D6B-9C00-44EC-ADAE-57D1E9981400_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/bd0dcd65-1e6f-8031-e441-915cf57e7cc9.jpeg)

名前をARKit InvertColorに変更する
![EB55BE07-A358-4F69-A85D-BCBBE1EEE95D_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/edf44769-9b39-fe26-1d61-92025e9b09a0.jpeg)

ARCoreInverColorも同様に作成する
![475A4F08-E903-46C4-88E1-9846C26DB2F0_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/c9e21024-44be-abf5-6d50-e2f9a9508e7b.jpeg)

ARKit InvertColorとARCore InvertColorに下記を追加する

```C#:ARKitInvertColor.Shader
Shader "CameraBackground/ARKitInvertColor"
{
    Properties
    {
        _textureY ("TextureY", 2D) = "white" {}
        _textureCbCr ("TextureCbCr", 2D) = "black" {}
    }
    SubShader
    {
        Cull Off
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            ZWrite Off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            float4x4 _UnityDisplayTransform;

            struct Vertex
            {
                float4 position : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            struct TexCoordInOut
            {
                float4 position : SV_POSITION;
                float2 texcoord : TEXCOORD0;
            };

            TexCoordInOut vert (Vertex vertex)
            {
                TexCoordInOut o;
                o.position = UnityObjectToClipPos(vertex.position);

                float texX = vertex.texcoord.x;
                float texY = vertex.texcoord.y;

                o.texcoord.x = (_UnityDisplayTransform[0].x * texX + _UnityDisplayTransform[1].x * (texY) + _UnityDisplayTransform[2].x);
                o.texcoord.y = (_UnityDisplayTransform[0].y * texX + _UnityDisplayTransform[1].y * (texY) + (_UnityDisplayTransform[2].y));

                return o;
            }

            // samplers
            sampler2D _textureY;
            sampler2D _textureCbCr;

            fixed4 frag (TexCoordInOut i) : SV_Target
            {
                // sample the texture
                float2 texcoord = i.texcoord;
                float y = tex2D(_textureY, texcoord).r;
                float4 ycbcr = float4(y, tex2D(_textureCbCr, texcoord).rg, 1.0);

                const float4x4 ycbcrToRGBTransform = float4x4(
                        float4(1.0, +0.0000, +1.4020, -0.7010),
                        float4(1.0, -0.3441, -0.7141, +0.5291),
                        float4(1.0, +1.7720, +0.0000, -0.8860),
                        float4(0.0, +0.0000, +0.0000, +1.0000)
                    );

                // 1 から元の RGBA 値を引くことで色を反転する
                float4 result = float4(1, 1, 1, 1) - mul(ycbcrToRGBTransform, ycbcr);

#if !UNITY_COLORSPACE_GAMMA
                // Incoming video texture is in sRGB color space.
                //If we are rendering in linear color space, we need to convert.
                result = float4(GammaToLinearSpace(result.xyz), result.w);
#endif // !UNITY_COLORSPACE_GAMMA

                return result;
            }
            ENDCG
        }
    }
}
```


```C#:ARCoreInvertColor.Shader
Shader Shader "CameraBackground/ARCoreInvertColor"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }

    // For GLES3
    SubShader
    {
        Pass
        {
            ZWrite Off
            Cull Off

            GLSLPROGRAM

#pragma only_renderers gles3

#ifdef SHADER_API_GLES3
#extension GL_OES_EGL_image_external_essl3 : require
#endif // SHADER_API_GLES3

            uniform mat4 _UnityDisplayTransform;

#ifdef VERTEX
            varying vec2 textureCoord;

            void main()
            {
#ifdef SHADER_API_GLES3
                float flippedV = 1.0 - gl_MultiTexCoord0.y;
                textureCoord.x = _UnityDisplayTransform[0].x * gl_MultiTexCoord0.x + _UnityDisplayTransform[1].x * flippedV + _UnityDisplayTransform[2].x;
                textureCoord.y = _UnityDisplayTransform[0].y * gl_MultiTexCoord0.x + _UnityDisplayTransform[1].y * flippedV + _UnityDisplayTransform[2].y;
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
#endif // SHADER_API_GLES3
            }
#endif // VERTEX

#ifdef FRAGMENT
            varying vec2 textureCoord;
            uniform samplerExternalOES _MainTex;

#if defined(SHADER_API_GLES3) && !defined(UNITY_COLORSPACE_GAMMA)
            float GammaToLinearSpaceExact (float value)
            {
                if (value <= 0.04045F)
                    return value / 12.92F;
                else if (value < 1.0F)
                    return pow((value + 0.055F)/1.055F, 2.4F);
                else
                    return pow(value, 2.2F);
            }

            vec3 GammaToLinearSpace (vec3 sRGB)
            {
                // Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
                return sRGB * (sRGB * (sRGB * 0.305306011F + 0.682171111F) + 0.012522878F);

                // Precise version, useful for debugging, but the pow() function is too slow.
                // return vec3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b));
            }
#endif // SHADER_API_GLES3 && !UNITY_COLORSPACE_GAMMA

            void main()
            {
#ifdef SHADER_API_GLES3
                vec3 result = texture(_MainTex, textureCoord).xyz;

#ifndef UNITY_COLORSPACE_GAMMA
                result = GammaToLinearSpace(result);
#endif // !UNITY_COLORSPACE_GAMMA
                // 1 から元の RGBA 値を引くことで色を反転する
                gl_FragColor = vec4(1, 1, 1, 1) - vec4(result, 1);
#endif // SHADER_API_GLES3
            }

#endif // FRAGMENT
            ENDGLSL
        }
    }

    FallBack Off
}
```


ARKitInvertColorマテリアルを作成し、InvertColor.Shaderを選択する。
ARCore InvertColorも同様に作成する。
![4C9BC3B9-03C3-44DE-8E1B-6F5B4476FC33_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/399ac494-883e-0ecc-f4b1-3acb099cd17a.jpeg)


AR CameraのARCameraBackgroundにARKit InvertColorをアタッチする
![E6A54015-47EF-4BD8-9E52-64C43107A207.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/74f2cd97-ef40-11d6-42eb-9463e265a10f.jpeg)


デバイスによって背景を切り替える
---

SelectCameraBackground.csを作成する
![B2D8C544-5A8E-4C72-821D-30CE18361563_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/b97216ed-da9b-c8c6-58fe-c5221ce0e2a6.jpeg)

下記スクリプトを記述する

```C#:SelectCameraBackground
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class SelectCameraBackground : MonoBehaviour
{
    [SerializeField]
    private Material ARKitCameraBackground;

    [SerializeField]
    private Material ARCoreCameraBackground;

    private ARCameraBackground m_ARCameraBackground;

    void Awake()
    {
        m_ARCameraBackground = GetComponent<ARCameraBackground>();
        //カメラ背景のカスタムマテリアルを有効にする
        m_ARCameraBackground.useCustomMaterial = true;
# if UNITY_IPHONE
        //カスタムマテリアルにARKIt用のマテリアルをセットする
        m_ARCameraBackground.customMaterial = ARKitCameraBackground;
#elif UNITY_ANDROID
        //カスタムマテリアルにARCore用のマテリアルをセットする
        m_ARCameraBackground.customMaterial = ARCoreCameraBackground;
#endif
    }
}
```

ARCameraにスクリプトをつけ、各マテリアルをアタッチする
![75DB5741-5324-454C-B205-7A0F48A1CB1F.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/2310d8ed-03bd-1102-d7e6-176c344d20cf.jpeg)