0 と 1

物忘れは防げない

TouchDesigner小ネタ集 01 ~音に反応した表現~

オーディオビジュアルの基本は音ハメ

f:id:gounsx:20180928045648g:plain (音が無いとなにもわからんな・・・)

ということで音に反応するsphereの作り方。

今回使用するOP(オペレーター)

音解析用

  • Audio File In
  • Audio Band
  • Analyze
  • Trigger

おまけ

  • Audio Device Out
  • Audio Spectrum
  • Trail

ネットワーク全体図

f:id:gounsx:20180928044845p:plain

全体の流れ

やりたいこととしては、音源ファイルから曲を再生し、低音域が鳴っている瞬間に3Dモデルのサイズを大きくしてあげたい・・・!

心臓が脈打つような何かが作れます。

音解析用は全て特定の周波数帯の音に反応したものを作るためのOPで、おまけに書かれているものは視覚的にデバッグしやすくするためのOPです。

  1. Audio File Inで音源を再生
  2. Audio Device Outで音が聴こえるように
  3. 音源の周波数を見て、不必要な周波数帯を削りたいのでAudio Spectrumでモニタリング
  4. Audio Bandで不必要な周波数帯を削る
  5. Analyzeで入力信号の最大値を取得
  6. Trigger閾値を設定

不必要な周波数帯を削って低音成分だけ抽出

周波数ですが、ドラムだと大体こんな感じになります。

楽器 中心周波数
バスドラ 80 ~ 100Hz
スネア 800 ~ 1.2kHz
シンバル 220 ~ 12kHz

なので、Audio Bandで100Hz以下を軽く持ち上げてあげて、それ以上の周波数はがっつり削ってあげます。
そうすることでAnalyzeを繋いでキックだけ抽出することができるようになります。

Analyzeは入力信号の最大値を取得するのに使用します。
FunctionをMaximumに設定することで最大値を取得することができます。

今回はTrailから最大値が0から1.5ぐらいを行き来することがわかりました。
なので、TriggerTrigger Thresholdを0.9ぐらいに設定してあげることで低音が強くなった時に値が1を出力するようにします。

ここでコツとして、Attack LengthSustain LevelRelease Levelをを0に設定することで瞬間的に1を出力するようになります。

この辺もTrailを見ながら調整しましょう。

あとはTrailから出力される値をGeometoryのScaleなどに設定してあげれば完成です。
このままだと0から1で値が変動し、3Dモデルが見えなくなる瞬間が出てきてしまうのでお好みでMathRangeで値を0.5から1とかにずらしてあげるといいかもしれません。

ランタイムで環境光の影響を反映させる方法

f:id:gounsx:20180607162417p:plain

キーワード

  • 環境光
  • 環境マップ
  • Cubemap
  • Reflection Probe

skyboxを動的に変更すると見た目がおかしくなる!?

ランタイムでskyboxを変更したところ、環境光が適切に反映されず、一部見た目がおかしい結果となる症状に遭遇しました。

今回はSkyboxによる環境光の影響を適切に反映してあげることで見た目をよくしたいと思います。

Unityにおける環境マップ

UnityではSkyboxにSkybox用のシェーダーを割り当てたマテリアルを設定してあげることで特に追加の設定は必要なく、環境光をオブジェクトに反映させてげることができます。

変化がわかりやすいように新規でStandardShaderを割り当てたマテリアルを作成し、MetallicSmoothness1にしてパチンコ玉のような見た目にします。

f:id:gounsx:20180607163612p:plain

DefaultのSkyboxではこのようにパチンコ玉にSkyboxが映り込んでいるのを確認することができます。

こちらのskyboxを違うskyboxに変更するとこういった結果が得られます。

f:id:gounsx:20180607163944p:plain

これは全天球画像から作られたskyboxで、劇場の椅子がしっかりと映り込んでいます。

このようにEditor停止中では適切な結果を得ることができるのですが、skyboxから行われる環境光の計算はランタイムでは動的に切り替わりません。

youtu.be

このskyboxの切り替え時にどういった処理が走っているかというと、環境マップとしてcubemapの生成を行います。

ランタイムで更新(cubemapの再生成)するにはそれなりのコストがかかるため、エディタ停止中には動作し、ランタイムでは動作しないというのはUnityエディタでそのコストを吸収しているためだと思われます。

試しにLighting ウィンドウのAuto Generateをオフにすると、環境光の影響が反映されなくなります。

そして、その右側にあるGenerate Lightingをクリックすると、シーン名フォルダが生成され、その中にcubemapが生成されます。 つまりこれをEditor停止中に内部的に生成しているということです。

この時生成したcubemapをskybox変更時にEnviroment ReflectionsSourceCustomに変更し、設定することで環境光の影響を受けるようにすることができます。

動的にcubemapを生成し、環境光の影響を適切に反映されるようにするには

今回はskybox変更時に、cubemapを生成し環境マップとして設定してあげる方向で修正を行いたいと思います。

cube mapの生成するにはいくつかの方法があります。

1つ目は、Reflection Probeを配置する。2つ目は、Camera.RenderToCubemap()を使用する方法です。

Reflection Probe

前者は非常に簡単でHierarchyからCreateLightReflection Probeと選択し、シーンに配置するだけです。

いくつかパラメータがあるのですが、TypeRealtimeReflesh ModeEvery frameにするとマイフレーム更新することができます。

f:id:gounsx:20180608181425p:plain

マイフレームではかなりのコストがかかるので、ReflectionProbe.RenderProbe()を呼ぶことで任意のタイミングで更新をかけることができます。

Camera.RenderToCubemap()

こちらはスクリプトを作成する必要があります。

参考までにcube mapを生成するスクリプト、生成したcube mapを設定するスクリプトを載せておきます。

RenderCubemap.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RenderCubemap : MonoBehaviour
{
    static public Cubemap Generate()
    {
        GameObject cubeMapCamera = new GameObject("CubemapCamera");
        Cubemap cubemap = new Cubemap(64, TextureFormat.RGBA32, true);
        var camera = cubeMapCamera.AddComponent<Camera>();
        cubeMapCamera.transform.position = Vector3.zero;
        cubeMapCamera.transform.rotation = Quaternion.identity;
        int layerMask = 0;
        camera.cullingMask = layerMask;
        camera.allowHDR = true;
        camera.RenderToCubemap(cubemap);
        DestroyImmediate(cubeMapCamera);
        RenderSettings.defaultReflectionMode = UnityEngine.Rendering.DefaultReflectionMode.Custom;
        RenderSettings.customReflection = cubemap;

        return cubemap;
    }
}

CubemapTester.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CubemapTester : MonoBehaviour
{
    [ContextMenu("Change Cubemap")]
    public void ChangeCubemap()
    {
        RenderSettings.defaultReflectionMode = UnityEngine.Rendering.DefaultReflectionMode.Custom;
        RenderSettings.customReflection = RenderCubemap.Generate();
    }
}

使い方はCubemapTester.csのChangeCubemap()を実行します。

f:id:gounsx:20180608181122p:plain

このように、Reflection ProbeもしくはCamera.RenderToCubemap()を使用し、任意のタイミングで更新をかけてあげることで動的に環境光を反映させることができるようになりました。

まとめ

cubemapの解像度や、HDRの有効無効の設定が異なるので上記の2つの方法での結果が少しずつことなっていますが、自分のプロジェクトに最適な方法を使用することをお勧めします。

見た目にかかわる部分なので、各種パラメータいじってみて理想の絵作りを追及してください!

UnityでglTFを使用する方法

f:id:gounsx:20180601192631p:plain

3Dモデルデータを用意

今回は検証用に3Dスキャナーでスキャンしたobjデータを用意。
フォルダの中には3つのファイルがあります。

- mesh.obj (3Dモデルデータ)
- mesh.mtl (マテリアルデータ)
- material0_basecolor.jpg (テクスチャデータ)

f:id:gounsx:20180601192816p:plain

Blenderの下準備

KhronosGroup製のglTF-Blender-Exporterレポジトリをダウンロードします。

github.com

\glTF-Blender-Exporter-master\scripts\addons\io_scene_gltf2Blenderアドオンディレクトに追加します。

BlenderのアドオンディレクトリはWindowsならC:\Program Files\Blender Foundation\Blender\2.79(バージョン番号)\scripts\addonsにあります。

次にBlenderを開き、アドオンを有効にします。
FileUser Preferencesと進み、Add-onsタブを選択後、検索窓に「gltf」と入力するとimport-Export: glTF 2.0 formatが出てくるので有効にします。
さらにEnable experimental glTF export settingsも有効にします。

f:id:gounsx:20180601194427p:plain f:id:gounsx:20180601194543p:plain

Blenderにobjデータをインポート

Blenderにobjデータをインポートします。

FileImportobjと進み、先ほどのobjデータを選択します。
真っ白な状態でインポートされました。
これからShaderの設定を行います。
f:id:gounsx:20180601195005p:plain

「glTF Metallic Roughness」シェーダーをリンクします。

FileLinkと進み、先ほどのglTF-Blender-Exporter-master内にあるglTF-Blender-Exporter-master\pbr_node\glTF2.blend\NodeTree\glTF Metallic Roughnessを選択します。

f:id:gounsx:20180601195730p:plain

これで「glTF Metallic Roughness」シェーダーが使用可能になります。

シェーダーの設定の前にレンダリングエンジンをCycles Renderに変更します。

f:id:gounsx:20180601200138p:plain

その後、MateriaのついているMeshを選択し、Materialの設定変更を行います。

f:id:gounsx:20180601200406p:plain

SurfaceからUse Nodesをクリックしたら、「glTF Metallic Roughness」シェーダーを選択します。

f:id:gounsx:20180601200719p:plain f:id:gounsx:20180601200733p:plain

設定項目の中からBase ColorImage Textureと進み、テクスチャファイルを選択します。

ここまで設定しても見た目は変わりませんが、ここで3Dモデルの表示モードをTextureに切り替えることで適切に設定されていることを確認することができます。

f:id:gounsx:20180601201046p:plain

glTF形式で出力

最後にglTF形式での出力を行います。
FileExportと進み、任意のディレクトを選択します。

f:id:gounsx:20180601203912p:plain

出力されたデータを見てみると、3つのデータから構成されていることがわかります。

- TestGLTF.gltf (glTFデータ)
- TestGLTF.bin (頂点データ)
- material0_basecolor.jpg (テクスチャデータ)

f:id:gounsx:20180601201631p:plain

Blenderでの作業はこれで以上です。

UnityでglTFファイルを読み込む

Unityを開き、Asset StoreからSktechfab for Unityをインポートします。

f:id:gounsx:20180601202144p:plain

もしくはsketchfabのUnityGLTFレポジトリからunitypackage形式でインストールすることも可能です。

github.com

インポートに成功すると‘Sketchfab‘タブが表示されるのでImport glTFを選択するとglTF Importerが表示されます。

Import file from diskをクリックし、先ほどのglTFファイルを選択後Importボタンをクリックすることで処理が始まります。

f:id:gounsx:20180601202951p:plain

少し待ってシーン上に3Dモデルが表示されれば成功です。

f:id:gounsx:20180601203231p:plain

作品アーカイブ

2015

Spatial Jockey

f:id:gounsx:20180505190619j:plain

vimeo.com

音楽に合わせて空間をリアルタイムに制御するHMD使用ソフト。
MIDIコントローラーを使用し、ジョッキーがリアルタイムで空間をコントロール
ローカルネットワークを構築し、複数台のHMDとの同期が可能です。
HMD装着者は音楽に合わせて変化する空間に身をゆだねる。


NOWHERE TEMPLE beta

f:id:gounsx:20180505191309j:plain f:id:gounsx:20180505191352j:plain

「Spatial Jockey」をプラットフォームに、現代オカルティズム研究者バンギ・アブドゥル氏とのコラボレーション作品。
HMDを使用し、実践魔術の儀式空間(Astral plane)と変性意識を体験するプログラム「NOWHERE TEMPLE beta」のデモンストレーションを行いました。

  • Oculus DK2
  • Unity

映像作家udocorg (鵜戸庚司) 個展「れいより40℃も高熱」360°映像コンテンツ

f:id:gounsx:20180505192605j:plain

個展開始直後に会場で360度動画の撮影を行い、スティッチ加工、編集を行いました。

  • QBiC MS-1 × 4台 (360度カメラ)
  • Gear VR

「ISLAND IS ISLANDS」 VRコンテンツ

f:id:gounsx:20180505193811j:plain f:id:gounsx:20180505193858j:plain

ファッションデザイナー・中里周子×写真家・小林健太による二人展「ISLAND IS ISLANDS」VRコンテンツ作成。
オブジェクトの3Dモデル作成にPhoto Scanの技術を使用。

  • Photo Scan
  • Oculus DK2
  • Unity

近距離通信アプリ 「AirMeet」

f:id:gounsx:20180505200946j:plain www.youtube.com

JPHACKS 2015応募作品
IBM賞受賞

2015.jphacks.com

  • iBeacon通信
  • node.js
  • Swift

2016

「ようこそ、ISETAN宇宙支店へ ~わたしたちの未来の百貨店~」VRコンテンツ

f:id:gounsx:20180505194250j:plain f:id:gounsx:20180505194258j:plain f:id:gounsx:20180505194309j:plain

ファッションブランド『ノリコナカザト』の伊勢丹TOKYO解放区企画店でのVRコンテンツ作成。

  • Oculus DK2
  • Unity

2017

ドット絵アーティスト・タカクラカズキ個展『有無ヴェルト』VRコンテンツ

f:id:gounsx:20180505194616p:plain

  • Vive Tracker × 2台
  • HTC Vive
  • Unity

chloma × STYLY HMD collection 展示/販売会 『chloma OS Umwelt』MRコンテンツ

f:id:gounsx:20180505194923p:plain www.youtube.com


2018

Microsoft HoloLensアプリケーション 「chloma x STYLY HMD collection」

f:id:gounsx:20180505195144j:plain

www.microsoft.com


Daydreamアプリケーション 「Nyoro The Snake & Seven Island」

www.youtube.com f:id:gounsx:20180505195604j:plain

  • Daydream
  • Unity

VTuber バートン

f:id:gounsx:20180505195853j:plain

www.youtube.com

第1回VTuberハッカソン応募作品
HTC VIVE賞受賞 panora.tokyo


Faceモデル作成アプリ (制作中)

f:id:gounsx:20180505200245p:plain

  • iPhoneX
  • Unity

リアルタイムIBLでARを現実空間に馴染ませる

f:id:gounsx:20180426144337p:plain

IBLとは

Image based lighting (イメージ・ベースド・ライティング)

画像から照明条件を算出して、ライティングを行う技術です。
2000年前後に登場した技術で、映画製作にも使われ、実写合成ではミラーボールを使用して高精細な全天球画像を作成します。
Unity5はBeastからEnlightenに移行したため、簡単にIBLを設定できるようになりました。

cgworld.jp

IBLの設定方法

Editor上のWindow -> Lighting -> Settingsから設定することができます。
Skybox Materialを変更するだけです。 これでSkyboxが環境光に影響を与えるようになります。

f:id:gounsx:20180425122106p:plain

試しに高精細なHDR全天球画像を配布しているHDR LabssIBL Archiveを使ってみます。

  1. Texture Shapeを2DからCubeに変更
  2. Create -> Materialを作成
  3. ShaderをSkybox/Cubemapに変更
  4. 1で変更したTextureをMaterialに設定
  5. LigtingのSettingsウィンドウのSkybox Materialに設定

結果

f:id:gounsx:20180425122931p:plain

このように、先程のSphereと比べて赤みがかった色合いになりました。
SkyboxのCubemapとして使用した画像が影響しているのがわかります。

f:id:gounsx:20180425123326j:plain

また、SphereのMaterial設定をMetalicを1、Smoothnessを1にすることでSkyboxの映り込みを確認することができます。  

f:id:gounsx:20180425123816p:plain

ARKit x IBL

さて、ここまではIBLの説明でしたが、「IBLとARKitを組み合わせて実在感をアップさせよう!」というのが今回の主題です。
現状のARコンテンツの大きな特徴は「キャラクターの実在感」だと個人的には考えています。
今までは平面ディスプレイ越しに接してきたキャラクターが、自分のいる現実世界に存在する、自分の机の上で踊っている・・・

しかし、ただそのまま現実空間に3Dモデルを表示するだけだと、3Dモデルが馴染まずにパキッった見え方になってしまいます。 そこで、今回はIBLを使用することで現実空間のライト状況を3Dモデルに反映し、キャラクターをより現実に溶け込ませてあげましょう。

大まかな流れ

  1. 現実世界の明るさに合わせて、Unity空間の明るさを調整
  2. カメラでキャプチャーした画像を基にIBLを行い、色合いの調整
  3. キャラクターが現実に馴染む!実在感が増す!

明るさ

ARKitにはUnityARAmbientというコンポーネントが用意されています。
これを使うことでカメラ越しに捉えた現実の明るさを基にUnity空間に存在するDirectional Lightのintensityを調整してくれます。
Lightコンポーネントが付いているGameObjectにアタッチするだけなので別途実装の必要はありません。

色合い (IBL)

では、先程説明したIBLをARKitと組み合わせて使用したいと思います。
先に大まかな実装の流れを説明すると

  1. UnityARVideoコンポーネントが取得しているyCbCrのテクスチャを取得する
  2. 変換行列を用いてRGBに変換する (先程の説明で言う所のダウンロードしてきたHDR画像)
  3. 極座標変換を行い、Skyboxに設定する (IBL)

注意!

今回実装するIBLはあくまで擬似的なものです。
というのも端末のカメラで取得できるイメージは単眼カメラで撮影したもので、そこからSkyboxを生成するというのは実際不可能だからです。
なんとなく現実空間の色合いをキャラクターに反映させたいというのが目標なのでカメラで撮影した画像に極座標変換を行うことで無理やり全天球画像にしてしまいます。

カメラで撮影した画像の取得

ARFakeIBL.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.iOS;

public class ARFakeIBL : MonoBehaviour
{
    [SerializeField]
    // ARKitで用意されているYUVMaterialを設定
    private Material _yuvMat;

    [SerializeField]
    // 疑似IBLスカイボックス用マテリアルとして使用
    private Material _yuvSkyboxMat;

    [SerializeField]
    private int _frameInterval;

    private int _frameCount;

    void Update()
    {
        if (_frameCount == _frameInterval)
        {
            Texture textureY = _yuvMat.GetTexture("_textureY");
            Texture textureCbCr = _yuvMat.GetTexture("_textureCbCr");

            _yuvSkyboxMat.SetTexture("_TextureY", textureY);
            _yuvSkyboxMat.SetTexture("_TextureCbCr", textureCbCr);

            DynamicGI.UpdateEnvironment();

            _frameCount = 0;
        }
        else
        {
            _frameCount++;
        }
    }
}

ARFakeIBLスクリプトを適当なGameObjectにアタッチします。
このスクリプトはARKitで使用しているYUVMaterialが持つyCbCRのテクスチャを今回自作するSkybox用シェーダーに受け渡しする役割を持ちます。
yuvSkyboxMatには後で説明するIBLSkyboxシェーダーから作成したマテリアルを設定してください。 Update内で処理は行っていますが、負荷との相談でframeIntervalを20ぐらいに設定しておくと良いと思います。

IBL用Skyboxシェーダー

IBLSkybox.shader

Shader "Skybox/IBLSkybox"
{
    Properties
    {
        _TextureY("TextureY", 2D) = "white" {}
        _TextureCbCr("TextureCbCr", 2D) = "black" {}
    }

    SubShader
    {
        Tags { "RenderType"="Background" "Queue"="Background" }

        Pass
        {
            ZWrite Off
            Cull Off
            Fog { Mode Off }

            CGPROGRAM
            #pragma fragmentoption ARB_precision_hint_fastest
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            #define PI 3.141592653589793

            struct appdata
            {
                float4 position : POSITION;
                float3 texcoord : TEXCOORD0;
            };
            
            struct v2f
            {
                float4 position : SV_POSITION;
                float3 texcoord : TEXCOORD0;
            };

            sampler2D _TextureY;
            sampler2D _TextureCbCr;

            static 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)
                ); 

            inline float2 ToRadialCoords(float3 coords)
            {
                float3 normalizedCoords = normalize(coords);
                float latitude = acos(normalizedCoords.y);
                float longitude = atan2(normalizedCoords.z, normalizedCoords.x);
                float2 sphereCoords = float2(longitude, latitude) * float2(0.5/UNITY_PI, 1.0/UNITY_PI);
                return float2(0.5,1.0) - sphereCoords;
            }
            
            v2f vert (appdata v)
            {
                v2f o;
                o.position = UnityObjectToClipPos (v.position);
                o.texcoord = v.texcoord;
                return o;
            }
            
            half4 frag (v2f i) : COLOR
            {
                float2 uv = ToRadialCoords(i.texcoord);

                float y = tex2D(_TextureY, uv).r;
                float4 ycbcr = float4(y, tex2D(_TextureCbCr, uv).rg, 1.0);


                return mul(ycbcrToRGBTransform, ycbcr);
            }

            ENDCG
        }
    } 
}

ToRadialCoords関数でuv座標を極座標変換しています。
この関数自体はビルトインシェーダーのSkybox/Panoramicの中で行われている変換処理と同一のものです。
そして、変換された座標からyCbCrテクスチャ上の色をフェッチし、RGBに変換して返すといったシンプルなシェーダーになっています。
RGBに変換するための行列ですが、一般的に使用されるyCbCr → RGB変換のための値ではうまくいきませんでした。
なので素直にARKitで用意されているUnlit/ARCameraShader内に記述されている変換行列をそのまま使用しています。

最後にこのシェーダーから作成したマテリアルをLigting/SettingsウィンドウのSkybox Materialに設定します。

結果

youtu.be

youtu.be

現実の状況を3Dモデルに反映することで、そのキャラクターがよりその場に存在する実在感が生まれました。

How to fix Unity ARKit Remote


この記事は

zeroichi.hatenablog.jp

を英語での解説が欲しいとリクエストがあったので英語でまとめたものです。
要点だけまとめてあるので、詳しい解説はリンク先のものを見てください。


f:id:gounsx:20180403163958j:plain

It does not work properly!

www.youtube.com

What is wrong?

f:id:gounsx:20180403163746p:plain

Since the data transmitted can not be handled on the receiving side, the sending side can not send it!

This problem occurs because iPhoneX has a high resolution.

f:id:gounsx:20180404124240p:plain

How to fix

Using the MemoryStream, compress the data by DeflateStream before sending it on the sending side.

The point is, ...

  1. Compress the data on the data sending side .
  2. Decompress the data on the data receiving side.

Compress & Decompress

    /// <summary>
    /// Compress using deflate.
    /// </summary>
    /// <returns>The byte compress.</returns>
    /// <param name="source">Source.</param>
    public static byte[] ConvertByteCompress(byte[] source)
    {
        using (MemoryStream ms = new MemoryStream())
        using (DeflateStream compressedDStream = new DeflateStream(ms, CompressionMode.Compress, true))
        {
            compressedDStream.Write(source, 0, source.Length);

            compressedDStream.Close();

            byte[] destination = ms.ToArray();

            Debug.Log(source.Length.ToString() + " vs " + ms.Length.ToString());

            return destination;
        }
    }

    /// <summary>
    /// Decompress using deflate.
    /// </summary>
    /// <returns>The byte decompress.</returns>
    /// <param name="source">Source.</param>
    public static byte[] ConvertByteDecompress(byte[] source)
    {
        using (MemoryStream input = new MemoryStream(source))
        using (MemoryStream output = new MemoryStream())
        using (DeflateStream decompressedDstream = new DeflateStream(input, CompressionMode.Decompress))
        {
            decompressedDstream.CopyTo(output);

            byte[] destination = output.ToArray();

            Debug.Log("Decompress Size : " + output.Length);

            return destination;
        }
    }

How to use

UnityRemoteVideo.cs

public void OnPreRender()
        {
            ~ abridgement ~

            //connectToEditor.SendToEditor (ConnectionMessageIds.screenCaptureYMsgId, YByteArrayForFrame(1-currentFrameIndex));
            connectToEditor.SendToEditor(ConnectionMessageIds.screenCaptureYMsgId, ByteConverter.ConvertByteCompress(YByteArrayForFrame(1 - currentFrameIndex)));

            //connectToEditor.SendToEditor (ConnectionMessageIds.screenCaptureUVMsgId, UVByteArrayForFrame(1-currentFrameIndex));
            connectToEditor.SendToEditor(ConnectionMessageIds.screenCaptureUVMsgId, ByteConverter.ConvertByteCompress(UVByteArrayForFrame(1 - currentFrameIndex)));
            
        }

ARKitRemoteConnection.cs

void ReceiveRemoteScreenYTex(MessageEventArgs mea)
        {
            if (!bTexturesInitialized)
                return;

            //remoteScreenYTex.LoadRawTextureData(mea.data);
            remoteScreenYTex.LoadRawTextureData(ByteConverter.ConvertByteDecompress(mea.data));
            remoteScreenYTex.Apply ();
            UnityARVideo arVideo = Camera.main.GetComponent<UnityARVideo>();
            if (arVideo) {
                arVideo.SetYTexure(remoteScreenYTex);
            }

        }

        void ReceiveRemoteScreenUVTex(MessageEventArgs mea)
        {
            if (!bTexturesInitialized)
                return;
 
            //remoteScreenUVTex.LoadRawTextureData(mea.data);
            remoteScreenUVTex.LoadRawTextureData(ByteConverter.ConvertByteDecompress(mea.data));
            remoteScreenUVTex.Apply ();
            UnityARVideo arVideo = Camera.main.GetComponent<UnityARVideo>();
            if (arVideo) {
                arVideo.SetUVTexure(remoteScreenUVTex);
            }

        }

UnityRemoteVideo.cs and ARKitRemoteConnection.cs are scripts prepared beforehand by Unity ARKit Plugin.

The compression & expansion processing is the script that I created this time.

Caution!

In order to use CopyTo method of DeflateStream class I am using .NET Framework 4.6 instead of .NET Framework 3.5.

Building the Unity ARKit Remote scene uses .NET Framework 3.5. Please change to .NET Framework 4.6 after building and run Editor.

Run

www.youtube.com

You are now able to use it successfully.

If there is something you do not understand please comment:)

twitter.com