scenario-patina-retexture について
scenario-patina-retextureは、単色や仮のマテリアルを持つメッシュを、Blenderで編集できるPBRマテリアルに変えるスキルです。表面の種類ごとにScenarioのPATINA Materialでマップを生成し、ローカルで処理前後の比較映像もレンダリングできます。
主な機能
- 01表面の種類ごとにマテリアルを分類
- 02シームレスなPATINAマップを生成
- 035種類のマップをBlenderのシェーダーに適用
- 04メッシュ形状とトランスフォームを維持
- 05処理前後の比較映像をレンダリング
活用シーン
- 01画像から生成した3DアセットをBlenderで再テクスチャリング
- 02色違いの素材に一貫したマテリアルを適用
- 03映像で元のシーンと再テクスチャリング後を比較
MCP 対応
ScenarioのMCPツールでPATINA Materialの検索と実行、生成アセットの取得・ダウンロード、スコープ管理を行います。ローカルのインベントリ作成、マテリアル適用、映像レンダリングは付属のBlenderおよびPythonスクリプトが担います。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-patina-retextureインストール後、Claude Code で/scenario-patina-retextureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/example-config.jsonfilm-config.mdmaterials-manifest.mdscripts/apply_materials.pycommon.pyfilm.pyinventory.pyscene.pyworker.py詳細
Scenario PATINA の再テクスチャリング
概要
マテリアルがフラットカラーや仮の素材になっているメッシュ(画像から3Dへの変換結果や、ジオラマ全体など)を、3つの手順でPBRシェーディングのアセットにします。マテリアルを物理的な表面の種類ごとにまとめ、Scenarioで種類ごとにシームレスなPATINAマテリアルを1つ生成し、頂点、面、トランスフォームを変更せずに、5つのマップをBlenderのマテリアルに接続します。オプションの動画では、同じライト、露出、カットを使い、1つのカメラパスに沿って元のシーンと再テクスチャリングしたシーンをレンダリングするため、2つのパネルの違いはマテリアルの反応だけになります。動画は3D成果物を提示するためにローカルでレンダリングし、Scenarioでは生成しません。そのため、このスキルの出力タイプは3Dのままです。
PATINAは、ScenarioにおけるPatina AIのマテリアルファミリーです(タグはsc:texture)。このスキルでは、プロンプトからマテリアルを生成するPATINA Materialを実行します。フラットテクスチャのメンバー(Image to Maps、Material Extract)はscenario-texturesに属します。メッシュ全体を3Dから3Dへのテクスチャリングモデルで再描画する場合はscenario-3dの領域ですが、このスキルではマテリアルごとの制御と、編集可能なBlenderシェーダーを維持します。エージェント自身の手順はMCP上で行います。付属スクリプト(Blender 4.2以降、Pillowとnumpyを備えたPython 3、ffmpeg)はローカルでの反復処理を担い、Scenarioを呼び出すことはありません。接続と基本的な処理の流れについては、scenarioスキルを参照してください。ここで挙げた関連スキルが利用可能なスキルにない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人で実行する場合は、ツールのスキーマに基づいて処理を進め、不足している点を明示してください。
クイックリファレンス
| 手順 | ツール | 備考 |
|---|---|---|
| 対象範囲 | teams_list, projects_list | 元のアセットと生成先は異なるプロジェクトにある場合があります。呼び出しごとに正しい組み合わせを指定してください |
| メッシュを取得する | asset_get、続いて asset_download | properties.materialCount、faceCount、hasUVs、dimensions。curl -fL で保存します |
| インベントリを作成する | Blender の inventory.py | Before.blend と inventory.json を書き出します。マテリアルごとのオブジェクト数、境界ボックス、ベースカラーが含まれます |
| PATINA を探す | target="models"、query="patina"、public=true を指定して search | PATINA Material(txt2img)を選び、実行前に model_schema_get を呼び出します |
| 料金を確認する | dry_run=true を指定した model_run | 作成時点では、1024x1024 の 5 マップセットは 17 CU でした。width、height、maps、upscaleFactor、numOutputs によって料金が変わります |
| 生成する | wait=false を指定した model_run。ファミリーごとに 1 回 | ファミリーごとに固定の seed を使い、すべての job_id に対して 1 回の jobs_wait を実行します |
| マップを識別する | 各出力に対して asset_get | metadata.type が役割を示します。位置を基準に判断しないでください |
| ダウンロードする | asset_download、続いて curl -fL | textures/<family>/<role>.png |
| 適用する | Blender の apply_materials.py | マニフェストは materials-manifest.md にあります。ジオメトリハッシュを検証します |
| フィルムを作成する | film.py の pilot、run、status | 設定は film-config.md にあります。途中から再開できます |
マテリアルファミリー
シーンではなく inventory.json を読み込みます。表面の物理的な材質(漆喰、
杉、テラコッタ、釉薬をかけた陶器、真鍮、塗装鋼、ガラス、キャンバス、アスファルト、葉)ごとにマテリアルをまとめ、
色違いには同じファミリーを再利用します。シェーダーはデフォルトで、元の各色を PATINA の
ベースカラーの下地となる色合いとして保持するため、1 セットの漆喰マテリアルでクリーム色、黄土色、灰色の壁に対応できます。同じ色が
異なる表面に使われている場合(キャンバスのオーニングと塗装された看板に使われている同じ緑など)は、オブジェクト名のプレフィックスをキーとする
object_overrides エントリで分けます。41 マテリアルのジオラマでは 14 ファミリーが必要でした。
ファミリーごとに 1 ジョブが必要だと見込んでください。メッシュにレンガ、屋根瓦、板材がすでにモデル化されている場合は、
パターンではなく 1 つの要素の材質(焼成粘土、風化した杉)をプロンプトに指定します。構造はジオメトリが表現するため、パターン付きのマップを使うと二重になります。
ファミリーごとに1セットを生成する
検出したIDに対するmodel_schema_getが仕様です。以下の名前は執筆時点のものです。
prompt(必須、2048文字)は、オブジェクトや標識のない、均一に照明されたシームレスな平面の物理的表面を記述します。mapsは、エントリーが1つでも配列にします(文字列だけを指定しても無視されます)。デフォルトの5つすべてを維持してください。widthとheightは512から2048まで16刻みで、デフォルトは1024です。tileSize(128、約1024 px)はこれらに合わせます。2048のセットでは256にしてください。そうしないと、繰り返し範囲がテクスチャと一致しなくなります。upscaleFactorの2または4は、ベーステクスチャではなく、予測されたマップのみを拡大します。tilingModeを指定すると、板材や波形材の繰り返しを1軸に制限できます。numOutputsは、1つのプロンプトから最大4つのバリエーションを返します。それぞれに料金がかかります。enablePromptExpansionはデフォルトでオンです。プロンプトを意図的に作り込んでいる場合はオフにしてください。ファミリーごとにseedを設定し、同一のファミリーを再生成できるよう、マニフェストに記録してください。
dry_runとwaitは、model_id、team_id、project_idと並べてmodel_runの最上位に指定してください。parametersの下に入れるのはモデル入力だけです。正確なペイロードの料金をdry_run=trueで見積もります(これはコストの見積もりであり、パラメーターの検証ではありません)。予算(ファミリー数×料金)を確認してから、すべてのファミリーをwait=falseで起動し、すべてのジョブIDをまとめて1回のjobs_waitに渡します(1回の呼び出しにつき32個)。タイムアウトした場合は、2回目のmodel_runを実行せず、pending_job_idsを指定して再度呼び出してください。トランスポートエラーが発生したら、再実行する前にjobs_listを使ってください。通常、ジョブはすでに登録されています。
デフォルトの5つのmapsとnumOutputs 1の場合、執筆時点では完了したジョブに6つのアセットIDが含まれていました。ベーステクスチャ(metadata.typeがinference-txt2img-texture)と、各マップに1つずつのアセットで、ラベルはtexture-albedo、texture-normal、texture-smoothness、texture-metallic、texture-heightでした。numOutputsの値に応じてセット数が増えます。asset_getで取得したmetadata.typeの値を仕様として扱い、順序ではなく5つの役割に対応付けてください。roughnessのリクエストはsmoothnessというラベルで返されます。執筆時点では値はroughnessでした(ブラッシュ仕上げの真鍮のマップは、マットなグレーのマップより暗く表示されました)。つまり、注意すべきなのはラベルであり、データではありません。マニフェストのroughness_is_smoothnessを設定する前に、仕上げがわかっているファミリーのそのマップをasset_displayで表示してください。値がtrueの場合、マップが反転されます。各マップをasset_downloadで(デフォルトではPNG形式)textures/<family>/<role>.pngにダウンロードし、プロンプト、シード、ジョブID、アセットID、スコープの組み合わせ、請求されたcuCostをマニフェストのprovenanceに記録してください。
Blenderでの適用
blender --background --factory-startup --python scripts/inventory.py -- model.glb work/を実行すると、メッシュ(GLB、glTF、OBJ、FBX)をインポートするか、.blendファイルを開き、パック済みのwork/Before.blendを保存して、work/inventory.jsonを書き出します。すべてのマテリアル名をファミリーに、すべてのファミリーを5つのマップに対応付けるwork/materials.jsonを作成します(マニフェストの参照には、すべてのキーとデフォルト値が含まれています)。次に、blender --background --factory-startup work/Before.blend --python scripts/apply_materials.py -- work/materials.jsonを実行します。このスクリプトはマニフェストを検証し、各面の優勢軸に沿ってオブジェクトのスケールで専用のPatinaUVレイヤーを投影するため、tile_spanは繰り返し1回あたりのメートル数を表します(リンクされた複製で共有されているメッシュは、最初にシングルユーザー化されます)。元の各マテリアルとファミリーに対してPrincipled BSDFを1つ構築し、画像をパックして、ジオメトリのハッシュが変更されていないことをアサートします。納品物は.blendです。glTFへのエクスポートでは、調整済みシェーダーグラフが平坦化されます(エクスポーターが保持するのは直接のテクスチャリンクだけです)。エンジンにエクスポートする前にベイクしてください。レンダリングに時間をかける前に、結果を開くか、静止画を1枚レンダリングしてください。
映画の比較
python3 scripts/film.py config.json pilot を実行すると、すべてのショットの両端を両方のパスで半分の解像度でレンダリングし、概算時間を記載した Pilot Contact.jpg を出力します。このシートを見て構図とマテリアルの欠陥を修正してから、run を実行すると、ネイティブ解像度でレンダリングし、有効なフレームを再利用し、両方のカメラシーンを編集可能な .blend ファイルとして保存したうえで、ムービーを組み立てて検証します。status は進行状況を表示します。実行フォルダーは入力ファイル、スクリプト、設定ファイルのフィンガープリントに基づいて決まるため、いずれかを変更すると新しいフォルダーが作成されます。エントリーポイントは common.py と scene.py を共有し、film.py は Blender 内で worker.py を起動します。この3つを直接実行することはありません。
1つのアセットに合う座標を使ったサンプルプランではなく、inventory.json の境界に基づいてショットを設計してください。高速プリセット(EEVEE、24サンプル、デノイズありの半解像度レイトレース反射、低速の動きを滑らかにするため12 fpsのソースを24 fpsに補間)は、ノートPCで2368x1332のフレームあたり約1秒で動作しました。そのため、サンプルプランのパスごとのソースフレーム792枚のレンダリングには、それぞれおよそ15分かかります。pilot_estimate.json を参考に調整し、速い動きには source_fps を24に設定してください。マスター全体を2 fpsでサンプリングした review/Sweep Contact.jpg で確認してください。ショットごとに1枚だけ静止画を確認する方法では、ショットの途中で現れる欠陥を見逃します。エンコーダーのログに問題がないことは、映像の品質が承認されたことを意味しません。
実践例:街並みのジオラマに新しいテクスチャを適用して比較映像を撮影する
- ユーザーがすでに承認したチーム/プロジェクトの組み合わせを使うか、
teams_listとprojects_listで一覧を取得し、選択してもらいます。承認済みの組み合わせがない状態で 自動実行する場合は、スコープが必要な呼び出しを行う前に停止し、スコープが未指定であることを 報告します。ジオラマ(画像から3Dに変換した結果。マテリアル41個、画像テクスチャなし、面数78K)に対してasset_get、asset_downloadを実行し、続けてcurl -fL -o work/street.glb "<url>"を実行します。 inventory.pyでインベントリを作成します。41個のマテリアルをplaster、cedar、terracotta、ceramic、brass、steel、glass、canvas、asphalt、leafなどの ファミリーに分類し、日よけオブジェクトにはcanvasを割り当てるオーバーライドを設定します。searchで PATINA を検索し、返された PATINA Material の ID に対してmodel_schema_getを 実行します。セッションごとに再検出します。- ファミリーごとの正確なペイロードに対して、トップレベルの
dry_run=trueを指定してmodel_runを実行します。作成時点では、各ファミリーにつき17 CU、14ファミリーで合計238 CU でした。現在の見積もりを使用してください。すでに承認された予算の範囲内で進めるか、合計額の 承認をユーザーに求めます。十分な予算が承認されていない状態で自動実行する場合は、見積もりを 返し、生成を始める前に停止します。 - トップレベルの
wait=falseを指定してmodel_runを14回呼び出します。「aged lime plaster wall, fine mineral grain, flat, evenly lit, seamless」などのプロンプトを使い、ファミリーごとにseedを固定します。続いて、14個すべての ID を指定してjobs_waitを1回呼び出し、すべての行が 完了するまで待ちます。 - 各出力に対して
asset_getを実行し、metadata.typeを読み取ります。滑らかさのラベルが付いた plaster マップに対してasset_displayを実行し、極性を確定します。asset_downloadとcurl -fLを使って、すべてのマップをtextures/<family>/にダウンロードします。 materials.jsonを作成します(ファミリーごとの roughness の範囲、確定したroughness_is_smoothness、ジョブ ID とコストを含むprovenanceを記載)。その後apply_materials.pyを実行し、PATINA.blendを一度開きます。- example-config.json をコピーし、ショットをインベントリの
バウンディングボックスに基づいて構図を決めたものに置き換えます。
pilotモードでfilm.pyを 実行して確認してから、runを実行します。マスター、共有用コピー、両方のパス、編集可能な シーン2つを引き渡し、使用した補間方法を明記します。 - オプション:
scenarioスキルのマルチパートアップロードの手順に従います。kind: "video"、file_name、content_type: "video/mp4"、バイト単位のfile_sizeを指定してupload_assetを呼び出し(dataは省略)、返された URL にすべてのパートを PUT します。 続けて、返されたupload_idと同じスコープを指定してupload_asset_completeを呼び出します。 完了後に動画アセット ID が返された場合に限り、ソースおよびマップとともにコレクションへ登録します (collection_createの後にcollection_add_assetsを実行します。カタログツールはscenario_tool_execute_write経由で実行し、引数はparametersの下に指定します)。
よくある間違い
- 出力を位置や
sourceフィールドだけで対応付けること:metadata.typeを読み取り、反転する前に 滑らかさラベルの極性を確認します。 - すでにメッシュでモデル化されているレンガ、タイル、板材をプロンプトに指定すること:模様が二重に なります。
- 看板、オブジェクト、照明について PATINA にプロンプトを指定すること:生成されるのはマテリアルであり、 シーンではありません。
jobs_waitがタイムアウトしたりmodel_runがトランスポートエラーを返したりしたために ファミリーを再生成すること:pending_job_idsを指定して再呼び出しするか、先にjobs_listを 実行します。- パイロットを行わずに映像全体をレンダリングすること、またはショットごとに静止画1枚だけを見て、 2 fps のスイープシートを確認せずに承認すること。
- 実行中に設定ファイルやスクリプトを編集して、レンダリングが再開されると期待すること: フィンガープリントが変わったため、最初からやり直されます。
- PATINA ID や17 CUという数値をハードコードすること:
searchで再検出し、dry_runで再見積もりします。