polywright
3Dモデル作業のハブ。モデルの制作方法を決定し、すべてのアセットをマニフェストとともに1つのフォルダにまとめ、各ステップを数値と画像で検証します。兄弟スキルが詳細を担います。
スクリプト: このスキルフォルダ内の scripts/pw.py(Python 3.9+、標準ライブラリ、コマンドごとに1つのJSONオブジェクトを出力)。scripts/pw_bpy.py はそのBlender版で、手動実行はしません。
セッション開始時に python <このフォルダ>/scripts/pw.py doctor を1度実行してください。Blender(全OS)、Pythonメッシュライブラリ、スライサー、ComfyUIホストを検出し、不足しているものを表示します。コマンド一覧: references/cli.md
ステップ1: ブリーフィング(推測できないことだけ尋ねる)
- What: オブジェクトまたは場所(実在・架空)、およびその認識精度の要件。
- Targets:
pw.py check --listの1つ以上(game-roblox、game-unity、game-unreal、web-threejs、ar-usdz、commerce-gltf、print-fdm、print-resin、video-blockout、cad-step)。ターゲットが予算を決定します。 - 実寸(メートル単位): ベンチは1.8m、人は1.7~1.8m。誤ったスケールは最も多い沈黙のエラーです。
check --real-size-mで検出します。 - 入力: プロンプト、写真、スケッチ、寸法、地図上の位置、既存のメッシュ。
- 忠実度と予算: ブロックアウト、ゲーム対応、ヒーロー。ホスト型生成機能にかけられる時間や費用。
スキャフォールド: pw.py new <dir> --name <Name> --kind real|imagined|hybrid --route <route> --targets a,b --real-size-m X
フォルダ構成: refs/(各ソースを記録した参照)、work/(.blend、中間ファイル)、out/(ターゲットごとに1つの納品物)、renders/(レビューシート)、brief.md、manifest.json。他のプラグインとの契約: references/contract.md
ステップ2: ルート選択(ブリーフィングを満たす最も安価な方法)
| 状況 | ルート | スキル |
|---|---|---|
| 一般的なオブジェクト、ライセンスが再利用を許可 | find: Poly Haven、Kenney、Quaternius(CC0)、Sketchfab、印刷サイト(各ライセンスを確認) | このスキル、references/routes.md |
| 寸法、はめ合い部品、鋭いエッジがある(ブラケット、ケース、建物、家具) | code (--route procedural): bpy、build123d/CadQuery/OpenSCAD | polywright-generate、polywright-blender |
| 実在の場所(公園、通り、キャンパス、地形) | place: OSM + 標高 (pw.py place) | polywright-capture |
| 写真撮影やスキャンが可能な実在の物体 | capture: 写真測量、スプラット、スキャナー、または寸法からのモデル | polywright-capture |
| 架空の有機物や一点物(彫像、クリーチャー、小道具) | generate: リファレンスシート → 画像-to-3D | polywright-references、polywright-generate |
| 変形するヒーローキャラクター | ベースを生成またはスカルプトし、その後リトポロジーとリギング | polywright-generate、polywright-finish |
ほとんどの良い結果はルートを組み合わせます。OSMの公園に生成したヒーロープロップ、コードで建てた家に生成した彫像など。パートごとのルートをマニフェストに記録します。
ステップ3: ジオメトリより先にリファレンス
既製品が見つからないものについては、最初にリファレンスを収集または生成します(polywright-references): 共通の地平線と高さバーを持つ正投影ビュー、マテリアルスウォッチ、スケール参照。生成された入力が画像-to-3D結果のほとんどを決定します。
ステップ4: 構築、そして証明(すべてのルート)
- 最初にブロックアウト(実寸で): シルエットとプロポーションのためのプリミティブ。ここでスケールを修正します。今なら安上がりです。
- 数値:
pw.py inspect <file>: 三角形、オブジェクト、サイズ、マテリアル、テクスチャ、UV、ウォータータイト、パーツ。破壊的なステップの前後で必ず読みます。 - 画像:
pw.py render <file> --out renders/<step>: 6つのビューと1枚のsheet.png。6枚のスクリーンショットではなく、シートを読みます。リファレンスと比較: シルエット、プロポーション、欠落または浮遊部品、シェーディングのスパイク、軸の誤り(横向き)、スケールの誤り。 - ターゲット:
pw.py check <file> --target <t> --real-size-m X。不合格は納品前に修正。警告は引き継ぎ時に明記。 - 記録:
pw.py manifest <dir> --add-output out/<file> --target <t> --inspect、すべてのソースを--add-source <url> --licence <l> --author <a>で追加し、--validateを実行。
計画、実行、批評は別々のパスです。構築後、批評家のようにシートを見て、完了を宣言する前に欠陥を列挙します。トレースバックの修正は2ラウンドまで価値があります。それ以上はアプローチを再検討します。マイルストーンごとに番号付きの .blend を保存します(work/<name>_v03.blend)。長時間のジョブがディスクから再開できます。
モデルを画像に合成
画像や動画モデルが設計されたプロップを描き続ける場合(ストーリーボードの静止画、セットの参照、ポスターなど)、画像から構図を、モデルから形状を取得します。
- 構図のみのために画像を選びます: 人の立ち位置、光、狙い。単純な代用プロップでかまいません。
pw.py match model.blend --still pic.png --out work/match.png --anchor-px X,Y --anchor-local=X,Y,Z --aim-px X,Y --aim-local=X,Y,Z --depth M --horizon ROW --hide BOX --mask-add BOX: モデルのアンカー(グリップ)が手に、エイムポイント(先端)が正確なピクセルに着地し、画像のレンズと地平線でRGBAレンダリング。--depthは、モデルの幅(ピクセル)が代用プロップの幅と一致するように設定します(幅 = f_px × 直径 / 深度; f_px は結果に含まれます)。--hideは手の後ろの部分を非表示にし、--mask-addは手をマスクに追加します。match_paste.pngを3倍に拡大して読みます: 形状、フレーム内のサイズ、狙い。深度とピクセルを修正し、再実行(数秒)。match_mask.png内で、マスクされた低ノイズ除去画像編集(FLUX.2 Klein または任意のインペイントモデル: ノイズ除去0.3~0.5、低cfg)でブレンドし、結果をマスクを通して貼り付け、外側のすべてのピクセルが画像自体のままになるようにします。画像全体の編集はすべてを再描画します(HDR色、より大きなプロップ)。- フルサイズで確認。2つ以上のシードを保持します。
プロップのリファレンスシートもモデルから取得します(polywright-references、ステップ2b)。
モデルからのゲームスプライト
画像モデルがゲームスプライトでメカニズムを間違え続ける場合(丸くない車輪、屋根の上の刃など)、モデルを構築し、ゲームのカメラを通してレンダリングし、画像モデルにはペイントのみを任せます。
pw.py spritecam <registry.json> --like <sprite> --out camera.json: ゲームのグラウンドダイヤモンド(L-014)からフィッティングされた正射投影カメラ。その中のtile_mをモデルの1タイルあたりのメートル数に設定します。- シーンプロパティ
sprite_partsのオブジェクトごとのパートプレフィックス(wheel_、roof_...)でモデルを構築し、可動部品をピボットの空間で構築されたピボットエンプティの下に配置し、モーションをシーンプロパティloopに設定します。 pw.py sprite model.blend --camera camera.json --out renders/L1 --scale 10.6667(96pxスプライトに対して1024px):sheetスタイルでパスとビューティをゲームのスプライトの隣で1倍で読みます。アニメーションパーツには--frames N --frame-passes id,pos、プレートなしの場合は--hide wheel_を使用。 その後、ペイント前にゲームの隣接スプライトとサイズを比較します:aw.py sprite <96pxのビューティ> --refs <同クラスのスプライト>は、それらの中央値の0.9未満のカバレッジで失敗します。ダイヤモンドフィットは地面のスケールを設定しますが、建物の見た目の大きさは設定しません。まずマッシングとプロップを追加し(より高い壁、庇、庭)、次にpx_per_tileを上げてfootprint_centre_pxを移動し、バウンディングボックスが隣接スプライトのようにキャンバス全体に広がるようにします(L-016)。円柱のシルエットから細い梁を遠ざけます。傾斜したレール上の水平な丸太は、それらの上下を通過しているように読み取られます(L-017)。- 粘土のCannyをコントロールとして(ControlNetを使用した画像モデル)ビューティをペイントし、レンダリングのアルファで切り抜いてフレーミングと
groundBaseが正確に保たれるようにし、その後sprite.jsonのIDとリムデータに対してペイントをチェックします。
モデルからのシーンイラスト
ローディング画面、キーアート、既存のモデル(建物、機械)を囲むカバー: シーンをBlenderで構築し、画像モデルにペイントさせることで、メカニズムとレイアウトを正確に保ちます。
- シーンプロパティ
scene_partsのオブジェクトごとのパートプレフィックスでモデルの周囲にシーンを構築し、車輪やディスクはringsに、キーポイントやパスはscene_pointsに配置します。パスに沿った土手、堤防、壁はそれぞれ1つのsweepです(pw.py bpyスクリプトでscripts/pw_scene.pyからインポート。箱を並べたものではありません(L-020))。 pw.py framecam problem.json --out cameras.json: ワールドポイントとスクリーンボックス、テキストバンド内および外に保持されるポイント、最大化するサイズメジャー。最適なカメラをプリセットとして出力します。バンドは実際のUIファイル(そのパディングとアンカー)から取得し、経験則からは取得しません(L-018)。pw.py scene scene.blend --cameras cameras.json --camera framecam_1 --out renders/v1 --size 1280x720(ペインティングワークフローの最初のパスサイズ): 粘土、ビューティ、深度、法線、ID、ライン、scene.json。最初に粘土と深度を読みます。深度範囲は、プリセットで固定が必要でない限り、シーン自身の測定に任せます(L-019)。- コントロール(深度またはライン)でペイントし、
scene.jsonに対してペイントをゲートします: リングリム、ポイント、ID色。
群衆と戦闘のブロックアウト(AI動画)
動画モデルは群衆に弱い。Blenderはそうではない。Blenderに軍隊を配置させ、動画モデルに見た目をペイントさせます。
pw.py crowd --out work/crowd --action clash --preview(または march、advance、charge、hold;--view、--lens、--move)、その後work/crowd/sheet.pngを読みます。- フルショットの場合は
--previewを外します:depth.mp4(メインコントロール)、pose.mp4(前列)、mask.mp4、clay.mp4、camera.json。デフォルトでは832x480、16fpsで81フレーム(Wan)。 - clayフレーム1を承認済みの開始静止画に再ペイントし、その静止画と深度動画でWan VACEまたはWan 2.2 Fun Controlを駆動します。コスチューム、サイドごとの色、光、もやをプロンプトします。頭数はプロンプトしません。
詳細と未テストの内容: references/crowd-blockouts.md。ショット計画は cinewright の担当です。
2人の戦闘: pw.py duel shot.json --preview は、ショットのカメラを通して、2体のマネキンを設定内のマークにポーズさせます(examples/duel.json)。sheet.png を読み、その後 --preview を外して各コントロールのmp4を取得します。詳細: crowd-blockouts.md、「Two fighters」。
少数の実在のフィギュアやおもちゃ(サイドが入れ替わった、余分なフィギュア、マーキングが失われた): 各々を写真からメッシュ化し、pw.py mark で色とペイントマーキングを修正し、動画モデルに pw.py turnaround の画像をリファレンスとして、pw.py lineup(固定サイドのチーム、深度とマスク)をオープニングとして提供します: references/figures-for-video.md
映画ショットのセットとプロップ: references/film-and-video.md
ステップ5: 仕上げと引き渡し
ターゲットごとの仕上げ(UV、LOD、法線マップ規約、軸と単位の変換、圧縮)は polywright-finish。印刷(ウォータータイトソリッド、壁、ベース、分割、3MF)は polywright-print。フォルダを使用するプラグインに引き渡します: three.jsページ(threewright)、映画と動画(cinewright)、Robloxプレイス(roblox-agent)、Unityプロジェクト(unity-agent)、印刷設定用のプリンター固有またはスライサースキル、さらに画像を生成する画像スキル。それらは manifest.json と out/ を読み取ります。
引き継ぎメッセージ:
Model: <name> (<route>) -> out/<file> for <target>: <tris> tris, <size> m, <watertight/parts>
Check: <target> pass|warn (<rules>) Review: renders/<step>/sheet.png
Sources: <n> with licences; AI-made parts: <which, which model> Owed: <what is not done>
ルール
- BlenderとglTFでは実寸(メートル単位)(Blenderは+Z上、glTFは+Y上)。印刷ファイルのみミリメートル。
- ファイル名や生成元の言葉だけでメッシュが問題ないと主張してはならない。インスペクト、レンダリング、チェックすること。
- ダウンロードまたは生成されたすべての入力に対して、ライセンス付きのソース行を取得する。ストアや印刷サイト(Fab、Unity Asset Store、Sketchfab、MakerWorld、Printables、Steam)はAI生成コンテンツの開示を要求する。マニフェストはそれを記録する。
- MCP経由のBlenderブリッジは任意のPythonを実行する。コピーに対して
pw.py bpyを推奨。ユーザーが監視している場合のみライブMCPセッションを使用する(polywright-blender)。 - Google Photorealistic 3D Tilesは表示のみ可能。エクスポート、キャッシュ、トレースは不可(同社の利用規約)。
メンテナンス
エバーグリーンユニット、ティア fast(ジェネレーターとBlenderは毎月更新)。付属: RESEARCH.md、CHANGELOG.md、LEARNINGS.md、TESTS.md(evals/evals.json を含む)、MAINTENANCE.md、evergreen.json の状態。使用のたびに evergreen.json を読む。期限が来たらタスクを実行し、その後リフレッシュ(evergreen-refresh)。教訓をその都度 LEARNINGS.md に書き込む。