PoseMirror開発で詰まった5つの不具合と解決策

投稿日: 2026年5月7日(2026年10月5日更新)
対象読者: Unity WebGL と AI の姿勢推定を組み合わせたアプリを作ろうとしているエンジニア

不具合内容

MediaPipe と Unity WebGL で PoseMirror(写真から3Dデッサン人形のポーズを作るアプリ)を作る途中で、次の5つの不具合に詰まりました。どれも修正時に数値を測って記録してあります。

  1. Firebase Hosting で、firebase.json に書いた Content-Encoding が返らない
  2. 写真から作ったポーズの肘の角度が、写真の見た目と平均 34° ずれる
  3. 人形の細い部位(腕・すね・つま先)を、クリックやタップで選べない
  4. つま先が足首から最大 157° 折れる
  5. 部位名を日本語にしたら、文字が「□」になる

全体の仕組みは 【Unity WebGL】MediaPipeで3Dポーズを動かす で説明しています。

原因(一言でいうと)

  1. Firebase Hosting が、大きいファイルの圧縮を自分で決めて返していた
  2. MediaPipe の3D座標(worldLandmarks)の奥行きの誤差が大きかった
  3. クリックの判定を、骨の細いコライダーにレイが当たったときだけにしていた
  4. 足首だけ可動域で角度を戻し、つま先はそのままにしていた
  5. Unity の文字表示(TextMeshPro)のフォントに、日本語の文字が入っていなかった

解決方法

  1. Unity の Decompression Fallback を有効にしてビルドする
  2. 画像上の座標から3D座標を組み直し、奥行きの z だけ 1/3 に縮める
  3. レイが外れたら、画面上でいちばん近い骨を選ぶ(寛容ピック)
  4. 可動域で戻したあとの回転を、足首とつま先の両方に使う
  5. 必要な文字だけを焼いたフォントを作り、元のフォントの予備として登録する

動作環境

項目 バージョン
Unity 6000.0.58f2
(WebGLビルド)
MediaPipe Tasks Vision 0.10.0
(pose_landmarker_heavy)
公開先 Firebase Hosting

不具合①:firebase.json に書いたヘッダーが返らない

解決方法の詳細

Unity の Player Settings → Publishing Settings → Decompression Fallback を有効にしてビルドします。ビルドに展開用の JavaScript が入るので、ヘッダーがどう返っても Unity のファイルを読めます。

原因詳細

再現: Unity のファイル(.unityweb)すべてに Content-Encoding: br を付けるよう firebase.json に書き、本番の応答を curl で取りました(2026年10月5日)。

ファイル 指定 実際の応答
.wasm.unityweb br br(Firebase が圧縮し直したもの)
.data.unityweb br gzip
.framework.js.unityweb br なし

Firebase Hosting は、指定したヘッダーではなく、自分の判断で圧縮して返していました。Unity が圧縮したファイルをブラウザに展開させる形は、Firebase Hosting ではまだ作れていません。詳しい設定は 【Firebase】Unity WebGLを無料で公開する手順 にまとめています。

不具合②:肘の角度が写真と平均34°ずれる

解決方法の詳細

MediaPipe の画像上の座標(landmarks)をピクセル単位に戻し、腰の中点を原点にして3D座標を組み直します。奥行きの z だけは 1/3 に縮めます。1/3 は、モーションキャプチャアプリ XR Animator の既定値と同じです。

const px = imageLandmarks.map(lm => [lm.x * imgW, lm.y * imgH, (lm.z * imgW) / 3]);

原因詳細

再現: 写真から作ったポーズ20件で、3D人形に付いた肘の角度を写真の見た目と比べました。worldLandmarks をそのまま使うと、平均 +34.1° ずれ、20件すべてで 15° 以上ずれていました。z を 1/3 にすると、平均 +10.3° まで減りました。

人形の書き出しファイル(BVH)から順に角度を計算し直しても同じずれが出たので、Unity 側の計算ではなく、worldLandmarks そのものがずれていると判断しました。x と y は画像上の位置そのものですが、z は1枚の写真から推し量った値なので、誤差が大きくなるのだと考えています。写真で比べた図は MediaPipe Pose 33ランドマーク完全ガイド に載せています。

不具合③:細い部位をクリックで選べない

解決方法の詳細

クリックした点からのレイが骨のコライダーに当たらなかったときは、画面上でクリックした点にいちばん近い骨を選ぶようにしました。拾う距離は画面の高さの4%(1080px の画面で約43px)にしたので、端末の解像度によらず同じ感覚で選べます。

if (Physics.Raycast(ray, out RaycastHit hit))
{
    uiController.SelectPartByTransform(hit.transform);   // 当たったらその骨
    return;
}
PickNearest(screenPos);   // 外れたら、画面上でいちばん近い骨

原因詳細

再現: 1080×1080 の画面の全 291,600 点で、実際の選択の処理を通して、どの点で骨が選ばれるかを数えました。骨が選ばれた点は、画面の 4.9% しかありませんでした。手は手首の点だけ、つま先は数ピクセルでした。寛容ピックを入れると 13.3% に増えました。

コライダーを太くする案も測りましたが、半径を2倍にしても 8.5% にしかなりませんでした。寛容ピックと併用すると、太いコライダーが先に当たって近い部位を奪うため、13.3% から 12.8% に減りました。

同じ調査で、腰と胸の判定が左に 43mm と 29mm ずれていることも見つかりました。コライダーの軸を、左側の子の骨(左脚・左肩)だけの方向から決めていたためです。左右の子の平均を軸にして直しました。

不具合④:つま先が足首から最大157°折れる

解決方法の詳細

足首を可動域で戻したあとの回転を、つま先にもそのまま設定します。

Quaternion world = ApplyJointLimit(footPart, ankleBone, rig.Fix(footPart, rotation));
SetBoneRotation(ankleBone, world);
SetBoneRotation(toeBone, world);   // つま先にも、戻したあとの回転を使う

原因詳細

再現: 用意してあるポーズ369件すべてで、足首とつま先の角度の差を測りました。右のつま先は最大 157.1°(中央値 30.8°)、左は最大 156.6°(中央値 30.5°)、足から折れていました。修正後は、右が全件 6.4°(モデルの形による一定の値)、左が全件 0.0° です。

MediaPipe には、つま先だけを曲げた情報がありません。そのため足首とつま先には同じ向きを渡していて、本来は同じ回転になるはずでした。ところが、足首だけ可動域の制限を通し、つま先は通していませんでした。制限で戻した分だけ、つま先が足から折れていたわけです。つま先は手で直す部位の一覧から外してあるので、利用者には直せない折れでした。

不具合⑤:部位名を日本語にしたら「□」になった

解決方法の詳細

部位の一覧に使う文字(29文字)だけを、Noto Sans JP と Noto Sans SC(どちらも OFL ライセンス)から焼いたフォントを作りました。それを、元のフォント(LiberationSans SDF)の予備(フォールバック)に登録しています。増えたダウンロードは数十KBです。

文言を増やしたり変えたりしたときは、このフォントを作り直す必要があります。

原因詳細

再現: 部位の一覧を日本語・英語・中国語に切り替えられるようにしたところ、日本語と中国語の文字がすべて「□」で表示されました。

Unity の文字表示(TextMeshPro)の標準フォントには、日本語と中国語の文字が1文字も入っていません。日本語のフォントをまるごと入れるとダウンロードが大きく増えるので、使う文字だけを焼く形にしました。

同じ多言語化で、言語を切り替えるたびに、選んでいた部位が「腰」に戻る不具合も出ました。一覧を作り直すときに、選択位置が先頭に戻っていたためです。作り直す前に選択位置を控え、作り直したあとに戻して直しました。

まとめ

不具合 原因 解決策
ヘッダーが返らない Firebase が圧縮を自分で決める Decompression Fallback を有効にする
肘が平均34°ずれる worldLandmarks の奥行きの誤差 画像上の座標から組み直し、z を 1/3 にする
細い部位を選べない 細いコライダーにしか当たらない 外れたら画面上で最も近い骨を選ぶ
つま先が最大157°折れる 足首だけ可動域で戻していた 戻したあとの回転をつま先にも使う
部位名が「□」になる フォントに日本語が無い 使う29文字だけのフォントを予備に登録する

選べる範囲が画面の 4.9% しかないことも、つま先の折れが全369件で起きていたことも、数えて初めて分かった規模でした。コライダーを太くする案のように、もっともらしい直し方が、測ると逆効果だったこともあります。

この5つを直した版が、PoseMirror で動いています。

5つの不具合を乗り越えた完成品です。

詰まった末にたどり着いた挙動を、ブラウザで確認できます。

▶ 完成した3Dデッサン人形を触ってみる

関連記事:

参考資料

← Kabe-Tech トップへ