画像から 3D モデルを作る生成 AI のサービスがありますが、同じことが手元の GPU でもできるかを、余っていた Radeon で技術検証しました。その中で、素体・髪・服・靴・鞄を別々に生成し、1体の人物に組み立てて同じ骨格で歩かせる試作をしました。つまずいたのは、別々に生成した部品が読み込んだだけでは重ならなかったことと、服を身体に沿わせる方法を最初に間違えて、服の厚みが潰れ表面が崩れたことです。

結論

  • 別々に生成した部品には、共通の縮尺も、共通の基準の姿勢(bind pose)もありませんでした。素体を測って高さを 2 にそろえ、ほかの部品は素体に合わせて、部品ごとに中心・寸法・回転を記録しました。
  • 服の表と裏の両面を身体へ投影すると、厚みが潰れて表面が崩れました。そこで投影はやめ、生成した服の形を保ったまま寸法と袖の位置を合わせました。外から見えない内側の層は、着せた版でだけ隠しました。
  • 鞄は外接箱(bounding box)を合わせるだけでは身体から浮きました。上着と鞄の実際の面を ray で調べて小さな隙間まで寄せ、身体に沿う肩ひもを足しました。

試した環境

  • 画像から 3D: TencentARC/Pixal3D を trellis.cpp v0.8.1 で実行(HIP、gfx1100)
  • 生成の設定: 解像度 1024、16 steps、FOV 15。7 つの部品を1つずつ順に生成
  • 計算機: Radeon RX 7900 XT(VRAM 20 GB)
  • 入力: 人が用意した三面図をもとに、画像生成で「部品が1つだけ写った」参考画像を 7 枚作り直しました(素体・髪・上着・シャツ・ズボン・靴・鞄)。人物は頭身の低いデフォルメです
  • 組み立てと確かめ: Blender

部品どうしに共通の物差しがない

部品は1つずつ別の画像から生成したので、出てきた GLB どうしには共通の縮尺も、共通の基準の姿勢もありませんでした。同じシーンに読み込んでも、それだけでは1人の人物になりません。

そこで、まず生成した素体を四方から見て測り、高さを 2 にそろえました。ほかの部品はこの素体に合わせて動かし、部品ごとに中心・寸法・回転を記録しました。元の 7 つの GLB には手を入れず、合わせた結果は別の派生ファイルにしています。生成したときに記録された SHA-256 と照らして、元のファイルが変わっていないことも確かめました。こうしておくと、生成された形と、合わせるために動かした量を分けて持てます。

部品ごとにも、それぞれ別のずれや傷がありました。

部品起きたことどうしたか
靴斜め前から描いた参考画像から作ったので、物の軸が斜めになった素体に合わせる前、左右を写して反転させる前に、水平の主軸を測った
髪細い割れ目があり、頭の入る空洞が小さすぎた元の GLB は残した。素体に合わせてから内側にふたを足し、前の下側の要らない縁を取り、小さなトンネルを体積の表現にして閉じた。派生側は一様な栗色の材質にした
素体後頭部のテクスチャに小さな暗い点があった元は残し、髪で隠れるかを確かめた。元の素体を「きれい」とは扱わなかった
大きさも向きもそろっていない部品が、素体のまわりに浮かんでいる絵

服を両面投影したら、厚みが潰れた

服を素体にぴったり沿わせたいとき、服の頂点を身体の面へ寄せる方法は手早く見えます。私たちも最初は、生成した服の表と裏の両方の面を身体へ投影しました。

すると服の厚みが潰れ、表面に乱れが出ました。生成した服は表と裏の面のあいだに厚みを持っていますが、両方を同じ身体の面へ寄せれば、そのあいだは無くなります。身体に合うかどうか以前に服の形そのものが壊れてしまうので、この方法はやめました。

代わりに、服の形は生成されたまま保ち、合わせる所を絞りました。

  1. 生成した服の形には手を入れない
  2. 素体に合わせて寸法をそろえ、袖の位置のずれを合わせる
  3. 着せたときに外から見えない内側の層は、着せた版の派生ファイルでだけ隠す(元の服からは消さない)

次の図は、二つのやり方がどこで分かれたかを表しています。

生成した服を素体に合わせる二つのやり方

投影の側は、そこで行き止まりになりました。形を保つ側は、寸法と袖位置を合わせたうえで、見えない層の扱いを着せた版だけに閉じ込めています。

頂点を動かす処理では、もう1つつまずきました。座標を書き換えながら法線を何度も問い合わせると、そのたびに重い再計算が走ることがありました。そこで、座標を書き換える前に法線の写しを取るようにしました。髪などの手直しの結果は、元のメッシュ・合わせた値・スクリプトをキーにしてキャッシュしました。

鞄は外接箱を合わせても浮いた

鞄も最初は、外接箱どうしを合わせて背中に置きました。箱の位置は合っていても、実際の鞄は身体から離れて立っていました。

そこで、上着の面と鞄の面に実際に ray を当てて二つの面の間隔を調べ、小さな隙間が残る所まで鞄を動かしました。間隔を測る相手は素体ではなく、いちばん外に着ている上着の面です。そのうえで、身体に沿う肩ひもを足しました。

どう確かめたか

静止の姿勢では、正面・横・後ろ・斜めの 4 方向から見ました。歩かせてからは、左右の足が入れ替わった踏み出しのコマと、横と後ろからのコマを見ました。最後に、書き出した GLB を読み込み直しても描けることを確かめています。

確かめていないこと

  • 参考画像と複数の方向で正確に一致しているかは、測っていません。
  • 布のシミュレーションはしていません。服は形を合わせ、骨格に付けただけです。
  • 首まわり・襟と、足首のつなぎ目は粗いまま残りました。髪の表面にも、生成でできた細かい凹凸が残っています。
  • 7 つの部品を組んだ人物は約 273k 三角形でした。リトポロジーや LOD、端末で動かしたときの負荷、エンジンに読み込んで動かすところは確かめていません。

おわりに

別々に生成した部品を組むとき、私たちの試作では、服は生成された形を保ったまま寸法と位置で合わせ、背負う物は実際の面どうしの間隔で寄せる、というやり方に落ち着きました。

※ Pixal3D・trellis.cpp・Blender の振る舞いは執筆時点の情報です。いまは変わっている可能性があります。