VTuberオタク大学生がKinect v2で美少女アバターを動かすために1年間やったこと

この記事は、[VTuber Tech #1 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/vtuber)の20日目の記事です。

昨日は @iwaken71 さんによる[VTuber尊い...なんで？と思いVirtual Beingについてサーベイした話](https://qiita.com/iwaken71/items/73da405cc34e116ceb7a)という記事でした！

## はじめに

どうも、にー兄さんと申します。VTuberTechアドカレということで記事を執筆させていただきます。
自分は普段xRやHumanoidアバター制御、CGなどの領域で個人開発をしている大学2年生でして、メインで進めているプロジェクトとして汎用モーキャプシステムの開発を(のびのびと)やっています。このプロジェクト自体は、もともと4月から始めていた「ARアバター配信システム」の機能の一部として開発していたものです。下のツイートが進捗っぽいものになります。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">個人開発しているARライブ配信システムのプロトタイプができました！<br>Kinect v2 配信ホスト⇒リアルタイムSocket鯖⇒AR視聴クライアント<br>でまぁまぁVRMモデルにリアルタイムで反映できてるみたいです。<br>KinectJoint→HumanoidBodyBoneがまだまだなので調整したいと思います。 <a href="https://t.co/mU3IsLYKt3">pic.twitter.com/mU3IsLYKt3</a></p>&mdash; にー兄さん@3DSensorとVTuberTechアドカレ執筆中 (@ninisan_drumath) <a href="https://twitter.com/ninisan_drumath/status/1154655089052663808?ref_src=twsrc%5Etfw">July 26, 2019</a></blockquote>

見て頂ければわかると思うのですが、 **モーションキャプチャがお粗末すぎる** んですよねぇ。どうにかしたいと思い試行錯誤している間に、モーキャプシステム開発にのめりこんでしまい、今に至ります。今回は、そんな感じで自分が試行錯誤した結果や実装した機能などを紹介したいと思います。
最後までお付き合いいただけたら光栄です。

### この記事について

前述した通り、この記事ではARアプリの一部として開発していたモーションキャプチャの実装についての記事になります。開発にはUnityを使いまずが、本記事ではUnityの基本的な使い方などは解説しませんので悪しからず。
この記事を読むことによって「どのようにモーションキャプチャを開発したらいいのか」や「モーションキャプチャに必要な技術」などの知見を得ることができます。とはいえ趣味で個人開発したものから得られた知見なので、間違っている部分やもっと効率的なやり方があるかもしれませんので、そのような時にはコメントなどでリアクションいただけると私が泣いて喜びます。また、この記事の内容と、来年2/29,3/1に行われる技術書典8で頒布する同人誌の内容に共通する内容が含まれるため、あまり具体的な内容に触れられないところもあります、ご了承ください。技術的な文献というより読み物に近い形になるかと思います。あと焦って書いたのですごい見にくい気がします...文才がないなりにそこも改善していくので、言い回し等が変更される可能性があります。

そして重要な点なのですが、記事の内容がまだ完成しておりません汗(2019年12月現在 「システムのを設計する」の章未完)。内容は告知なく変更になりますので、なにとぞご容赦ください。(ストックしていただければ変更通知を送り致します)

## バーチャル美少女受肉を実現するには

俗にいう”バ美肉”をするにはいくつか必要な工程があります。その中でもよくつかわれる技術として「声質変換」と「モーションキャプチャ」について簡単な説明をします。

### 声質変換

よくボイチェンといわれ、自分の声を演じたいキャラクターの声に寄せるためにピッチを調整したりイコライジングしたりする作業のことです。多くの場合、男声から女声への変換が使われ、そのためのソフトが有料のものも無料のものも多く配布されています。配信で声質変換をするには、マイクで拾った自分の声を仮想の音声デバイスに入力し、それを受け取ったソフトが配信ソフトに流すというフローが一般的です。
本記事では声質変換を扱うことはないですが、バ美肉をするにあたって多くの人が利用している技術ですので自分も興味があります。

### モーションキャプチャ

モーションキャプチャ(以下モーキャプ)とは字の通り、自分の動きをコンピュータで再現するための技術です。一口にモーキャプといっても、上半身だけの場合だったりフルボディ(全身)の場合があったり、頭だけだったりと色々あり、それぞれ実現するために必要な技術力やデバイスが異なります。例えば上半身だけの場合、HMDとVRコントローラなどで実現することが多いですね。OculusQuestやViveFocus、Windows Mixed Realityなどの製品を用いる場合がいい例ですね。また、頭だけのトラッキングの場合はスマホ単体で完結します。ただその場合、インカメラを使って行うことが多いので、フェイストラッキングと併用されることが常です。REALITYやSHOWROOM V などのVアバター配信で多く見受けられるパターンといえます。本記事で扱う全身のモーキャプでは、必要な機材やスキルが高くなりがちです。自分は金欠学生なので高い機材が買えないので、居候している研究室からKinect v2というデバイスをお借りしました。

## 使用したデバイス・開発環境

### Kinectについて

　Kinectとはマイクロソフトが開発しているセンサーデバイスのことです。このデバイスを用いることによって一般のカメラのようにRGBイメージを取得したり、赤外線カメラによるデプスイメージを取得したりできます。また、BodyTrackingAPIを使うことによって、カメラに写っている人を感知し、その人の姿勢を推定することができます。
　つまり、このデバイスを使えば非接触型のフルトラッキングを実現することができるのです。フルトラッキングといえば、ViveトラッカーやPerceptionNueronなどのデバイスや、もっと高価なものだとOptiTrackやVICONのような光学式モーションキャプチャデバイスを思い浮かべる方も多いのではないでしょうか？Kinectではこれらよりも比較的安価にフルトラッキングを実現できます。
　今回私が使っているのはKinect v2というデバイスで2014年に発売されていますが、今ではサポートが終わってしまっているデバイスです。代わりに最近AzureKinectというデバイスがリリースされ、日本での発売も予定されています。余談なのですが、以前TMCNさんが主催するイベントでKinectのバージョンについてのお話を聞いたところによると、HoloLensは実はKinect v3という扱いになっており、今回のAzureKinectはv4という位置づけらしいですね。

### Unityでアバター制御をする

　フルトラッキングでモーキャプシステムを作るためには、トラッキングしたボーンのデータをキャラクターに反映する必要があります。私のプロジェクトはUnityで開発をしているのですが、その理由として3Dモデル特にキャラクターの扱いが楽だからです。
　では実際にUnityでキャラクターを動かすためにはどうすればいいのでしょうか？パッと思いつく限りだと以下のようなものが思い当たります。

- FinalIK(VRIK)
- Mecanim
- Animation Riging

　FinalIKとは様々なIK(詳しくは後述)処理が簡単に実装できる有料アセットです。VRChatの住人の方やほかのモーキャプシステムでも広く使われているので、アバターを動的に動かすスタンダードな手段といえるでしょう。したがってFinalIKを使うことは”無難”に”高品質”な結果が得られますし、ドキュメントも豊富です。ただ私のプロジェクトでは2つ目のMecanimを使いました。FinalIKを使わなかった理由として以下のようなことが挙げられます。

- 高い(個人の意見です)
- 高機能すぎて使い切らなそう
- OSSとして公開したかった

　まず、1つ目の高いことに関してはたぶん思っているのは自分だけです(それも言い過ぎ)。というのも、そもそもVR機器自体が高いので「VRをやりたい！」と思う人はある程度高い出費を覚悟のうえな場合が多いので、必須アセットといっても過言でないFinalIKを高いとは言っていられないのではないでしょうか？ただ自分には覚悟が足りないため高く感じました。それに加えて2つ目ですが、実際自分が使いたいのは腕や足のボーン制御(2ボーン制御)だったので、たとえば指の制御や携帯物による体の制御などの高度な昨日は必要ありませんでした。最後に3つ目ですが、最終的にプロジェクト自体をOSSとして公開したり、アセットライブラリにしたかったというのもあり、「有料アセットに依存していると使ってもらえないかも」という懸念がありました。これがFinalIKを使わなかった理由になります。結構後付けみたいなところはあるんですけどね。

AnimationRigingに関してはまだ自分に知見がそこまでないので詳しいことはお話しすることはできないのですが、2019年12月現在プレビュー版としてUnity2019で公開されている機能で、アバターのリターゲティングやIK制御などの豊富な機能が実装されています。Job Systemを使って実装されているため並列的に処理されるところも魅力です。モダンなUnity感...。

最後にMecanimについてですが、こちらは前からUnityに実装されているHumanoidアバター制御機能です。Humanoidでリギングされた3DモデルはMecanimを使うことによってボーンを動的に動かしたり、簡単なIK処理をすることができます。

今回私は最後に説明したMecanimを使いました。なぜAnimationRigingを使わなかったかというと、単純にそれを知るのが遅かったのが原因です...。プレビュー版とはいえ素晴らしい機能なので今後すぐ対応していきたいです。

## アバターを自然に動かすために

　アバター制御をする手法はいくつかありますが、単純な方法だと人間らしさがなかったり、ボーンが破綻してしまって目も当てられない姿になってしまったりと悲しいお気持ちになってしまいます(実際開発していて悲しいお気持ちになったため)。
自分は1年間モーキャプを開発するにあたって「自然に」というのを一つの目標にしてきました。ここでは自然な姿勢制御を実現するために用いた技術について解説していきたいと思います。

### 補間、補正をする意味

モーキャプはセンサリングの一種です。センサーを扱うわけですので、センサーの値の誤差やノイズ、欠損の問題を無視することはできません。高いモーキャプデバイスを買えばそれなりに解決できる問題も多いのですが、それは根本的な解決にはなりません。ですので、しっかりソフトウェア側でデータを補完するシステムが必要です。
私は以下の3つの機能を導入することにしました。

- IK制御
- キャリブレーション/レジストレーション
- 平滑化フィルタ

ここからはそれぞれについて解説していきます。

### FKとIK

　ボーン制御の方法として主に2つの手法があります。それは"FK"と"IK"です。FKとはForward Kinematicsの略で、ボーンの親から順番に回転を加えていくことによりボーンの制御をします。一方IKとは、Inverse Kinematicsの略で、FKとは逆に末端のボーンの姿勢から親のボーンの姿勢を逆計算する手法を指します。
　基本的にシンプルな実装をしようと思えばFKになるような気がするのですが、FKは「末端のボーンに誤差が蓄積されていく」という大きな問題を孕んでいるため、結果的にIK制御を採用しました。
　しかしIKにもデメリットは存在していて、クリティカルなものだと実装が大変になるというところですかね。FKのようにただ取得出来たボーンの回転を当てはめるだけでは実現できないので、ベクトル演算によって位置を計算しなければいけません。ただ、前述した通り
UnityのMecanimでは既にIK処理のAPIが用意されているのでそれを利用すれば簡単に実装できます。
　また、これは後付けなのですが、Kinect以外のデバイスを使う場合、Kinectのように体全体のボーンを取得できない可能性が高い問題もあります。どういうことかというと、Kinectの場合は腰や胸、脊椎、肩などのボーンが取れますが、普通のViveトラッカー配置だと肩のボーンは取得できません。しかしIKならば、四肢のボーンは末端のボーンだけで解決するのでボーンの数がFKに比べて少なくて済みます。したがって、IK制御を導入すると、マルチデバイス対応がしやすくなるという点も大きいです。

### 体形を合わせる～キャリブレーション～

キャリブレーションという単語を聞いたことがある人は多いかもしれません。キャリブレーションとは、センサーの標準状態を本格的なセンサリングに入る前に記録して調整することを指します。これはモーキャプ以外の分野でも広く使われる言葉ですが、モーキャプで言うキャリブレーションとは「リアルの体形のデータを記録してアバターの体形に合わせる準備をする」ことを指しすらしいです。
リアルの体とアバターでは体形が違うことが多いです。極端な例ですが、クマのぬいぐるみみたいなアバターをモーキャプで制御しようと思ったときには四肢の長さや頭身、肩幅などに差異が出ます。これを吸収してやるためにキャリブレーションを行います。キャリブレーションはいろいろな方法があると思うのですが、私は胸から手、腰から足、というベクトルを比較することによって体系合わせをしました。実際これでもよいのですが一つ問題があって、Unity標準のHumanoidでは胸のボーンが任意ボーンになっています。ということはもしかするとアバターの方に胸のボーンが割り当てられていない可能性があります。実際のところ胸のボーンがないというのは考えにくいのですが、100%ないとは限りません。特に人外アバターとなると懸念すべきでしょう。

その対策として、最近とても良い記事を見かけました。[おぐらさん](https://twitter.com/ogog_ogura)という方がバーチャルキャストのモーションフィルターというキャリブレーション機能について解説してくださっており、そちらの記事では胸ではなく肩のボーンを基準に位置合わせをしていました。自分もそちらに対応したいと考えております。
小倉さんのモーションフィルタについての記事は[こちら](https://virtualcast.jp/blog/2019/12/motionfilter/)

あと、これは個人的にハマった点なのですが、モーキャプしたボーンのデータ構造とUnity標準のHumanoidのボーン構造が違う問題がありました。具体的には、胸のボーンを使いたいのに、Kinectでは胸のボーンが取れないという問題です。Kinectでは背骨関連のボーン(Joint)として、`SpineBase(腰)`、`SpineMiddle(背骨中点？)`、`SpineShoulder(肩中心)`というものがありますが、胸に対応するJointがないため、胸の位置を推定する必要がありました。おそらくキャリブレーションなどの処理においては、他のデバイスでもこういう問題に直面するかもしれません。
([Kinect v2のボーンとHumanoidのボーン構造の違いをまとめた記事を書きましたのでよかったらご覧ください(ダイマ)](https://qiita.com/drumath2237/items/c061e2591cc40988a308))

### データの平滑化

次にデータの平滑化についてのお話をします。モーキャプで生のデータを流してしまうとセンサーノイズによって、アバターの一部分がブルブルしてしまう現象が見られます。センサーの精度にもよるのですが、こういう現象は何とかして減らしたいものです。そこで、ボーンの移動を滑らかにすることによりこの問題を解決しようと考えました。そこで導入したのがフィルターという概念です。フィルターとは不要なものを”濾す”ことによりきれいなデータだけをとりだすことですが、ここではフィルターで統計的な処理を入れることにより、純粋な姿勢データを推定することを目指します。
世の中にはいろいろなフィルターがあるのですが、私が採用したのは”2重指数平滑化フィルター(DEMA)”というものです。DEMAと検索すると色々ヒットするので詳しい解説は参照していただきたいのですが、数式にすると以下のようなものです。

<img width="400px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86191/97cea85d-6d50-782e-273b-ef570ca4cf38.png"></img>

なぜこのフィルタを採用したかというと、「計算コストが低く、高精度な補完が効く」からです。調べていると、もともとFXや株の値動きに対する予測に用いることが多いみたいです。

## システムを設計する

ここの章はまだ完成してません...！申し訳ございません！
随時更新していきますのでよろしくお願い致します...

### 保守・拡張しやすい設計を目指して

// TBD

### MV(R)Pパターンの導入と債務の分離

// TBD

## VTuberオタクはバーチャル美少女受肉の夢を見るのか？

### 個人的な夢

1年間モーキャプに注力してきて「自分そんなに美少女になりたいと思ってないな」って思いました(唐突)。これは完全に個人的な話なのですが、かわいいキャラクターはやっぱり外から見ている方が楽しいなぁとか思ったり、どちらかというと自分はキャラクターの補助に回りたいというか、後方腕組エンジニア面して見守ってるほうが好きだなぁとか考えました。とはいえ受肉に関しては興味は尽きなくて、人外アバターとかやってみたいんですよね。今年で大学2年生だけど中2病なので、ローポリモデルとかロボットとか神秘的なゴーストみたいなキャラクターになってみたいです。

唐突に個人的な話をしてしまったのですが、そもそもこういう話が普通にできる世の中ってすごいと思うんですよ。まだ一部の界隈にしか知れ渡っていない文化とはいえ、その一部の人たちは、現実と違うリアリティにアバターを持っていて、それはその人のアイデンティティになっていて、しかも場所という概念を超えて他のアバターと交流できるわけですから。TwitterやFacebookにおけるアバターから拡張されて、自分で動き、話すことでよりそのアバターに没入する、そんな世界がもう普通に来ているのがたまらなくアツいです(語彙力)。
また、キャラクターへの没入感が強いと自然とそのキャラクターに合わせた振る舞いをするようになる、なんていう事象も確認されています。最近だと、アメコミヒーローのVRゲームで、主人公のアバターを操作していると、自然と背筋が伸びていき、勇ましい姿勢になったみたいなニュースを見た気がします。VRChatなんかでずっと過ごしていれば、いずれ自分の人格がキャラクターに引っ張られてしまうなんてことも起こりえるんじゃないでしょうか？そうなったらどっちがリアルなのかわかりませんね...。

ただ、前述した通りこのような文化はまだ一部の界隈にしか通じません。しかもまだ発展途上な領域であるがゆえに、機器自体の値段が高かったり、アバターが変な動きをしてしまったり、機材トラブルでシステムが落ちてしまったり、VR酔いがでてしまったり、と一般に広く使われるためには改善点がたくさんあります。私が尊敬するGOROman氏風に言うなれば、”キモイ”状態だと思います。

自分はこの環境をより良いものにしたいと考えています。もっとキャラクターになりきれるように、ユーザーが安価に、ほぼ100%違和感なく、アバターを操作できるような世界を実現したいです。
最終的には、リアルとバーチャルが融け合い、相互にインタラクションできる世界を創りたいです。
モーキャプシステムの開発は、自分の夢の実現を意識させるとても良い機会になりました(まだ開発は終わってないですが...)

### 今後の展望

今回記事に書いたような技術を使ってモーキャプシステムを作ったわけですが、自分としてはまだ満足ができていなくて、検討したい改善方法がいくつかあります。

- 床との設置感の実装
- 腕の動きに伴う肩のアシスト
- DEMAよりも高度なフィルタの導入
- キャリブレーションロジックの改善
- AnimationRigingの導入
- PD制御の導入
- システム設計の見直し
- Kinect以外のデバイスでの検証
- AzureKinect欲しい

全部実装できるかどうかはわかりませんが、来年以降もゆるゆると取り組んでいきたいと思います。
そして出来たらまた記事にまとめたいです。


明日は @broken55 さんによる[ドコモAIエージェントAPIを使ってキャラクターと会話する](https://qiita.com/broken55/items/5cdda8366aa2b6fa6fc0)という記事です！