作ったもの

前回の記事では、アニメ調の人型3Dモデルを自作する3つのルートを調べた。 その後、「3Dのスキルがない人がClaudeを使うなら、どこまでできるのか」が気になった。 そこで、Claudeにコードだけで2.5頭身のキャラクターを作らせる方法を実際に試した。下が完成したモデルで、ドラッグで回転でき、ボタンで表情を切り替えられる。

3Dモデルを読み込んでいます…

Claude Codeがスクリプトだけで作ったVRMモデル(約2.1MB)。体を揺らすとツインテールが揺れ、数秒おきにまばたきする

筆者がしたのは、Claude Codeとの会話で「試してみたい」と伝え、デザインの方向として「デフォルメキャラ」を選んだことだけだ。 Blenderのインストール、VRMアドオンの導入、約600行のスクリプトの作成と修正、ブラウザでの表示確認は、すべてClaude Codeが行った。 髪の色や衣装のデザインもClaudeに任せた。 モデルはVRMファイルとして、生成スクリプトはPythonファイルとして公開している。

進め方:書く、描画する、画像を見て直す

ClaudeはBlenderの画面を見ながらマウスで操作するわけではない。BlenderのPython API(bpy)でモデルを組み立てるスクリプトを書き、Blenderを画面なしで実行してVRMを書き出す。 書き出したVRMはthree.jsとthree-vrmで描画し、正面・斜め・横・後ろの4方向と、12種類の表情を1枚ずつの画像に撮る。Claudeがその画像を見て問題を見つけ、スクリプトを直す。

flowchart LR
    A["Claudeが<br/>bpyスクリプトを書く"] --> B["Blenderを画面なしで実行<br/>VRMを書き出す"]
    B --> C["three-vrmで描画<br/>Playwrightで撮影"]
    C --> D["Claudeが画像を見て<br/>問題を探す"]
    D -->|直す| A
    D -->|問題なし| E["ブログに配置"]
制作のループ。初版から最終版まで、スクリプトの修正は7回だった

確認にBlenderのレンダリングではなくthree-vrmを使ったのは、最終的に表示する環境がブラウザだからだ。 VRMの見た目を決めるMToonシェーダーや、揺れもののSpringBoneは、表示するソフトの実装で動く。Blender上できれいに見えても、ブラウザで同じに見えるとは限らない。

# Blender 5.2 LTSとVRMアドオンを入れる
brew install --cask blender
blender --online-mode --command extension sync
blender --online-mode --command extension install vrm --enable

# スクリプトを画面なしで実行し、VRMを書き出す
blender -b --python build_chibi.py -- chibi.vrm

組み立て方のポイント

体は球と筒の組み合わせ

2.5頭身のキャラクターは、体の部品がほぼ球と筒で表せる。頭は少し縦につぶした球で、下半分ほど横幅を絞ってあごを作った。 胴は楕円体、腕と脚は筒、靴は平たい球、スカートは円錐だ。スカートは裾の頂点を交互に出し入れし、プリーツに見せている。 髪は後頭部を覆う殻と、曲線に太さを付けた毛束の組み合わせで作った。前髪とツインテールは毛束だ。

目と口は「貼り絵」にする

一番の工夫は顔だ。目・口・眉・頬の赤みは立体として作らず、平らな図形として描き、正面から頭の表面に投影して貼った。 頭の手前から奥へ光線を飛ばし、当たった位置に、表面から数ミリ浮かせて頂点を置く。 瞳・瞳の明るい部分・瞳孔・ハイライト・まつ毛は浮かせる高さを少しずつ変え、重なり順を作っている。

from mathutils import Vector
from mathutils.bvhtree import BVHTree

head_bvh = BVHTree.FromObject(head, depsgraph)

def project(x, z, offset):
    """正面(-Y)から光線を飛ばし、頭の表面からoffsetだけ浮かせた点を返す"""
    hit, normal, _, _ = head_bvh.ray_cast(Vector((x, -1.0, z)), Vector((0, 1, 0)))
    return hit + normal * offset

# 楕円の輪郭を投影して瞳を作る。重ねるパーツほどoffsetを大きくする
iris = decal("IrisL", ellipse_pts(0.088, 0.80, 0.037, 0.050), 0.0020, MAT["iris"])
pupil = decal("PupilL", ellipse_pts(0.088, 0.796, 0.015, 0.0225), 0.0032, MAT["pupil"])

貼り絵のパーツは、MToonの陰色を基本色と同じ色にした。こうすると光の向きに関係なく、同じ色で塗りつぶされる。 アニメの目に陰が落ちると汚く見えるので、絵として描いた部分は陰の計算から外している。

表情は2Dで変形して貼り直す

貼り絵にした利点は表情づくりで出た。各パーツの元の2D座標を保存しておき、表情ごとに2Dで変形してから、もう一度頭の表面に投影する。その位置をシェイプキーとして登録する。 まばたきは目を下端に向けて縦につぶし、笑顔の「^ ^」は細くつぶした目を山なりに反らせる。怒りは目の上側を眉間側へ、悲しみは目尻側へ傾けた。 立体的な顔のシェイプキーを手で作るのに比べ、式を1つ書けば済む。

12種類の表情を並べた画像。上段は左からふつう、まばたき、喜び、怒り、悲しみ、楽しみ。下段は驚きと、あ・い・う・え・おの口の形
VRM 1.0のプリセット表情。上段: ふつう・まばたき・喜・怒・哀・楽。下段: 驚・あ・い・う・え・お

作ったシェイプキーは、VRMの表情プリセット(happy、blink、aaなど)に結び付ける。 感情の表情には「まばたきを抑止する」設定を付けた。笑顔の「^ ^」の上にまばたきが重なると、目が崩れるからだ。

v1 = armature.data.vrm_addon_extension.vrm1
for key, preset in [("happy", "happy"), ("blinkL", "blink_left"), ("aa", "aa")]:
    ex = getattr(v1.expressions.preset, preset)
    bind = ex.morph_target_binds.add()
    bind.node.mesh_object_name = "Face"
    bind.index = key          # シェイプキー名
    bind.weight = 1.0
    if preset == "happy":
        ex.override_blink = "block"  # 笑顔のあいだはまばたきを止める

法線・骨・揺れもの

前回の記事で書いた工程も一通り入れた。あごを細くした頭には、変形前の球の法線をデータ転送で写した。形は細いあごのまま、陰は球のように丸く出る。 骨は腰・背骨・胸・首・頭と手足の17本をVRMの人型ボーンに割り当てた。ツインテールには4本ずつ骨を入れてSpringBoneで揺らし、輪郭線はMToonのアウトライン(太さ2.2mm)で付けた。

ハマったところ

前髪を「切り抜き」で作るとヘルメットになる

最初、髪は頭より一回り大きい球を1つ作り、顔の部分を切り抜いて作った。前髪の毛先は、切り抜く線をジグザグにして表した。 正面から見ると前髪らしく見えたが、斜めや横から見ると、切り口の段差がそのまま見えた。頭全体を殻で覆っているので、ヘルメットをかぶっているようにも見えた。

初版のモデルを正面・斜め・横・後ろから見た画像。前髪が球を切り抜いた形で、横から見ると切り口が段になっている
初版。前髪は球をジグザグに切り抜いた形で、斜めと横から見ると切り口が目立つ

直し方は、アニメ調モデルで一般的な作り方に寄せることだった。殻は後頭部と頭頂部だけに残し、前髪は先の尖った毛束を13本、頭頂から額へ流した。 毛束は丸い筒のままだと額から浮くので、頭の表面に沿うよう平たくつぶしている。最初は毛束の付け根が額の途中にあって横一線の段差が見えたため、付け根を頭頂まで上げた。

最終版のモデルを正面・斜め・横・後ろから見た画像。前髪は毛束が頭頂から流れ、後ろ髪の裾はギザギザになっている
最終版。前髪を毛束に変え、後ろ髪の裾もギザギザにした

表情を全身に持たせて8.3MB

初版は全身を1つのメッシュにまとめていたので、表情のシェイプキーが全身約2万頂点ぶん記録され、ファイルが8.3MBになった。 VRoid Studioのモデルと同じように、顔(頭と貼り絵のパーツ)を別のメッシュに分け、シェイプキーは顔だけに持たせた。これで2.1MBに減った。

VRM 1.0の基準姿勢はTポーズ

初版は腕を斜め下に下ろしたAポーズで作っていた。VRM 1.0の仕様では、モデルの基準姿勢をTポーズにすることになっている。 基準姿勢が違うと、VRM用のアニメーション(VRMA)を流したときに腕の角度がずれる。腕を水平に伸ばして作り直し、腕を下ろす処理は表示する側(ビューア)に移した。

ツインテールの重み付けが腕を巻き込む

Tポーズにしたら、腕が三角形に引き伸ばされて崩れた。原因はツインテールの重み付けだった。 全身をまとめた後に「頭の横にあり、ツインテールの骨に近い頂点」を探して髪の骨に割り当てていた。水平に伸ばした腕がツインテールのすぐ横に来たので、腕の頂点まで髪の骨に割り当てられていた。 重み付けを、まとめる前のツインテールのメッシュだけで行うように直した。位置で対象を選ぶ処理は、形を変えたとたんに別の部品を巻き込むことがある。

このやり方が通用する範囲

完成したモデルを見ると、ClaudeとBlenderの組み合わせで「スキルなし」から1体を作ること自体はできた。ただし、条件がそろっていたから成立した面が大きい。

今回うまくいった理由条件が外れると
体型2.5頭身のデフォルメで、部品が球と筒で表せる等身の高い体は、筋肉や関節の形を数式で書くのが難しい
顔目と口を貼り絵で表すデザイン鼻や唇を立体で作る顔は、形の良し悪しを式で詰めにくい
確認描画して画像で見るループを自動で回せたBlenderの画面操作に頼ると、確認の手間が増える
判断崩れ・隙間・ずれなど、誰が見ても分かる問題が中心「かわいいか」「好みか」は、人が見て決めるしかない

最終版にも粗は残っている。斜めから見るとこめかみに小さな隙間があり、スカートのプリーツはほとんど目立たない。指は作っておらず、手は球だ。 また、Claudeは画像を見て崩れを見つけるのは得意だったが、デザインの好みについては筆者が何も指定していないので、Claudeが選んだ配色と髪型になっている。 自分のキャラクターを作りたいなら、三面図や色の指定を最初に渡し、毎回の画像を人も見て「ここをこうしたい」と返す使い方になる。

まとめ

  • 3Dのスキルがなくても、Claude CodeにBlenderのスクリプトを書かせれば、表情・骨・揺れもの付きのVRMを1体作れた。人が決めたのはデフォルメで試すことだけだった
  • 目と口を頭の表面に投影する貼り絵にすると、表情は2Dの変形を書くだけで作れる。陰色を基本色と同じにして、絵の部分には陰を落とさない
  • 前髪の切り抜き、全身のシェイプキー、Aポーズ、位置で選ぶ重み付けで手戻りが出た。どれも描画した画像を見て気づけた
  • 成立したのは、デフォルメの体型、貼り絵の顔、画像で確認するループがそろっていたから。好みの判断は人に残る

続編のClaudeが作った3DキャラをVTuberにするでは、このモデルを作り込み、リップシンク・うなずき・顔トラッキングで動かし、AI生成モデルとも比べた。

理解度チェック

問題 0 / 50%
Q1

今回のモデルで、目や口のパーツに陰が落ちないようにした方法はどれか。

キーボード: 1〜4 で選択、Enter で回答