gombeのブログ

マイコンの電子工作系PIC32/KiCad/C/C++/3D/

esp32でMMDで躍らせる

esp32でMMD? どうやって?

esp32はおなじみの方が多いと思いますが、wifi, bluetoothモジュールの中にdual coreのプロセッサが入っています。これをうまく使って、ソフトウェアレンダリングで3Dモデルを躍らせようというプロジェクトです。

www.youtube.com

github.com

はじめに

esp32に含まれているCPUにはFPUというFloating Point Unitがあります。これにより浮動小数点を含む3Dの演算をまあまあの速度で動かすことができます。ソフトウェアレンダリングはラスタライズをCPUで行います。単純作業の繰り返しになるまで三角形を分解してから最後に描画するといった流れでしょうか。

では実際にどのようにして躍らせているのでしょうか?

実は踊ってるように見えて実際踊ってるのですが、頂点グループをまとめたボーンを動かしていることにすぎません。このような技術をSkeletal animationと呼んだりします。MMDではFK, IKと物理演算をうまく組み合わせることでリアルな動きを表現しています。

ラスタライズ(レンダリング

レンダリングは3Dにおいて最も基本となる部分です。目視で確認するためには最も早く実装すべき機能でしょう。すでにラスタライズについては以前の記事で書いていますのでここでは深く触れませんが、ラインスキャン法で3D描画しています。z-bufferの前身ともいわれる方法で、z-buffer法より少ないメモリでそれに近いパフォーマンスを引き出すことができます。ただ、スキャンライン法は1ラインずつの処理ですが、それではさすがに遅い場合は複数ライン描画するといった解決方法があります。もちろん全画面描画できればz-buffer法と同じでパフォーマンスも高いのですが、メモリが足りなくてそんなことできないので、24行など細かい単位で転送をかけます。z-bufferについては1転送分のみ確保すればいいのですが、video bufferについては2転送分確保します。これはDouble bufferingするためです。描画タスクと並行して内部描画が可能になります。

FK, IK

FK, IK について深く知らない方も多くはないでしょうが、私たちの体はFK、IKによって制御されていると説明しても大きな不自然な点はないことと気づくと思います。

FKはForward Kinematicsと呼ばれている技術で、私たちの骨の接続に注目すると木構造になっていることから親ボーンが動くと子ボーンも動くことを計算上で実現する方法です。実際私たちの体もひじを動かすと、それにつながっている手首も動きますね?正確に言うならば、手首の位置に注目すると、ひじの位置を中心とした回転運動をするはずです。これらの運動を算術的に解き、変換行列を求めることでFKを実現します。

IK (Inverse Kinematics)も自然な考え方です。私たちの頭の中で足の動きを考えてください。ここに足のつま先を持ってくる→足首の関節→ひざの関節→...と意識が伝搬して足が動くでしょう。これはIKの最も基本となる考え方です。私たちはIKにより足を動かしてるといってもおかしくはないでしょう。わざわざ毎回膝をどれだけまげて歩くなどは考えていないと思います。つまりIKはFKと逆の手順で膝や足首、足の運動を解くことができます。目標に対してどのように運動するかを考えることでその姿勢を求めることができるのです。

実はIKの実装にはFKの実装が欠かせません。今回はIKをCCD-IKを用いて実装しました。CCD-IKの最も基本はFKに基づくIKへのフィードバックです。実際に動かしてみてそれを基にIKにどう反映するのかを考えます。実際にモデルにてIKをどう応用するのかは難しい分野で、動きが自然に実現される必要があります。実際、これらの機能は負荷が大きいことでも知られています。詳しいtechnicalな部分はまたあとで解説しましょう。

まとめとesp32 for MMDの展望

いまはようやく20fpsを超える程度で動き出したばっかりです。実際3Dを動かすためには様々な処理が必要です。アニメーションを通してどのようにMMDモデルを動かすかのみではなく、一般的にコンピュータグラフィックスという分野がどれだけ幅に広がっているのか、レンダリングのみではなく、FKやIKも含まれますので、アニメーションの基礎を学ぶことができました。

で、これからどうしていくかは不透明ですが、実装したい項目はいくつかあります。

- 表情の追加(歌わせたいって言われた)

- 物理演算(性能的に厳しそ)

- 高速化(どうやるかはわからん。Fix-Point演算やTextureのAffine化の対応など)

- 複数モデル対応(データ構造どうしようって思って。z-bufferと違ってすべての頂点を解析する必要があるから。。)