Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What is going on with this article?
@nari-nari

Kinectを使って身振り手振りもできるバーチャル美少女おぢさんになる

Kinectを使って身振り手振りもできるバーチャル美少女おぢさんになる

※かなりゆるい記事になるので肩の力を抜いて読んでもらえるとです
※Windows向けの内容になります

きっかけ

2月下旬にコロナにより、在宅勤務による移行が行われました。
現在まで続いており、仕事自体は快適にできております。
ゲーム会社で働く社員としては、やはり遊び心がほしいところです。
なので早いうちにビデオ通話にバ美肉にをしたいと考えました。
バ美肉やりたかったのは女の子になりたいなんとなくです。
はい、きっかけなんて些細なものです。

最初にやったこと

最初はスマホのフェイストラッキングアプリを使いました。
自分もiPhoneXを持ってるので
背景をグリーンスクリーンにしてOBSで合成して作業しました。
最初試してたのは以下の2つ
カスタムキャスト
Reality
他にもたくさんありましたが
Realityの見た目が好みだったのでしばらく使ってました。
babi.gif
画像の感じで6月ぐらいまで毎日を過ごしてました

ただ、やはり物足りない・・・
顔だけでも表情や視線などあって十分だと思ったのですが
やはり身振り手振りしたいです。
ということで自前で作ろうとなりますた。

全身トラッキングしたい

自前で作る上で必要になるものは以下の物が必要だなと考えました。

  • 全身をトラッキングするデバイス
  • 3Dモデル
  • 制御するソフト

ソフトはとりあえずUnityでやろうと考えて
後は、とりあえずそれぞれどうするか調査していきました。

全身をトラッキングするデバイス

ちょうどお家にKinect v2があったのでこれを利用しようと思いました。
Kinect for Windows v2なので現在は販売停止してますが多分皆さんのご家庭にも一台必ずあると思うので問題ないはず
もしなかったら代わりにAzure KinectDKが後継機でありますがSDK周りがKinectV2と異なるので今回やるバ美肉のやり方を流用できないかもしれないので注意です。
ちょい値段もv2より上がってるので自分はDKでなくなったら買おうかなと思ってます。

Kinect for Windows v2はSDKがあるので利用する前にSDKも入れます

3Dモデル

せっかく美少女になるので見た目の可愛い子を選びました。
スノウエルフお嬢様が可愛かったのでこの娘にしました。
有料ですが可愛かったので後悔してないです。
ファイル形式はunitypackageとfbxだったので取り込みやすかったです。

8月ぐらいまでの利用してましたがだんだんと
自分でデザインしたい
欲が出てきて自分で見た目も作りたくなりました。
VRoid Studioがすごい使いやすくて
こちらを利用することにしました。

見た目を変えるのに以下のデータを購入して活用させていただきました。
【VRoid】ビビ セルルックアニメ風改変モデル
【VRoid】クロップドパーカーセット【セルルック対応】

髪型もJsonで管理されてるのでツール利用して複数の髪型を合成しました。
こちらはエクスポートしたVRMモデルを扱いました。
VRMをUnityで使う際には変換する必要があります。
こちらもめちゃくちゃ便利なUniVRMがあるのでこちらを使ました。

制御するソフト

ソフトはUnityで作ります。
バージョンは2019.4.7f1です。
ローコストで片手間な感じで作りたいので以下のアセットを購入しました。
Kinect v2 Examples with MS-SDK

もし1から制作したい場合はこちらの記事を参考にしてもらえるとです。

今回は上記のアセットを元に改変/拡張して進めました。

簡単な流れと注意点を以下書いていきます。
モデルはVRoid Studioで作ったVRMデータを使います。
モデルの作り方とかはググってください。
デフォルトのモデルもかなり可愛いのでそのままエクスポートしてもいいかもです。
UniVRMも入れておきます。

VRoidStudioでエクスポートしたモデルをUnityProjectドラッグ・アンド・ドロップします。
image.png

するとVRMのモデルがprefabとしてインポートされるので
シーンに配置します。
image.png

そしてインポートしたデータにAvatarControllerを配置します。
image.png

続いてKinectControllerという空オブジェクトを作ります。
KinectManager/KinectGestures/FacetrackingMangerを入れます。
image.png

これで再生すると動きます。
babi4.gif

カメラを調整してSkyboxをGreenにすれば出来上がり!
おわり!
・・・嘘です。もうちょっとだけやります。

このままだと足がプルプルしてしまいますので
足回りのトラッキングだけ除外します。

以下のファイルの533行目に入れると足のトラッキングを停止させられます。

AvatorController.cs
                if (joint == KinectInterop.JointType.HipLeft || joint == KinectInterop.JointType.HipRight ||
                    joint == KinectInterop.JointType.KneeLeft || joint == KinectInterop.JointType.KneeRight ||
                    joint == KinectInterop.JointType.FootLeft || joint == KinectInterop.JointType.FootRight)
                {
                    continue;
                }

babi5.gif

コードを入れるとこんな感じでトラッキングしなくなると思います。

続いて表情がないと思います。
これも簡単に口パクを実装しましょう。
BlendShapeFaceController.csがあるのでこれベースに
VRMのモーフに置き換えと必要なもの最小限に置き換えておきます。

FaceController.cs
using UnityEngine;

public class FaceController : MonoBehaviour 
{

    public SkinnedMeshRenderer faceMesh;

    private FacetrackingManager manager;
    private int jaw;
    private int eyeLeft;
    private int eyeRight;

    string Prefix = "Face.M_F00_000_00_Fcl_";

    void Start()
    {
        jaw = faceMesh.sharedMesh.GetBlendShapeIndex(Prefix+"MTH_Joy");
        eyeLeft = faceMesh.sharedMesh.GetBlendShapeIndex(Prefix+"EYE_Joy_L");
        eyeRight = faceMesh.sharedMesh.GetBlendShapeIndex(Prefix+"EYE_Joy_R");

    }

    void Update() 
    {
        // get the face-tracking manager instance
        if(manager == null)
        {
            manager = FacetrackingManager.Instance;
        }

        if(manager && manager.GetFaceTrackingID() != 0)
        {
            // AU1 - Jaw Lowerer
            // 0=closed; 1=fully open; -1= closed, like 0
            float fAU1 = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.JawOpen);
            fAU1 *= 200;
            faceMesh.SetBlendShapeWeight(jaw, Mathf.Clamp(fAU1,0,70));

            // AU6, AU7 – Eyelid closed
            // 0=neutral; -1=raised; +1=fully lowered
            float fAU6_left = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LefteyeClosed);
            fAU6_left = fAU6_left <= 0.3f ? 0 : fAU6_left;
            fAU6_left = fAU6_left >= 0.55f ? 1 : fAU6_left;
            fAU6_left *= 100;

            float fAU6_right = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.RighteyeClosed);
            fAU6_right = fAU6_right <= 0.3f ? 0 : fAU6_left;
            fAU6_right = fAU6_right >= 0.55f ? 1 : fAU6_left;
            fAU6_right *= 100;
            faceMesh.SetBlendShapeWeight(eyeLeft, Mathf.Min(Mathf.Clamp(fAU6_right,0,100),Mathf.Clamp(fAU6_left,0,100)));
            faceMesh.SetBlendShapeWeight(eyeRight, Mathf.Min(Mathf.Clamp(fAU6_right,0,100),Mathf.Clamp(fAU6_left,0,100)));

        }
    }

}


上記のスクリプトを配置してるVRMに貼り付けるとトラッキングするようになります。
babi6.gif

これでリリースビルドにしてバイナリを作って
OBSでキャプチャすれば完成です!

最後に音声も認識したいので実装しました。
OVRLipsyncを利用して実装しました。
こちらの記事を参考に実装を進めました
こちらも合わせるとかなり複雑な口の動きが再現できるようになります。

また瞬きはランダムで瞬くようにしました。
こちらの記事のものを利用させていただきてます。

最後に

プレゼンするときはOBSも駆使してこんな感じで現在やってます。
ただこれは特別な場のときのみですね。
babi3.gif

発表中にこんな感じでKinectのハンドトラッキングでものを握って説明したこともありました。
babi8.gif

普段のビデオ通話ではこんな感じでラフになってます。
背景は自分の部屋を撮影してバーチャル背景にしてます。

babi2.gif

他にもトラッキングができなくなったら
離席で扱うようにして離席時をわかりやすくしました。
ただ冬になってから椅子にかけてるコートが誤認されてるようで
動作しないときがちょいちょいあります。
特にコートや洗濯物は誤動作不可避のようで人物がいてもよく誤認されてしまいます。
babi7.gif

以上になりますが
みなさんも良い美少女ライフを送ってもらえるとです!

4
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
4
Help us understand the problem. What is going on with this article?