サービスロボット導入シミュレーション Log#45 | 受け渡しを寄りで見せる、ハコブくんと看護師の3D

この記事の素材(コード・ログ・データ 6ファイル・まとめてダウンロードあり)
AIで読む ChatGPT・Claude などで、この記事に質問できます

病院の搬送ロボットが看護師と薬を受け渡す場面を、シミュレーションの中で近くから見せるために、4コママンガのロボット「ハコブくん」と看護師の大城さんを、Unity で動かせる実寸の3Dモデルにした。看護師には Unity の人型の決まりどおりの骨45本と、5つの口の形を入れ、引き出しを開ける・両手で受け取る・おじぎする・困るといった姿勢を、服や肌を裂かずに付けられるようにした。 どちらも実物のロボットや人ではなく、3DCG の中の話です。

この回で良くなったこと、できるようになったことです。

  • 受け渡しの手元と顔が見せられるようになった。これまでの病院の1日のシミュレーションでは、人は青い筒、ロボットは白い箱で、真上から見るだけだった。今回の2つのモデルは同じ見た目の決まりで作ったので、横に並べても浮かない
  • 形を言葉で直せるようになった。体の寸法はすべて Python のコードの中の数字で、骨の位置もその数字から決まる。「首が長い」「腕が長い」と言われたら数字を変えて作り直すだけで、骨も一緒に合う。看護師の形は、この方法で15回作り直した
  • 歩く動きを自分で作らずにすむ。Adobe の Mixamo から、歩く・曲がる・うなずく・話す・おじぎなど33本の動きを借りた(Adobe の決まりで、動きのファイルは公開しない)
  • 作業の時間は、前の方法と比べられる数字を測っていない。Unity で場面を撮る依頼(依頼162)を回している途中で、かかった時間はその報告で確かめる

困っていたのは、人とロボットのやり取りが、今までの見せ方では伝わらないことでした。病院の1日のシミュレーションでは、ロボットが何回止まったか、だれとすれ違ったかは数えられます。けれど、看護師が引き出しのどこを持って、どんな顔でロボットに話しかけるのかは、筒と箱では分かりません。

試算、全体のシミュレーション、シチュエーションの細部表現、実際のロボットでリアルな動画構築といった具合に全体が構築されていければより伝わりやすくなると考えます。

この回は、その3段目(場面の細部)の始まりです。

引き出しを開けたハコブくんの前で、看護師の大城さんが少しかがんでいる3DCG。明るい灰色の地に2人だけが立っている
何をなぜどうなったか
ハコブくんの体の角とタイヤを丸め、横に厚い板を足した
人の3Dと並べると、三面図どおりの角が硬く見えた
三角形2,728 から5,804。頭と顔の画面は三面図のまま
看護師の大城さんの3Dを、マンガの三面図から作った
受け渡しの手元と顔を見せる人がいなかった
身長1.65m・三角形52,592。粘土のような簡略化した見た目
骨45本・目の骨・口5つを入れた
Unity で姿勢と表情を付けて動かすため
8つの姿勢を骨で付けて、服と肌が破れないかを確かめた
袖を別の部品にし、まるごと上腕の骨に付けた
腕を前に出すと袖が裂け、上げると袖の山がゆがんだ
腕を上げても袖の形が変わらない
Mixamo から動きを33本借りた
歩く動きの元がなかった
歩く・曲がる・うなずく・話す・おじぎなど。公開はしない
Unity で、薬を積む場面と受け取る場面を作る依頼を出した
3Dを実際の場面で動かして撮るため
依頼162 を回している途中。歩かせる依頼163 は下書き

病院の搬送ロボットのほかに、配膳ロボットを自分の店に入れたらどうなるかは、このシリーズの試算をもとにした別のページで試せます。

店の立体図(席・キッチン・配膳ロボットの通り道)導入前シミュレーション配膳ロボットを、導入前に自分の店舗でシミュレーション店舗の図面と人数から、何人で回るか・どこで止まるか・月いくらかかるかを出します

作業ログ ― 病院の場面を「試算・1日・寄り・実物」の4段で見せる

サービスロボット導入シミュレーションは、配膳ロボットのファミレスのあと、病院で検体や薬を運ぶ搬送ロボットの1日を Unity で動かしてきました。前の回(LOG491)では、職員141人の動かし方を持ち場ごとの型に替え、ロボットが走っている間の問題を1日68件から19件にしました。

病院の1日は、真上から見て数を数えるための場面です。人は青い筒、ロボットは白い箱で描いています。数は出せても、その1件1件で何が起きているのかは見えません。そこで、場面を切り取って近くで見せる段を、1日のシミュレーションとは別に作ることにしました。

この3Dでリアルな形は、今までのシミュレーションより、現場のより具体的なシチュエーションの場面を切り取って見せるために使おうと思います。モノを渡す、受け取る、トラブルの時の動き、コミュニケーションの姿などを表現できたらと思います。

段見せること道具いまの状態
1. 試算何台で、何人分の手間が浮くか
Python の試算(tools/hospital_sim/)
済み(前の回まで)
2. 全体のシミュレーション1日の動きと、問題の数
Unity の病院の1日(真上から)
回している
3. 場面の細部
渡す・受け取る・トラブル・話しかける
Unity の場面の寄り(Closeups)
この回で始めた
4. 実物の動画実際のロボットで同じ場面実機まだ

3段目に使うのは、マンガ『ハコブくん』の2人です。ロボットのハコブくんと、看護師の大城さん。マンガの三面図がすでにあるので、形をゼロから決めずにすみます。

作業ログ ― ハコブくんの3Dを、人と並ぶ形に丸めた

Blender は、3DCG を作る無料のソフト

Blender は、3Dの形を作り、色を付け、絵に描き出す(レンダリングする)ための無料のソフトです。この回では画面を開かず、Python から Blender を動かしています(pip install bpy で入る、Blender を Python の部品にしたもの)。

言葉意味
メッシュ
三角形をつないだ形。三角形の数が多いほど細かいが、Unity で重くなる
FBX
形と骨と動きを1つにまとめるファイルの形式。Unity がそのまま読める
モディファイア
形に後からかける加工(三角形を減らす・角を丸めるなど)
Cycles
Blender の中の、光の当たり方を計算して絵を描く仕組み

このプロジェクトでは、形も確認用の絵もすべてコードで作り、コードを GitHub(p2m-site の tools/)に置いています。同じコードを動かせば、同じ形ができます。

ハコブくんの3Dモデルは、三面図から測った実寸の箱だった

ハコブくんの3Dは、先に三面図から作ってありました(p2m-site の 92e9b80)。三面図の外形を測り、幅0.653・奥行0.760・高さ1.150m の実寸で、三角形は2,728。軽く、Unity の病院でそのまま走らせられる形です。

ところが、看護師の3D(次の節)が粘土のような丸い見た目になると、並べた時にハコブくんの角だけが硬く見えました。そこで体の角を丸めることにしました。

  • ねらい:人と並べた時に、同じ世界の物に見えるようにする
  • 変わったこと:胴の縦の角を三面図の3.5倍の半径に丸め、台・黒い帯・引き出しの前の板・トレーの角も丸めた。タイヤは太くして角を丸め、上半分を台の中に隠した。横に、輪の付いた厚い板(厚さ約2cm)を足した。三角形は5,804
  • 見込める効果:寄りの場面で、ロボットだけが別の絵から切り抜いたように見えなくなる(見た目の話なので、数字では測っていない。Unity で撮った静止画を見て確かめる)
丸める前(左)と丸めた後(右)のハコブくん。右は体の角とタイヤが丸く、横の輪の所に厚い板がある

顔の画面のまわりは、丸めずに三面図のまま残した

最初は頭も含めて全体を丸めました。すると頭の上の丸みが画面の上の縁を押して、画面の上に白い線が出ました。画面が体から浮いて、立体の板のようにも見えました。

見直しで受けた指摘は3つです。顔の画面には手を入れないこと(上の線は消し、画面に立体感を付けない)、顔のまわりまで丸くすると変に見えること、画面の所は斜めにスパッと切れていること。三面図のハコブくんは、頭の前が斜めに切り落とされ、そこに画面がはまっています。

そこで、丸めるのは体だけにしました。高さの6.4割から下は丸め、7割までで三面図の角に戻します。頭の上を丸くする処理(dome)は止めました。

お腹の横の丸みは、マンガのハコブくんから足した

次に、お腹のあたりの丸みを足すよう指示がありました。マンガのページ(pixelstomotors.com/manga-archive )を見直すと、ハコブくんの横の、輪が付いている所がふくらんで描かれています。三面図の横の板の輪郭を測った線(F["pod"])に沿って、厚さ0.022m・ふちの丸み0.02m の板を両側に足しました。輪は板の表面に乗せています。横の板の所だけ、幅は0.674m になります。

タイヤも直しました。三面図どおりの細い車輪は、丸めた体の下では棒のように見えました。半径0.046m・幅0.052m・20角の太いタイヤにして、角を0.013m 丸め、上半分を台の中に隠しています。

この形を、ハコブくんのもとの形にすることにしました(p2m-site の fae15fa)。

ハコブくんの三面図(左)と3Dモデル(右)、斜めから見た形、人(1.6m の筒)との大きさ、引き出しを開けた所。三角形5,804

作業ログ ― 看護師の大城さんを、式で書いた形から作った

形を「表面からの距離」の式で書き、格子で面にした

看護師の形は、部品ごとに「その点が表面からどれだけ離れているか」を返す式で書きました。この式を SDF(符号付き距離関数)と呼びます。点が形の中にあれば負、外にあれば正の数を返します。頭は楕円体、腕や指は両端の丸い円柱(カプセル)、胴は角を丸めた箱、というように簡単な形の式を書き、なめらかに足したり削ったりして組み合わせます。

式で書いた形は、そのままでは Unity に入りません。空間を2.5mm 角の格子に区切って式の値を調べ、値が0になる所(表面)に三角形を張ります。これをマーチングキューブ法と呼び、scikit-image の marching_cubes を使いました。できた細かい面を、Blender のモディファイアで三角形を減らして軽くしています。

言葉意味
SDF
点から形の表面までの距離を返す式。中は負、外は正
smin / smax
2つの形を、つなぎ目がなめらかになるように足す・削る式
マーチングキューブ法
格子の上で式の値が0になる所に三角形を張り、面にする方法
格子の大きさ
細かいほど形は正確だが、三角形が増える。今回は2.5mm

この作り方を選んだのは、形を言葉で直せるからです。首の長さも肩の丸みも、コードの中の1つの数字です。骨の位置も同じ数字から決めているので、形を直すと骨も一緒に合います。

平らな面に穴があいたのは、格子の点がちょうど表面に乗ったため

途中で2つつまずきました。1つは、胴を楕円体の式で書いたら、胴がふくらみすぎたことです。楕円体の正しい距離は簡単な式では出せず、近似の式は細長い形ほどずれます。胴は角を丸めた箱の式に替えました。

もう1つは、胴の平らな面に穴があいたことです。格子の点がちょうど平らな面の上に乗ると、式の値が0ぴったりになり、面を張る向きが決まらなくなります。格子全体を、格子の幅の0.37倍だけずらして解決しました(nurse_build.py の mesh_of の最初の行)。

看護師の見た目は、マンガの三面図と「デフォルメしすぎない」で決めた

マンガ『ハコブくん』の看護師、大城さんの三面図(正面・背中・横)。V ネックのスクラブ、胸ポケット、すそのポケット2つ、低いお団子の髪

見た目の決まりは次のとおりです。

  • 粘土のような簡略化した見た目。ただしデフォルメしすぎない。頭は身長の約7分の1
  • 服はマンガのとおり。V ネックのスクラブ、胸ポケット1つ、すそのポケット2つ、まっすぐなパンツ、白い靴。ナースキャップはなし。色はロイヤルブルー
  • 髪は低いお団子と、横に流した前髪
  • 目はハコブくんの縦長の目に少し寄せる。同じにはしない

最初の形を見て返ってきた指摘です。

首長すぎ、肩がいかつすぎ、後ろの首元が変。Vネックが変。体が長すぎる?のかな。

ここから、首を短くし、肩をなで肩にし、腕を短くし、目を大きくしました。V ネックは浅くし、襟元のつなぎ目を整えました。直した所と、変えた数字の主なものです。

直した所変えたこと
首が長い
頭の中心を1.516m に下げ、首の円柱を短くした
肩がいかつい
肩の線を、首から外へ下がる斜めの面で削った(`1.372 - 0.25*clip(
腕が長い
肩の高さ1.300m、上腕0.250m、前腕0.220m
目が小さい
目を大きくし、縦長の丸(ハコブくんの目)と楕円の間の形にした
襟元のつなぎ目が変
V の切り込みと首まわりの切り込みを、なめらかに合わせた(smin)
V ネックが深い
V の底を1.288m に上げた(`1.288 + 1.15
最初の形(左の2つ)と、直した形(右の2つ)。最初は首が長く肩が角ばり、V ネックが深い。直した形は首が短く、なで肩で、胸ポケットとすそのポケットがある

作業ログ ― 骨と口を入れ、腕を動かしても袖が裂けない形にした

Unity の Humanoid は、人型の骨に決まった名前を付ける仕組み

Unity は、人型の骨に決まった名前(Hips・Spine・Chest・Neck・Head・LeftUpperArm など)が付いていると、Humanoid(人型)として読みます。Humanoid として読めれば、ほかの人型のために作られた歩く・手を振るといった動きを、骨の長さが違っても当てはめられます(リターゲット)。

言葉意味
骨(ボーン)
形の中に入れる、動かすための見えない棒。親子につながる
重み(ウェイト)
形の頂点が、どの骨にどれだけついて動くかの割合。合計は1
Avatar
Unity が、骨の名前と人型の部位の対応を覚えておくもの
リターゲット
別の人型のために作った動きを、この人型の骨に当てはめること

看護師の骨は45本です。体(Hips → Spine → Chest → Neck → Head)、左右の腕(Shoulder → UpperArm → LowerArm → Hand)、左右の指5本(Proximal → Intermediate の2節)、左右の脚(UpperLeg → LowerLeg → Foot → Toes)。このほかに、Humanoid に入れない顔の骨として、目(Eye_L・Eye_R。上下につぶすとまばたき)と眉(Brow_L・Brow_R。回すと困り顔)を入れました。口は骨ではなく、笑顔・まっすぐ・困り・話す・驚くの5つの部品を作り、表示を切り替えます。

重みは、骨ごとに「その骨が受け持つ範囲」の式を書き、頂点からその範囲までの距離が近いほど重くなるように決めました。1つの頂点につく骨は、重い順に4本までです。

8つの姿勢を骨で付けて、服と肌が破れないかを確かめた

骨と重みが合っているかは、姿勢を付けて描いて確かめます。立つ・片手で差し出す・両手で受け取る・引き出しの物をつかむ・指で示す(話す口)・おじぎ・困った(眉と口)・話しかける、の8つです(nurse_pose.py)。指の骨は、x 軸のまわりに回すと手のひらのほうへ曲がる向きにしてあります。

骨で姿勢を付けた看護師の8つの姿勢。立つ、片手で差し出す、両手で受け取る、引き出しの物をつかむ、指で示す、おじぎ、困った、話しかける

袖は、裂けた・まだ裂けた・ゆがんだ、の3回で直った

いちばん手間がかかったのは袖です。

体が動いた時に服の袖が切れてるよ。修正してください。

1回目は、腕を前に出すと、袖と胴の継ぎ目が裂けて、すき間から肌が見えました。袖が胴と1つの面になっていて、胴の側は胸の骨、袖の側は腕の骨について動くので、その間が引きのばされて切れていました。袖を胴から切り離し、別の部品(Nurse_Sleeves)にしました。

2回目は、まだ裂けて見えると言われました。袖を離しても、袖の中に隠れている腕の付け根の肌が、腕を上げると袖の外へ突き出ていました。袖の中に入る所の肌は作らないことにしました(腕の骨の向きに沿って0.134m より付け根の肌を消した)。

3回目は、腕を上げた所で袖の山がゆがんでいました。2回目までは、袖の付け根4cm を肩の骨と腕の骨で分け合い、そこから先を腕の骨だけで動かしていました。腕を上げると、肩の骨についた袖の山は動かず、腕の骨についた所だけが回るので、その間の4cm がねじれます。袖をまるごと上腕の骨に付けると、腕を上げても袖の形が変わらなくなりました。 袖の山は肩の関節のすぐ外にあるので、腕と一緒に回しても肩から離れません。上の図解で、2つの付け方を比べられます。

  • ねらい:腕をどこへ動かしても、袖が裂けたりゆがんだりしないようにする
  • 変わったこと:袖を胴から離した別の部品にし、袖の中の肌を消し、袖の重みをすべて上腕の骨にした
  • 見込める効果:Unity で Mixamo の動き(腕を大きく振る・手を振る・物を拾う)を当てても、袖を直さずにすむ。Unity で腕を上げた所の静止画を見て確かめる(依頼163 の確かめ (g))
腕を上げた姿勢の袖の寄り(直したあと)。袖の山が肩につながったまま、腕と一緒に回っている

袖を直した版は、この記事の時点ではまだ p2m-site に入れていません。Unity の依頼162 が、直す前の FBX(md5 09c296c50f88d39156fbcd62223b7d3e)を読んで回っている途中だからです。依頼162 が終わってから入れ替えます(直した版の md5 は 351b47d08b4a6c6fcbfa90a6d39479fc)。

作業ログ ― 歩く動きは Mixamo から借りた

Mixamo は、人型の動きを無料で借りられる Adobe のサービス

Mixamo は、人型の動き(歩く・走る・手を振る・おじぎなど)を無料で借りられる Adobe のサービスです。使うには Adobe のアカウントが要ります。動きは FBX でダウンロードでき、Unity の Humanoid として読めば、この看護師の骨に当てはめられます。

言葉意味
Without Skin
形を付けず、骨と動きだけをダウンロードする設定
パック
歩く・曲がる・止まるなど、組で使う動きをまとめたもの
Root Motion
動きの中の、体ごとの前進や回転。これで歩かせると足が床をすべりにくい

歩く動きの元がないことは、Unity の依頼162 を書いた時点で分かっていました。依頼162 では「足を交互に出す簡単な動きで作り、不自然なら足元を外して撮る」としてあり、どこから借りるかは決めていませんでした。Mixamo を使ってよいことになったので、借りました。

ダウンロードは、Mac の Claude のアプリの中のブラウザで行いました。Adobe へのログインは、パスワードを Claude が入れずに、画面の上で本人が入れています。動きはどれも骨だけ(Without Skin)・30fps で、Mixamo の見本の人型(Sporty Granny)の骨で書き出されています。

まとまり本数中身
Female Locomotion Pack
10
立って待つ・歩く・走る・左右に曲がる・横歩き・跳ぶ
Gestures Pack Basic
15
うなずく・首を横に振る・考えながら首を振る・ほっと息をつく・目をそらす・体重を移す など
1本ずつ8
歩き始め・歩き終わり・話す・軽いおじぎ・物を拾う・前を指す・不安そうに見回す・手を振る

Mixamo の動きのファイルは、Adobe の決まりにより、そのままの形では配りません。置く場所は Unity の作業場所(ServiceSim の Assets/ServiceSim/Models/Animations/)だけにし、GitHub・iCloud・KIOXIA には写しません。この記事に載せるのは、ファイルの名前と md5 の一覧だけです。置き場所は MASTER の保存先の表に足しました。

mixamo_20261113/md5.txt(ダウンロードした33本の一覧)

a687bcbe21d11888301796f6404ba956  gestures/acknowledging.fbx
76c1f889a4fea5670842a25dd1fa3483  gestures/angry gesture.fbx
be0df202946df81566d4ce9bf08dbb0d  gestures/annoyed head shake.fbx
782d4a7b69b0ba5c63c855cb8285a7de  gestures/being cocky.fbx
f640659145f102aa9223cfb5a300ea0b  gestures/dismissing gesture.fbx
891a60cadbb619866ff96cde0cbac366  gestures/happy hand gesture.fbx
b473e16c4ce55bb5ee8d941498dc7925  gestures/hard head nod.fbx
138945177361dea073417b4212702d92  gestures/head nod yes.fbx
417ba747f380ed6bd1bed3bff139b73e  gestures/lengthy head nod.fbx
3bb10d47206d3e56b75f4c9c1a7fad0f  gestures/look away gesture.fbx
2827de3c6f40bfe2a77cb4360a40b209  gestures/relieved sigh.fbx
a3597439d1da0271adc2c4a6aeea6ee3  gestures/sarcastic head nod.fbx
45968fbaa4bca607eadef28f2096a09c  gestures/shaking head no.fbx
f4eef6b7ebc44ed8f9253937bc7b4dae  gestures/thoughtful head shake.fbx
d6cb0a523f1ff47545bc01defabac1f1  gestures/weight shift.fbx
6915a6ee6c64f41fd379b09d3ed3add3  locomotion/idle.fbx
d550b4b10d2a4502b70dc14bd4455d1f  locomotion/jump.fbx
bf0013704cf4b1aa26c43400b79b522c  locomotion/left strafe walk.fbx
39c8c7aa23e6050adfc1d023c02c84ab  locomotion/left strafe.fbx
4567284397e012d67a840e234fd9d9a9  locomotion/left turn.fbx
c150aa446d6c8e5c933ca64f0264e34b  locomotion/right strafe walk.fbx
957b87b93e6de4e38f90b1d85fe0284e  locomotion/right strafe.fbx
38d2bc6524dc6e304ba69926f44452b9  locomotion/right turn.fbx
44ee41279a2428a4f78a63b67b7c9e96  locomotion/running.fbx
6ddfaa7e1d451e82ce623d06f9b71e59  locomotion/walking.fbx
4f96afbdb76c8c710fe1b22a20587473  single/Female Start Walking.fbx
3673cc1eecf1d164c9a4e6a7daca04eb  single/Female Stop Walking.fbx
dc02bbfc1b6d1d544cec9708ef798d90  single/Nervously Look Around.fbx
da8f339e8ceb2061bdfca8451d4bdd4b  single/Picking Up Object.fbx
fb1f6e0442d397f77b6f62a2c253d06f  single/Pointing Forward.fbx
2a5012f95a55621c4697b398f47d8964  single/Quick Formal Bow.fbx
4ff8215763b5e78ac63ddf1ac6b4fb1d  single/Talking.fbx
4f7d12264ca079d78530109f4628911a  single/Waving Gesture.fbx

依頼163 で、看護師を歩かせて撮り直す

借りた動きを Unity に入れ、看護師を歩かせる依頼(依頼163)を下書きしました。依頼162 の結果を読んでから出します。中の {COMMIT} と {NURSE_MD5} は、袖を直した版を p2m-site に入れたあとに埋めます。歩く所では、足が床に着いている間に動いた距離が3cm 以内であることを確かめます。

依頼163(下書き)

---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 300
---
# 依頼163:場面の寄りに Mixamo の動きを入れ、看護師を歩かせて①積む・②受け取るを撮り直す。袖を直した看護師に差し替える

依頼162 の報告(claude_code_reports/20261113_closeup_162.txt)を読んでから始める。162 で作った場面(Assets/ServiceSim/Closeups/Closeup_Handover.unity)と台本の JSON を土台にする。

エイイチと決めたこと(2026-11-13):
- 人の動きは Mixamo から借りる(エイイチの Adobe のアカウントで借りた)。**Adobe の決まりで、Mixamo の FBX はそのまま公開しない**。置き場所は ServiceSim の Assets/ServiceSim/Models/Animations/ だけ(MASTER の保存先テーブル)。GitHub・iCloud・KIOXIA には写さない
- 看護師のモデルを、袖を直した版に差し替える(腕を上げた時に袖の山がゆがんでいた。袖をまるごと上腕の骨に付けた)

**病院の1日の場面(Assets/ServiceSim/Hospital/)・配膳の場面・それぞれの実行ファイルと台帳・共通の部品には触らない。** 触るのは Assets/ServiceSim/Closeups/・Assets/ServiceSim/Models/ の中だけ。Packages にも触らない。
**エイイチは見ていない。人に聞かないと進めない所に当たったら、その項目は止めて報告に書き、ほかは続ける。**

## 正(読むもの)
- 看護師:p2m-site main({COMMIT})の `tools/sim_people/nurse_oshiro/nurse_oshiro.fbx`(md5 {NURSE_MD5})。骨の名前・作りは依頼162 と同じ。Nurse_Sleeves の重みだけが変わった
- 動き:Assets/ServiceSim/Models/Animations/Mixamo_20261113/ に Claude が写した 33 本(元は Mac の ~/Downloads/mixamo_20261113/。md5 の一覧は同じフォルダの md5.txt)
  - locomotion/:walking・idle・left turn・right turn・left strafe walk・right strafe walk ほか(Female Locomotion Pack)
  - gestures/:head nod yes・lengthy head nod・acknowledging・thoughtful head shake・shaking head no・relieved sigh・look away gesture・weight shift ほか(Gestures Pack Basic)
  - single/:Female Start Walking・Female Stop Walking・Talking(ふつうの会話)・Quick Formal Bow・Picking Up Object・Pointing Forward・Nervously Look Around・Waving Gesture
  - どれも骨だけ(肌なし)・30fps・Mixamo の骨の名前(mixamorig:)

## 始める前に確かめること(違えば作らずに報告して終わる)
作業場所の保留 0・Unity と回し係が動いていない・KIOXIA がマウント済み・看護師の md5・動きの md5(md5.txt と合う)・依頼162 の判定

## 1. 読み込む
- 看護師の FBX を Assets/ServiceSim/Models/NurseOshiro/ で差し替える(Avatar の設定は依頼162 と同じ)
- 動きの FBX:Rig を Humanoid、Avatar は「このモデルから作る」。Root Transform の向き・高さは元の動きに合わせる(Bake Into Pose の設定は報告に書く)
- walking・idle・talking・weight shift はループにする

## 2. 場面を直す(台本の JSON の動きを、Mixamo の動きに置きかえる)
- 歩く:Female Start Walking → walking(ループ)→ Female Stop Walking。曲がる所は left turn・right turn。歩く距離は台本の位置から決め、足がすべらないこと(Root Motion で歩かせる)
- 立って待つ:idle と weight shift
- かがんで引き出しを開ける・箱を置く/取る:Picking Up Object を土台にして、手は依頼162 の IK で取っ手・トレー・箱に合わせる
- ① 積み終わったら head nod yes で軽くうなずく。② 受け取ったら Talking で話しかけ(口は talk と smile を交互に出す)、最後に Quick Formal Bow で軽くおじぎ
- まばたきは依頼162 のまま
- 一場面の長さは 25〜40秒

## 3. 確かめ(違えば 4 は撮らずに止める)
- 依頼162 の (a)〜(e) と同じ
- (f) 歩く所:足が床をすべった長さ(足が床に着いている間に動いた距離の最大)が 3cm 以内。足が床に沈む・浮くが 2cm 以内
- (g) 袖:腕を上げた所の静止画を目で見て、袖がゆがんだり裂けたりしていないか

## 4. 撮る
- 依頼162 と同じカメラ・大きさで、①と②を1本ずつ撮り直す。静止画も依頼162 と同じ種類に、歩いている全身(横から)を足す
- 出力:/Volumes/KIOXIA/r2r2r-data/service_sim/unity/closeup/20261113_closeup163/。動画と静止画は iCloud の …/サービスロボット導入シミュレーション/hospital/closeup163/ にも写し、md5 を確かめる(Mixamo の FBX は写さない)
- check-in(保留0)。実行ファイルは作らない

## 報告
claude_code_reports/20261113_closeup_163.txt に:始める前の確かめ、1 の読み込み(Humanoid の割り当て・Root Motion の設定)、2 で直したもの、3 の確かめ(表)、4 のカメラの値と動画の長さ、出力の場所、check-in の番号、決めてほしいこと(直し方の候補は作らない)。
**報告の最後の1行は必ず次のどれか**:「判定:合格」/「判定:止めた(決めてほしいことあり)」/「判定:失敗」

作業ログ ― Unity で、薬を積む場面と受け取る場面を作る依頼を出した

この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。

ファイルの一覧(6本)

01_sec06.md ― 依頼162 は、場面の寄りの最初の2つを作る / 依頼162(Claude Code に回した全文)・3,843字

02_sec07.py.txt ― 看護師の作り方:nurse_build.py(袖を直した版)・23,630字

03_sec07.py.txt ― 看護師の姿勢の確かめ:nurse_pose.py・6,286字

04_sec07.py.txt ― ハコブくんの作り方:hakobu_build.py(体の角を丸めた版・fae15fa)・34,134字

05_sec07.py.txt ― ハコブくんの確認用の絵:hakobu_render.py・5,678字

06_sec07.py.txt ― この記事の画像の作り方:scene_render.py(看護師とハコブくんを同じ床に置いて描く)・5,619字

依頼162 は、場面の寄りの最初の2つを作る

ハコブくんと看護師の FBX ができたので、Unity の場面を作る依頼を、依頼箱から Claude Code に回しました。依頼箱は、iCloud のフォルダに依頼の文を置くと、Mac の Claude Code が1件ずつ読んで実行し、報告を書く仕組みです。

作るのは、病院の1日の場面とは別の新しい場面(Assets/ServiceSim/Closeups/Closeup_Handover.unity)で、撮るのは2つです。

  • ① 薬剤部で、看護師がハコブくんの引き出しに薬の箱を積む(25〜35秒)
  • ② 届け先で、看護師がハコブくんの引き出しから箱を受け取り、話しかける(25〜35秒)

確かめる所も決めました。引き出しを開ける時に手のひらの中心と取っ手の中心が2cm 以内か、箱がトレーから浮いたりめり込んだりしていないか(1cm 以内)、看護師の手や体がハコブくんの体を突き抜けていないか、袖・首元・指が裂けていないか。どれかが外れたら撮らずに止めます。

この記事の時点で、依頼162 は回っている途中です(7時49分に始まった)。結果は次の回で書きます。

引き出しを閉めたハコブくんに、看護師が手のひらを見せて話しかけている3DCG。② の終わりの姿を、Blender で先に描いたもの

依頼162(Claude Code に回した全文)

01_sec06.md3,843字・64行・markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 300
---
# 依頼162:病院の「場面の寄り」を新しく作る。看護師がハコブくんに薬を積む場面と、届け先で受け取る場面を撮る

## ねらい
サービスロボット導入シミュレーションは、これから次の4段で見せる(エイイチ、2026-11-13):
別のタブで開く保存

作業ログ ― コードと出力の全文

看護師の作り方:nurse_build.py(袖を直した版)

形・骨・重みを作り、FBX と blend を書き出すコードです。python3 nurse_build.py <出力フォルダ> --vox 0.0025 で動きます。袖の重みの直し(weight_sleeves)が入った版で、p2m-site には依頼162 のあとで入れます。

02_sec07.py.txt23,630字・631行・python
"""粘土のような簡略化した看護師(大城さん)を、形の式(距離の場)から作る。
python3 nurse_build.py <out_dir> [--vox 0.0025]
前が -y、上が z、単位は m。身長 1.65 m。
出力:nurse_clay.blend・nurse_oshiro.fbx・nurse_report.json(部品ごとの三角形の数・骨の名前)
FBX は Unity 向け(顔が Unity の +Z、上が +Y)。骨は Unity の Humanoid の名前(Hips・LeftUpperArm など)。
口は5つの形(smile・flat・worried・talk・surprised)を別の部品で入れてあり、Unity で表示を切り替える。
"""
import math
別のタブで開く保存

袖の直しの差分(e3daa10 との差)

diff --git a/tools/sim_people/nurse_oshiro/nurse_build.py b/tools/sim_people/nurse_oshiro/nurse_build.py
index b1ada99..fe796f3 100644
--- a/tools/sim_people/nurse_oshiro/nurse_build.py
+++ b/tools/sim_people/nurse_oshiro/nurse_build.py
@@ -527,22 +527,11 @@ def weight_mesh(ob, kind):
 
 
 def weight_sleeves(ob):
-    """袖:付け根(腕の骨の根元から 4cm)だけ肩の骨と分け合い、そこから先は腕の骨だけ"""
-    gs = {}
+    """袖はまるごと上腕の骨に付ける(付け根を肩の骨と分け合うと、腕を上げた時に袖の山がゆがんだ)。
+    袖の山は肩の関節のすぐ外にあるので、腕と一緒に回しても肩から離れない"""
     for side, L in ((1, "Left"), (-1, "Right")):
-        sh, _, _, d1, _ = arm_points(side)
-        ga = ob.vertex_groups.new(name=L + "UpperArm")
-        gsh = ob.vertex_groups.new(name=L + "Shoulder")
-        for v in ob.data.vertices:
-            if v.co.x * side <= 0:
-                continue
-            proj = float(np.dot(np.array(v.co) - sh, d1))
-            w = min(max((proj + 0.01) / 0.04, 0.0), 1.0)
-            if w > 0:
-                ga.add([v.index], w, "REPLACE")
-            if w < 1:
-                gsh.add([v.index], 1 - w, "REPLACE")
-    return gs
+        g = ob.vertex_groups.new(name=L + "UpperArm")
+        g.add([v.index for v in ob.data.vertices if v.co.x * side > 0], 1.0, "REPLACE")
 
 
 def weight_whole(ob, bone):

看護師の姿勢の確かめ:nurse_pose.py

03_sec07.py.txt6,286字・209行・python
"""骨の動きを確かめる:決めた姿勢を付けて描く。
python3 nurse_pose.py <nurse_clay.blend> <出力フォルダ> [姿勢の名前...]
姿勢:rest give receive drawer point bow worried talk
(Unity では Humanoid の動き・腕の IK で動かす。ここの姿勢は、骨と重みで服や肌が破れないかの確認用)
"""
import math
import os
import sys
別のタブで開く保存

看護師の確認用の絵:nurse_render.py

"""粘土の人を描く。python3 nurse_render.py <blend> <out_dir> [views...]"""
import math
import os
import sys

import bpy  # noqa: I001
from mathutils import Vector

bpy.ops.wm.open_mainfile(filepath=sys.argv[1])
out = sys.argv[2]
want = sys.argv[3:]
os.makedirs(out, exist_ok=True)
H = 1.65
sc = bpy.context.scene
sc.render.engine = "CYCLES"
sc.cycles.device = "CPU"
sc.cycles.samples = 24
sc.cycles.use_denoising = True
sc.view_settings.view_transform = "Standard"
w = bpy.data.worlds.new("W")
sc.world = w
w.use_nodes = True
bg = w.node_tree.nodes["Background"]
bg.inputs["Color"].default_value = (0.80, 0.90, 0.89, 1)
bg.inputs["Strength"].default_value = 0.65
key = bpy.data.lights.new("K", "AREA")
key.energy = 380
key.size = 3
ko = bpy.data.objects.new("K", key)
ko.location = (-2.2, -2.8, 3.0)
ko.rotation_euler = (Vector((0, 0, 1.0)) - Vector(ko.location)).to_track_quat("-Z", "Y").to_euler()
sc.collection.objects.link(ko)
fill = bpy.data.lights.new("F", "AREA")
fill.energy = 130
fill.size = 4
fo = bpy.data.objects.new("F", fill)
fo.location = (2.8, -2.0, 1.4)
fo.rotation_euler = (Vector((0, 0, 1.0)) - Vector(fo.location)).to_track_quat("-Z", "Y").to_euler()
sc.collection.objects.link(fo)
views = {
    "front": ((0, -6, H / 2), (0, 0, H / 2), H * 1.08, (520, 1000)),
    "side": ((-6, 0, H / 2), (0, 0, H / 2), H * 1.08, (520, 1000)),
    "back": ((0, 6, H / 2), (0, 0, H / 2), H * 1.08, (520, 1000)),
    "persp": ((1.5, -3.2, 1.25), (0, 0, H * 0.52), None, (600, 1000)),
    "face": ((0.32, -1.3, 1.53), (0, 0, 1.49), 0.36, (640, 640)),
    "neck": ((0.55, -0.75, 1.42), (0.03, 0, 1.34), 0.26, (640, 640)),
    "neckback": ((-0.5, 0.9, 1.45), (0, 0, 1.34), 0.30, (640, 640)),
    "upper": ((-0.9, -2.2, 1.45), (0, 0, 1.2), None, (700, 800)),
}
for name, (loc, tgt, ortho, res) in views.items():
    if want and name not in want:
        continue
    cam = bpy.data.cameras.new("C")
    if ortho:
        cam.type = "ORTHO"
        cam.ortho_scale = ortho
    else:
        cam.lens = 55 if name == "persp" else 70
    co = bpy.data.objects.new("C", cam)
    co.location = loc
    co.rotation_euler = (Vector(tgt) - Vector(loc)).to_track_quat("-Z", "Y").to_euler()
    sc.collection.objects.link(co)
    sc.camera = co
    sc.render.resolution_x, sc.render.resolution_y = res
    sc.render.filepath = os.path.join(out, f"{name}.png")
    bpy.ops.render.render(write_still=True)
    print("wrote", name)

看護師の出力:nurse_report.json(部品ごとの三角形と骨の名前)

{
 "height_m": 1.65,
 "triangles": {
  "Nurse_Skin": 15258,
  "Nurse_Hair": 5006,
  "Nurse_Top": 9998,
  "Nurse_Sleeves": 4222,
  "Nurse_Pants": 6556,
  "Nurse_Shoes": 2520,
  "Nurse_Eyes": 2616,
  "Nurse_Brows": 1004,
  "Nurse_Mouth_smile": 1190,
  "Nurse_Mouth_flat": 878,
  "Nurse_Mouth_worried": 938,
  "Nurse_Mouth_talk": 1120,
  "Nurse_Mouth_surprised": 1286,
  "_total_triangles": 52592
 },
 "bones": [
  "Hips",
  "Spine",
  "Chest",
  "Neck",
  "Head",
  "LeftShoulder",
  "LeftUpperArm",
  "LeftLowerArm",
  "LeftHand",
  "LeftIndexProximal",
  "LeftIndexIntermediate",
  "LeftMiddleProximal",
  "LeftMiddleIntermediate",
  "LeftRingProximal",
  "LeftRingIntermediate",
  "LeftLittleProximal",
  "LeftLittleIntermediate",
  "LeftThumbProximal",
  "LeftThumbIntermediate",
  "LeftUpperLeg",
  "LeftLowerLeg",
  "LeftFoot",
  "LeftToes",
  "Eye_L",
  "Brow_L",
  "RightShoulder",
  "RightUpperArm",
  "RightLowerArm",
  "RightHand",
  "RightIndexProximal",
  "RightIndexIntermediate",
  "RightMiddleProximal",
  "RightMiddleIntermediate",
  "RightRingProximal",
  "RightRingIntermediate",
  "RightLittleProximal",
  "RightLittleIntermediate",
  "RightThumbProximal",
  "RightThumbIntermediate",
  "RightUpperLeg",
  "RightLowerLeg",
  "RightFoot",
  "RightToes",
  "Eye_R",
  "Brow_R"
 ]
}

看護師の README.md(p2m-site の tools/sim_people/nurse_oshiro/)

# 看護師(大城さん)の3Dモデル(サービスロボット導入シミュレーション・病院の場面の人)

ハコブくんと人のやり取りを、現場の具体的な場面として短く切り取って見せるための人(2026-11-13)。物を渡す・受け取る、トラブルの時の動き、話しかける姿などを Unity で動かす。マンガの大城さんの三面図(oshiro_ref.png)を元に、粘土のような簡略化した見た目で作った。

- 見た目の決まり(エイイチの指示、2026-11-13):リアルにしすぎない。デフォルメもしすぎない(頭は身長の約7分の1)。服はマンガのとおり(Vネックのスクラブ・胸ポケット1つ・すそのポケット2つ・まっすぐなパンツ・白い靴、ナースキャップなし)。色はロイヤルブルー。髪は低いお団子と横に流した前髪。目はハコブくんの縦長の目に少し寄せた形(同じにはしない)
- 大きさ:身長1.65m(髪のてっぺんまで1.642m)
- 向き:根(骨組みの Nurse_Oshiro)は床の中心。顔が Unity の +Z を向く

## 作り方

1. `pip install bpy==5.3.0 scikit-image`(Blender を Python から使う・面を作る)
2. `python3 nurse_build.py <出力フォルダ> --vox 0.0025`:nurse_oshiro.fbx・nurse_clay.blend・nurse_report.json(部品ごとの三角形の数・骨の名前)を作る
3. 確認用の絵(GitHub に入れない。iCloud の サービスロボット導入シミュレーション/hospital/people_3d/)
   - `python3 nurse_render.py <出力>/nurse_clay.blend <絵のフォルダ> front side back persp face upper`:立った姿
   - `python3 nurse_pose.py <出力>/nurse_clay.blend <絵のフォルダ>`:骨で姿勢を付けた絵(立つ・片手で差し出す・両手で受け取る・引き出しの物をつかむ・指で示す・おじぎ・困った・話しかける)。服や肌が破れないかの確認用

形は、部品ごとに「表面からの距離」を式で書き(頭・首・腕・手・指・服・髪)、格子で面にしてから三角形を減らしている。寸法はすべて nurse_build.py の中の数字で、直すときはそこを変えて作り直す。骨の位置も同じ数字から決めているので、形を直せば骨も一緒に合う。

## 中身(三角形 52,592・材質は部品ごと)

| 名前 | 中身 | 三角形 |
|---|---|---|
| Nurse_Oshiro | 骨組み(45本)。床の中心 | – |
| Nurse_Skin | 頭・首・胸元・腕・手(指5本ずつ) | 15,258 |
| Nurse_Hair | 髪(前髪・お団子) | 5,006 |
| Nurse_Top | スクラブの上の胴(Vネック・ポケット3つ) | 9,998 |
| Nurse_Sleeves | 袖(両方) | 4,222 |
| Nurse_Pants | パンツ | 6,556 |
| Nurse_Shoes | 白い靴 | 2,520 |
| Nurse_Eyes | 目 | 2,616 |
| Nurse_Brows | 眉 | 1,004 |
| Nurse_Mouth_smile | 口:笑顔(既定で表示) | 1,190 |
| Nurse_Mouth_flat / worried / talk / surprised | 口:まっすぐ・困り・話す・驚く(既定では隠してある) | 878 / 938 / 1,120 / 1,286 |

- 色は画像を使わず、部品ごとの材質の色だけ(肌・髪・服・靴・目・口)

## 骨(Unity の Humanoid にそのまま割り当てられる名前)

- 体:Hips → Spine → Chest → Neck → Head
- 腕:Left/Right の Shoulder → UpperArm → LowerArm → Hand
- 指:Left/Right の Index・Middle・Ring・Little・Thumb の Proximal → Intermediate(指先の節はない)
- 脚:Left/Right の UpperLeg → LowerLeg → Foot → Toes
- Left は本人の左。作った時の姿勢は、腕を体の横に少し開いて下ろした形(Unity の Humanoid では T ポーズに直して読ませる)
- 顔の骨(Humanoid には入れない):Eye_L・Eye_R(目を上下につぶすとまばたき)、Brow_L・Brow_R(回すと眉頭が上がって困り顔、上へ動かすと驚き顔)
- 口は骨ではなく、5つの口の部品の表示を切り替える(話す時は talk と smile/flat を交互に出す)

## 動かした時に気をつけたこと

- 袖は胴とつなげず、別の部品にしてある。つなげると、腕を前に出した時に袖と胴の継ぎ目が裂けて、すき間から肌が見えた。袖は付け根の4cmだけ肩の骨と分け合い、そこから先は上腕の骨だけで動く
- 袖の中に隠れる腕の付け根の肌は作っていない(服がのびた時に肌が服から突き出ないように)
- 指の骨の z 軸は手のひらに向けてある。骨の x 軸まわりに回すと、指が手のひらのほうへ曲がる(握る・つかむ)
- 胴の服の重みは高さで Hips・Spine・Chest に分け、境目はなめらかにつないである(おじぎで胴を曲げても段にならない)

ハコブくん(tools/sim_robots/hakobu/)と並べて使う。ハコブくんの体の角も、この人の見た目に合わせて丸めてある。

ハコブくんの作り方:hakobu_build.py(体の角を丸めた版・fae15fa)

python3 hakobu_build.py --out <出力フォルダ> で動きます。丸めの既定は --soft 3.5、横の板は既定で付きます(--no-pods で外す)。

04_sec07.py.txt34,134字・885行・python
"""ハコブくんの軽い3Dモデルを Blender(bpy)で作り、Unity 用に書き出す。

使い方:
  python3 hakobu_build.py --out <出力フォルダ> [--W 0.459 --D 0.549 --H 1.081] [--render]

大きさの既定は、病院の搬送ロボットのシミュレーションのロボット
(p2m-site tools/hospital_sim/hospital-unity-params.json の robot.size_m)。
外形は hakobu_profiles.json(三面図から測った外形)から作る。
別のタブで開く保存

ハコブくんの確認用の絵:hakobu_render.py

05_sec07.py.txt5,678字・147行・python
"""hakobu.blend から確認用の絵を書き出す(Cycles・CPU)。
使い方: python3 hakobu_render.py <hakobu.blend> <出力フォルダ> [views...] [--drawer-open 0.28]
views: front side back persp sim sim_open top
"""
import math
import os
import sys
別のタブで開く保存

ハコブくんの出力:hakobu_report.json

{
 "size_m": {
  "W": 0.653,
  "D": 0.76,
  "H": 1.15
 },
 "triangles": {
  "Hakobu_Body": 4760,
  "Hakobu_Drawer": 312,
  "Hakobu_Face": 60,
  "Hakobu_Ring": 432,
  "Hakobu_Tray_1": 60,
  "Hakobu_Tray_2": 60,
  "Hakobu_Tray_3": 60,
  "Hakobu_Tray_4": 60,
  "_total_triangles": 5804
 },
 "shell_levels": 42,
 "files": [
  "hakobu.fbx",
  "hakobu.glb"
 ]
}

ハコブくんの README.md(p2m-site の tools/sim_robots/hakobu/)

# ハコブくんの3Dモデル(サービスロボット導入シミュレーション・病院の搬送ロボットの見た目)

ハコブくんの三面図から、Blender を Python で動かして作った軽いモデル。Unity の病院の場面で、搬送ロボットの見た目として使う(2026-11-13)。

同じ場面に出る人(粘土のような簡略化した人)に合わせて、体の角を丸めた形をもとにする(2026-11-13、エイイチの決定)。頭(画面のまわり)は三面図どおりで、画面の面は斜めにスパッと切れたまま。

- 元にした絵:iCloud の ハコブくん/4コママンガ作成データ/キャラ/hakobu_front.png・hakobu_side.png・hakobu_back.png
- 大きさ:三面図のハコブくんの実寸(幅0.653・奥行0.760・高さ1.150m。幅は台の一番広い所。横の厚い板の所だけ幅0.674m)。エイイチの指示(2026-11-13)。病院の試算のロボット(hospital-unity-params.json の robot.size_m=KEENON W3 の幅0.459・奥行0.549・高さ1.081m)より大きい
- 向き:根(Hakobu)は床の中心。顔が Unity の +Z(進む向き)を向く

## 作り方

1. `python3 hakobu_profiles.py <キャラのフォルダ> hakobu_profiles.json`:三面図から外形を測る(済んでいる。三面図が変わった時だけ)
2. `pip install bpy==5.3.0`(Blender を Python から使う)→ `python3 hakobu_build.py --out <出力フォルダ>`:hakobu.fbx・hakobu_albedo.png・hakobu_emission.png・hakobu_report.json を作る。大きさの既定は実寸。`--W --D --H`(m)で変えられる。丸めの既定は `--soft 3.5`(体の角を三面図の3.5倍の半径に。`--soft 1` で三面図どおりの角)。横の厚い板は既定で付く(`--no-pods` で外す)
3. `python3 hakobu_render.py <出力>/hakobu.blend <絵のフォルダ> front side back persp sim sim_open`:確認用の絵(GitHub に入れない。iCloud の サービスロボット導入シミュレーション/hospital/hakobu_3d/)

## 中身(三角形 5,804・材質1つ)

| 名前 | 中身 | 三角形 |
|---|---|---|
| Hakobu | 根(空の物)。床の中心 | – |
| Hakobu_Body | 胴・頭・台・車輪・バンパー・横の厚い板(両側) | 4,760 |
| Hakobu_Face | 画面(顔) | 60 |
| Hakobu_Ring | 横の輪(両側) | 432 |
| Hakobu_Drawer | 引き出し(前の板・取っ手・中の箱)。前へ 0.26m まで引き出せる | 312 |
| Hakobu_Tray_1〜4 | 引き出しの中のトレー(田の字に4枚) | 60 ×4 |

- 色は1枚の画像(hakobu_albedo.png・1024px)にまとめた。光る所(目・口・輪・背中の帯)は hakobu_emission.png。材質は Hakobu_Mat の1つだけ
- 丸めたのは体だけ:胴の縦の角(高さの6.4割から下。7割までで三面図の角に戻す)、台と黒い帯の角、引き出しの前の板とトレー、タイヤ(太くして角を丸め、上半分を台の中に隠した)
- 横の厚い板:三面図の横の板(輪の付いた所)の輪郭どおりに、厚さ約2cm・ふちの丸み2cmの板を両側に足した(マンガ ep147 のハコブくんの、お腹の横のふくらみ)。輪はこの板の表面に乗る
- 横の継ぎ目・頭の帯・背中の扉と操作箱・前の引き出しのすき間は、形ではなく画像で描いている(三角形を増やさないため)
- Tray_1〜4 は FBX では根の直下にある。引き出しの子にすると、FBX の向きの変換が二重にかかってトレーが90°回る(Blender で読み直して確かめた)。Unity のプレハブで Drawer の子にする
- 輪と顔を別の部品にしてあるのは、あとで状態(移動中・止まった・完了)で色や表情を変えられるようにするため
- 4コマのチェック項目と同じ決まりを守っている:腕・脚なし、体に文字なし、輪は平らで真ん中に穴・点なし

この記事の画像の作り方:scene_render.py(看護師とハコブくんを同じ床に置いて描く)

記事の最初の画像とサムネイルは、看護師の blend にハコブくんを読み込み、姿勢を付けて描きました。python3 scene_render.py <nurse_clay.blend> <hakobu.blend> <出力> drawer 1920 1080 で動きます。背景は透明で描き、onto_bg.py でサイトのカードと同じ明るい灰色(#eceef2)に重ねています。Unity で撮った絵ではありません。

06_sec07.py.txt5,619字・166行・python
"""LOG496 用:看護師(大城さん)とハコブくんを同じ床に置いて描く(記事の画像とサムネイルの素材)。
python3 scene_render.py <nurse_clay.blend> <hakobu.blend> <出力png> <場面> [幅 高さ]
場面:drawer(引き出しの前でかがむ)・talk(立って話しかける)
背景は透明で描き、あとで #eceef2 の地に重ねる(影は床の影だけ残す)"""
import math
import os
import sys
別のタブで開く保存

onto_bg.py

"""透明で描いた絵を #eceef2 の地に重ねる。python3 onto_bg.py <入力png> <出力>"""
import sys
from PIL import Image
a = Image.open(sys.argv[1]).convert("RGBA")
bg = Image.new("RGBA", a.size, (236, 238, 242, 255))
bg.alpha_composite(a)
bg.convert("RGB").save(sys.argv[2], quality=95)

compose.py(前と後を並べる画像)

"""LOG496 の比べる画像を組む(前と後を左右に並べ、下に短い名前を書く)"""
from PIL import Image, ImageDraw, ImageFont
F = ImageFont.truetype("/usr/share/fonts/opentype/noto/NotoSansCJK-Medium.ttc", 30, index=0)
BG = (247, 247, 247)


def row(paths, labels, out, h=760, gap=24):
    ims = [Image.open(p).convert("RGB") for p in paths]
    ims = [im.resize((int(im.width * h / im.height), h), Image.LANCZOS) for im in ims]
    W = sum(i.width for i in ims) + gap * (len(ims) + 1)
    c = Image.new("RGB", (W, h + 90), BG)
    d = ImageDraw.Draw(c)
    x = gap
    for im, lb in zip(ims, labels):
        c.paste(im, (x, 0))
        if lb:
            d.text((x + 8, h + 22), lb, font=F, fill=(36, 36, 36))
        x += im.width + gap
    c.save(out)
    print(out, c.size)


H = "/home/claude/hakobu"
P = "/home/claude/people/clay"
row([f"{H}/out_real/renders/render_persp.png", f"{H}/out_base/renders/render_persp.png"],
    ["前:三面図の角のまま(三角形 2,728)", "後:体の角・タイヤを丸め、横に板(5,804)"],
    "LOG496_images/LOG496_02_hakobu_before_after.png")
row([f"{P}/out_v1/r/front.png", f"{P}/out_v1/r/side.png", f"{P}/out_final/r/front.png", f"{P}/out_final/r/side.png"],
    ["最初の形", "", "直した形", ""],
    "LOG496_images/LOG496_03_nurse_first_final.png")