LoginSignup
4
5

More than 3 years have passed since last update.

UnityとARkitでVtuberアプリを作ってみた

Last updated at Posted at 2020-02-25

はじめに

最近の流行りのVtuberになれるアプリ作ってみました。

このアプリは2つのアプリから成り立っていて
iPhone側でフェイスキャプチャー用が
PC側(Windows10)でLive2Dの制御用です。


動画左がiPhoneのアプリで、右側がPCアプリです。
※この動画では下のサンプルコードで取得してる部位以外も使用しています。

開発環境

Unity2019.2.15f1
Windows10
iPhoneXR
ios13.3
Mac 10.15.1
Xcode 11.3
ARFoundatinは、Unity公式のGitHubからARFoundationの最新プロジェクトをクローンしてきます。
ARFoundatinリンク
Live2DモデルはCubism3.0桃瀬ひよりを使用しました。

※ARFoundationに関しては自分も勉強途中なので間違っているところもあるかもしれません

iPhone側のアプリについて

今回はARKitFaceBlendShapesのシーンをメインで使っていきます。

iPhone側のアプリで参考にするのはARKitBlendShapeVisualizer.csになります。
今回はこれをもとに改造していきます。

ARKitBlendShapeVisualizerの簡単な説明

ARFaceコンポーネントを取得していて、これを軸に作成されています。
ARFaceは顔情報の更新が検知できるので、ここのupdatedに更新ごとの処理を登録していく形になります。

データの取得

c#ARKitBlendShapeVisualizer.cs

 void UpdateFaceFeatures()
    {
        if (skinnedMeshRenderer == null || !skinnedMeshRenderer.enabled || skinnedMeshRenderer.sharedMesh == null)
        {
            return;
        }  

        using (var blendShapes = m_ARKitFaceSubsystem.GetBlendShapeCoefficients(m_Face.trackableId, Allocator.Temp))
        {
            foreach (var featureCoefficient in blendShapes)
            {
                int mappedBlendShapeIndex;
                if (m_FaceArkitBlendShapeIndexMap.TryGetValue(featureCoefficient.blendShapeLocation, out mappedBlendShapeIndex))
                {
                    if (mappedBlendShapeIndex >= 0)
                    {
                        skinnedMeshRenderer.SetBlendShapeWeight(mappedBlendShapeIndex, featureCoefficient.coefficient * coefficientScale);
                    }
                }
                switch (featureCoefficient.blendShapeLocation)
                {
                    case ARKitBlendShapeLocation.EyeBlinkLeft:
                        motionDate.Leye = featureCoefficient.coefficient;
                        break;
                    case ARKitBlendShapeLocation.EyeBlinkRight:
                        motionDate.Reye = featureCoefficient.coefficient;
                        break;
                    case ARKitBlendShapeLocation.JawOpen:
                        motionDate.Mouth = featureCoefficient.coefficient;
                        break;
                }
            }   
        }
    }

基本的に参考にしているscript内のUpdateFaceFeaturesメソッドで実装されています。

NativeArrayの中に構造体で格納されているので必要な部位のデータだけ
取得します。

foreachを使って構造体ごとに取り出していきます。
部位の選択はstruct内の部位情報と自分の欲しい部位が一致しているかで行っています。
ARKitBlendShapeLocation(enum)で部位指定できます。

switch文部分が追加したコードです

データ格納用クラスを作成し
格納クラス→JSON→byteと変換しPCに送信していきます
送信タイミングは顔データが更新されると送信としました。

送信方法はUDPで実装しています。
PC側が受信、iPhone側で送信で実装しています

よく使われるUDPの通信です。
すでに多くの資料が公開されているので通信部分は省略します。
(UDP C# 実装で検索)

ここからはPC側のアプリについてです

データが受信できたら復元しLive2Dに適用していきます
データを復元したタイミングでnullチェックしておくのがオススメです

モデルへのデータ適用はLive2D公式のドキュメントのパラメーター更新と同じ方法です(ドキュメントリンク)

データ適用時の注意点だけ記述します

  1. 取得したデータは個人差があるので1.0〜0.0でキレイに取得できることは無いです なので各部位ごとに平均最大値と平均最小値を算出し 正規化した数値を適用したほうがきれいに見えると思います
  2. 目の開きのデータはLive2Dと最大最小が逆で取得されるので数値の変換が必要になります
  3. 部位によって最大最小値が異なるのでその対応も必要になります
  4. 純粋なARkitの数値が入っているという感じでない部位がある。

作っている中で躓いたポイントです

Wi-Fiでの通信ができない

PC側でWi-Fiの設定をプライベートに変更
あとはポートの設定も変えとく(windows10 ポート開放で検索)

iPhone側でWi-Fi設定からプロキシ設定を手動
サーバに使用するIPアドレスを
ポートに使用するポート番号を入力して保存

上の設定しても通信ができない

多分ルーターとかのセキュリティ問題 (学校の学科専用Wi-Fiでやったらできなかった)

急に接続が切れた

どうやらiPhoneで残り電池残量等のポップアップが出ると接続が切れるっぽいので再接続

その他

NativeArrayの部分を改造するときは開放処理を忘れずに

NativeArrayは指定したAllocatorのタイプごとに開放処理が必要です
今回は、Tempを指定したので1フレーム以内です!
詳しくは Unity NativeArrayで検索!
(UnityDOTSなどでも使われるので、これからは必須の知識になりそう)

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5