scenario-patina-retexture

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Scenario PATINA retexture

Scenario PATINA 重贴图

Overview

概述

A mesh whose materials are flat colors or placeholders (an image-to-3D result, a whole diorama) becomes a PBR-shaded asset in three moves: group its materials into physical surface families, generate one seamless PATINA material per family on Scenario, and wire the five maps into Blender materials with vertices, faces, and transforms left unchanged. An optional film renders the original and the retextured scene along one camera path with the same lights, exposure, and cut, so the material response is the only thing that differs between the two panels. The film is rendered locally to present the 3D deliverable, never generated on Scenario, so the skill's output type stays 3D.
PATINA is Patina AI's material family on Scenario (tag
sc:texture
). This skill runs PATINA Material, the prompt-to-material member; the flat-texture members (Image to Maps, Material Extract) belong to
scenario-textures
. Repainting a whole mesh with a 3D-to-3D texturing model is the
scenario-3d
lane; this one keeps per-material control and editable Blender shaders. The agent's own steps stay on MCP; the bundled scripts (Blender 4.2 or newer, Python 3 with Pillow and numpy, ffmpeg) do the local repetition and never call Scenario. Connection and the core loop: the
scenario
skill. If a sibling skill named here is missing from your available skills, ask the user to install it (
npx skills add scenario-labs/skills --skill <name>
); unattended, proceed from tool schemas and flag the gap.
材质为平色或占位符的网格(图生3D结果、完整微缩场景)可通过三步变为PBR着色资产:将其材质按物理表面族分组,在Scenario上为每个族生成一套无缝PATINA材质,再将五张贴图接入Blender材质,全程不改动顶点、面和变换信息。可选的影片功能会沿同一条相机路径渲染原始场景和重贴图后的场景,保持光照、曝光和剪辑一致,因此两个画面对比中唯一的差异就是材质表现。影片在本地渲染以展示3D交付物,绝不会在Scenario上生成,因此该技能的输出类型仍为3D。
PATINA是Patina AI在Scenario上的材质系列(标签为
sc:texture
)。本技能运行的是PATINA Material(提示词生成材质的成员);平纹材质相关的成员(Image to Maps、Material Extract)属于
scenario-textures
技能。使用3D到3D贴图模型重绘整个网格属于
scenario-3d
赛道;本技能则保留逐材质控制和可编辑的Blender着色器。Agent自身的步骤都在MCP上执行;捆绑的脚本(Blender 4.2及以上版本、安装了Pillow和numpy的Python 3、ffmpeg)负责本地的重复操作,绝不会调用Scenario。连接和核心循环依赖
scenario
技能。如果你的可用技能中缺少这里提到的兄弟技能,请让用户安装(命令:
npx skills add scenario-labs/skills --skill <name>
);无人值守模式下可基于工具schema继续执行,并标记缺失的技能。

Quick reference

快速参考

StepToolNotes
Scope
teams_list
,
projects_list
The source asset and the generation destination may live in different projects: pass the right pair on every call
Fetch the mesh
asset_get
, then
asset_download
properties.materialCount
,
faceCount
,
hasUVs
,
dimensions
; save with
curl -fL
Inventoryinventory.py in BlenderWrites
Before.blend
and
inventory.json
: per-material object counts, bounds, base color
Find PATINA
search
with
target="models"
,
query="patina"
,
public=true
Pick PATINA Material (
txt2img
);
model_schema_get
before running
Price
model_run
with
dry_run=true
One 1024x1024 five-map set was 17 CU at authoring time;
width
,
height
,
maps
,
upscaleFactor
, and
numOutputs
move it
Generate
model_run
with
wait=false
, one per family
Fixed
seed
per family; one
jobs_wait
over every
job_id
Identify maps
asset_get
on each output
metadata.type
names the role; never rely on position
Download
asset_download
, then
curl -fL
textures/<family>/<role>.png
Applyapply_materials.py in BlenderManifest in materials-manifest.md; geometry hash asserted
Filmfilm.py
pilot
,
run
,
status
Config in film-config.md; resumable
步骤工具说明
范围确认
teams_list
,
projects_list
源资产和生成目标可能位于不同项目中:每次调用时都要传入正确的项目对
获取网格
asset_get
,然后调用
asset_download
获取
properties.materialCount
、
faceCount
、
hasUVs
、
dimensions
等属性;使用
curl -fL
保存
资产清点Blender中的inventory.py生成
Before.blend
和
inventory.json
:包含逐材质的对象数量、边界框、基础色
查找PATINA调用
search
,参数为
target="models"
、
query="patina"
、
public=true
选择PATINA Material(
txt2img
类型);运行前先调用
model_schema_get
成本估算调用
model_run
,参数为
dry_run=true
编写本文时,一套1024x1024的五张贴图消耗17 CU;
width
、
height
、
maps
、
upscaleFactor
和
numOutputs
会影响成本
生成材质每个族调用一次
model_run
,参数为
wait=false
每个族使用固定的
seed
;对所有
job_id
调用一次
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;支持断点续传

Material families

材质族

Read
inventory.json
, not the scene. Group materials by what the surface physically is (plaster, cedar, terracotta, glazed ceramic, brass, painted steel, glass, canvas, asphalt, foliage), reusing one family across color variants: the shader keeps each original color as a tint under the PATINA basecolor by default, so one plaster set serves cream, ochre, and grey walls. Split a shared color that sits on different surfaces (the same green on a canvas awning and a painted sign) with an
object_overrides
entry keyed by object-name prefix. A 41-material diorama needed 14 families; expect one job per family. Where the mesh already models bricks, roof tiles, or planks, prompt for the material of one element (fired clay, weathered cedar), never for the pattern: the geometry supplies the structure and a patterned map doubles it.
请读取
inventory.json
而非场景文件来分组。按表面的物理材质类型(灰泥、雪松、陶土、釉面陶瓷、黄铜、烤漆钢、玻璃、帆布、沥青、植物)对材质分组,同一种材质族可复用于不同颜色变体:默认情况下,着色器会保留每个原始颜色作为PATINA basecolor下的色调,因此一套灰泥材质可用于米色、赭石色和灰色的墙面。对于不同表面上的相同颜色(比如帆布遮阳篷和烤漆标牌上的同一种绿色),可通过以对象名称前缀为键的
object_overrides
条目来拆分。一个有41种材质的微缩场景需要14个材质族;基本上每个族对应一个生成任务。如果网格已经建模了砖块、屋顶瓦或木板的结构,提示词只需描述单个元素的材质(烧制黏土、风化雪松),绝不要描述图案:几何结构已经提供了形态,带图案的贴图会造成重复。

Generating one set per family

为每个族生成一套材质

model_schema_get
on the discovered id is the contract; the names below held at authoring time.
prompt
(required, 2048 characters) describes a flat, evenly lit, seamless physical surface with no objects or signage.
maps
is an array even for one entry (a bare string is ignored); keep the default of all five.
width
and
height
run 512 to 2048 in steps of 16, 1024 by default, and
tileSize
(128, about 1024 px) follows them: 256 for a 2048 set, or the repeat window no longer matches the texture.
upscaleFactor
2 or 4 enlarges the predicted maps only, not the base texture.
tilingMode
restricts the repeat to one axis for planks or corrugation.
numOutputs
returns up to 4 variants of one prompt, each priced.
enablePromptExpansion
is on by default: turn it off when the prompt is deliberate. Set
seed
per family and keep it in the manifest so a family can be regenerated identically.
Keep
dry_run
and
wait
at the top level of
model_run
, beside
model_id
,
team_id
, and
project_id
; only model inputs belong under
parameters
. Price the exact payload with
dry_run=true
(a cost estimate, not parameter validation), confirm the budget (families times cost), then launch every family with
wait=false
and one
jobs_wait
over all the job ids (32 per call), re-called with
pending_job_ids
on timeout rather than answered with a second
model_run
. On a transport error,
jobs_list
before re-running: the job usually landed.
With the default five
maps
and
numOutputs
1, a completed job carried six asset ids at authoring time: the base texture (
metadata.type
inference-txt2img-texture
) and one asset per map, labeled
texture-albedo
,
texture-normal
,
texture-smoothness
,
texture-metallic
, and
texture-height
;
numOutputs
multiplies the set. Treat the
metadata.type
values read back with
asset_get
as the contract and map them to the five roles, never the order. The roughness request comes back labeled smoothness, and at authoring time the values were roughness (a brushed brass map read darker than a matte grey one), so the label is the trap, not the data:
asset_display
that map for a family whose finish you know before touching
roughness_is_smoothness
in the manifest, which inverts it when true.
asset_download
each map (PNG by default) into
textures/<family>/<role>.png
, and record prompt, seed, job id, asset ids, scope pair, and billed
cuCost
under the manifest's
provenance
.
对找到的模型ID调用
model_schema_get
是官方约定;以下参数名在编写本文时有效。
prompt
(必填,最多2048字符)描述平整、光照均匀、无缝的物理表面,不能包含物体或标识。
maps
是数组类型,即使只有一个条目也要用数组(裸字符串会被忽略);建议保留默认的五张贴图。
width
和
height
的取值范围是512到2048,步长为16,默认值为1024;
tileSize
(默认128,约对应1024像素的贴图)会跟随这两个参数调整:2048尺寸的贴图对应256的
tileSize
,否则重复窗口会和贴图不匹配。
upscaleFactor
设为2或4时,仅放大预测的贴图,不放大基础纹理。
tilingMode
可用于木板或波纹材质,限制仅在单个轴向上重复。
numOutputs
最多返回4个同一提示词的变体,每个变体单独计费。
enablePromptExpansion
默认开启:如果提示词已经经过精心设计,可以关闭。为每个族设置固定的
seed
并记录在清单中,这样可以完全相同地重新生成某个材质族。
请将
dry_run
和
wait
放在
model_run
的顶层参数中,和
model_id
、
team_id
、
project_id
同级;只有模型输入参数才放在
parameters
下。使用
dry_run=true
对精确的请求体进行成本估算(这是成本预估,不是参数校验),确认预算(材质族数量乘以单个成本)后,再为所有族调用
wait=false
的
model_run
,然后对所有job ID调用一次
jobs_wait
(每次最多32个);如果超时,使用
pending_job_ids
重新调用
jobs_wait
,而不是再次发起
model_run
。如果遇到传输错误,先调用
jobs_list
再重新运行:任务通常已经提交成功。
使用默认的五张
maps
且
numOutputs
为1时,编写本文时一个完成的任务会返回6个资产ID:基础纹理(
metadata.type
为
inference-txt2img-texture
)和五张贴图资产,分别标记为
texture-albedo
、
texture-normal
、
texture-smoothness
、
texture-metallic
和
texture-height
;
numOutputs
会成倍增加资产数量。请将
asset_get
返回的
metadata.type
值作为官方约定,将其映射到五个贴图角色,绝不要按顺序判断。请求的roughness贴图返回时标记为smoothness,编写本文时其数值实际是roughness(比如拉丝黄铜的贴图比哑光灰色的贴图更暗),所以标签是容易踩的坑,数据本身没问题:在修改清单中的
roughness_is_smoothness
(设为true时会反转数值)之前,先用
asset_display
查看你已知材质效果的族的对应贴图,确认极性。将每张贴图(默认PNG格式)通过
asset_download
保存到
textures/<family>/<role>.png
,并在清单的
provenance
字段下记录提示词、seed、job ID、资产ID、项目范围对,以及扣除的
cuCost
。

Applying in Blender

在Blender中应用

blender --background --factory-startup --python scripts/inventory.py -- model.glb work/
imports the mesh (GLB, glTF, OBJ, or FBX) or opens a
.blend
, saves a packed
work/Before.blend
, and writes
work/inventory.json
. Write
work/materials.json
mapping every material name to a family and every family to its five maps (the manifest reference has every key and default), then run
blender --background --factory-startup work/Before.blend --python scripts/apply_materials.py -- work/materials.json
. It validates the manifest, projects a dedicated
PatinaUV
layer along each face's dominant axis at object scale so
tile_span
means meters per repeat (a mesh shared by linked duplicates is made single-user first), builds one Principled BSDF per original material and family, packs the images, and asserts the geometry hash is unchanged. The
.blend
is the deliverable: a glTF export flattens the calibrated shader graph (the exporter carries only direct texture links), so bake before exporting to an engine. Open the result or render one still before spending render time on a film.
执行
blender --background --factory-startup --python scripts/inventory.py -- model.glb work/
命令会导入网格(支持GLB、glTF、OBJ或FBX格式)或打开
.blend
文件,保存打包后的
work/Before.blend
,并生成
work/inventory.json
。编写
work/materials.json
文件,将每个材质名称映射到一个材质族,并将每个材质族映射到对应的五张贴图(清单参考文档包含所有键和默认值),然后运行
blender --background --factory-startup work/Before.blend --python scripts/apply_materials.py -- work/materials.json
。该脚本会校验清单,为每个面沿其主导轴在对象尺度上投影一个专用的
PatinaUV
层,这样
tile_span
就表示每重复一次对应的米数(由链接副本共享的网格会先转为单用户),为每个原始材质和材质族构建一个Principled BSDF着色器,打包图像,并校验几何哈希值未发生变化。
.blend
文件就是交付物:glTF导出会扁平化校准后的着色器图(导出器仅保留直接的纹理链接),因此导出到引擎之前需要进行烘焙。在花时间渲染影片之前,先打开结果文件或渲染一张静帧确认效果。

Comparison film

对比影片

python3 scripts/film.py config.json pilot
renders both endpoints of every shot at half resolution for both passes and writes
Pilot Contact.jpg
with a rough time estimate. Fix framing and material defects from that sheet, then
run
renders at native resolution, resumes valid frames, saves both camera scenes as editable
.blend
files, and assembles and verifies the films;
status
prints progress. The run folder is fingerprinted from the inputs, the scripts, and the config, so a change to any of them starts a new folder. The entry points share common.py and scene.py, and
film.py
launches worker.py inside Blender; none of the three is run directly.
Design shots from
inventory.json
bounds, not from the example plan, whose coordinates fit one asset. The fast preset (EEVEE, 24 samples, half-resolution ray-traced reflections with denoising, 12 fps sources interpolated to 24 fps for slow moves) ran at about a second per 2368x1332 frame on a laptop, so the example plan's 792 source frames per pass take roughly a quarter hour each; refine from
pilot_estimate.json
, and keep
source_fps
24 for fast motion. Verify with
review/Sweep Contact.jpg
, sampled at 2 fps across the whole master: one still per shot passes a defect that fades in mid-shot. A clean encoder log is not visual approval.
执行
python3 scripts/film.py config.json pilot
会以半分辨率渲染每个镜头的两个端点(原始和重贴图后),生成
Pilot Contact.jpg
并给出大致的时间估算。根据这张图调整构图和材质缺陷,然后使用
run
命令以原生分辨率渲染,支持续传有效帧,将两个相机场景保存为可编辑的
.blend
文件,并组装和验证影片;
status
命令会打印进度。运行文件夹的名称由输入、脚本和配置的指纹生成,因此任何一项改动都会启动一个新的文件夹。入口点共享common.py和scene.py,
film.py
会在Blender内部启动worker.py;这三个脚本都不要直接运行。
请根据
inventory.json
中的边界框设计镜头,不要照搬示例方案的坐标,因为示例坐标只适配特定资产。快速预设(EEVEE、24采样、半分辨率光线追踪反射加降噪、12fps源帧插值到24fps以实现慢动作)在笔记本电脑上渲染2368x1332分辨率的帧大约每帧1秒,因此示例方案的每遍792个源帧大约需要15分钟;请根据
pilot_estimate.json
调整参数,快速运动场景请保持
source_fps
为24。使用
review/Sweep Contact.jpg
进行验证,它会在整个主影片中以2fps采样:每个镜头一张静帧可能会漏掉在镜头中间逐渐出现的缺陷。干净的编码器日志不等于视觉效果合格。

Worked example: retexture a street diorama and film the comparison

实操示例:重贴图街道微缩场景并生成对比影片

  1. Use the team/project pair already authorized by the user, or enumerate with
    teams_list
    and
    projects_list
    and ask them to choose. Unattended without an authorized pair, stop before scoped calls and report the missing scope.
    asset_get
    on the diorama (an image-to-3D result: 41 materials, no image textures, 78K faces),
    asset_download
    , then
    curl -fL -o work/street.glb "<url>"
    .
  2. Inventory with
    inventory.py
    ; group the 41 materials into families such as
    plaster
    ,
    cedar
    ,
    terracotta
    ,
    ceramic
    ,
    brass
    ,
    steel
    ,
    glass
    ,
    canvas
    ,
    asphalt
    , and
    leaf
    , with an override sending the awning objects to
    canvas
    .
  3. search
    for PATINA, then
    model_schema_get
    on the returned PATINA Material id; re-discover each session.
  4. model_run
    with top-level
    dry_run=true
    on the exact family payloads. At authoring time, 17 CU per family made 238 CU for fourteen; use the current estimates. Proceed within an already authorized budget or ask the user to approve the total. Unattended without enough authorized budget, return the estimates and stop before generation.
  5. Fourteen
    model_run
    calls with top-level
    wait=false
    , prompts such as "aged lime plaster wall, fine mineral grain, flat, evenly lit, seamless",
    seed
    fixed per family; one
    jobs_wait
    with all fourteen ids until every row is complete.
  6. asset_get
    on each output to read
    metadata.type
    ;
    asset_display
    the smoothness-labeled plaster map to settle polarity;
    asset_download
    and
    curl -fL
    every map into
    textures/<family>/
    .
  7. Write
    materials.json
    (roughness ranges per family,
    roughness_is_smoothness
    as settled,
    provenance
    with job ids and cost) and run
    apply_materials.py
    ; open
    PATINA.blend
    once.
  8. Copy example-config.json, replace the shots with ones framed from the inventory bounds, run
    film.py
    in
    pilot
    mode, inspect, then
    run
    ; hand over the master, the sharing copy, both passes, and the two editable scenes, and name the interpolation used.
  9. Optional: follow the
    scenario
    skill's multipart upload flow:
    upload_asset
    with
    kind: "video"
    ,
    file_name
    ,
    content_type: "video/mp4"
    , and
    file_size
    in bytes (omit
    data
    ), PUT every part to its returned URL, then
    upload_asset_complete
    with the returned
    upload_id
    and the same scope. Only after completion returns the video asset id, file it with the source and the maps in a collection (
    collection_create
    , then
    collection_add_assets
    : catalog tools, run through
    scenario_tool_execute_write
    with their arguments under
    parameters
    ).
  1. 使用用户已授权的团队/项目对,或通过
    teams_list
    和
    projects_list
    枚举并让用户选择。无人值守模式下如果没有授权的项目对,在进行范围相关调用前停止,并报告缺失的范围。对微缩场景(图生3D结果:41种材质、无图像纹理、78K个面)调用
    asset_get
    ,然后调用
    asset_download
    ,再执行
    curl -fL -o work/street.glb "<url>"
    下载文件。
  2. 使用
    inventory.py
    进行资产清点;将41种材质分组为
    plaster
    (灰泥)、
    cedar
    (雪松)、
    terracotta
    (陶土)、
    ceramic
    (陶瓷)、
    brass
    (黄铜)、
    steel
    (钢)、
    glass
    (玻璃)、
    canvas
    (帆布)、
    asphalt
    (沥青)和
    leaf
    (树叶)等族,并添加覆盖规则将遮阳篷对象归为
    canvas
    族。
  3. 搜索PATINA,然后对返回的PATINA Material ID调用
    model_schema_get
    ;每个会话都要重新查找。
  4. 对精确的材质族请求体调用顶层参数为
    dry_run=true
    的
    model_run
    。编写本文时每个族17 CU,14个族共238 CU;请使用当前的估算值。在已授权的预算内继续执行,或请用户批准总预算。无人值守模式下如果授权预算不足,返回估算结果并在生成前停止。
  5. 发起14次顶层参数为
    wait=false
    的
    model_run
    调用,提示词例如"aged lime plaster wall, fine mineral grain, flat, evenly lit, seamless",每个族使用固定的
    seed
    ;对所有14个ID调用一次
    jobs_wait
    直到所有任务完成。
  6. 对每个输出调用
    asset_get
    读取
    metadata.type
    ;用
    asset_display
    查看标记为smoothness的灰泥贴图确认极性;调用
    asset_download
    和
    curl -fL
    将所有贴图保存到
    textures/<family>/
    目录。
  7. 编写
    materials.json
    (每个族的roughness范围、确认后的
    roughness_is_smoothness
    值、包含job ID和成本的
    provenance
    信息),然后运行
    apply_materials.py
    ;打开一次
    PATINA.blend
    确认效果。
  8. 复制example-config.json,将镜头替换为根据资产边界框构图的镜头,先以
    pilot
    模式运行
    film.py
    检查效果,然后再运行
    run
    ;交付主影片、分享版副本、两个通道的素材,以及两个可编辑的场景文件,并说明使用的插值方式。
  9. 可选:遵循
    scenario
    技能的分片上传流程:调用
    upload_asset
    ,参数为
    kind: "video"
    、
    file_name
    、
    content_type: "video/mp4"
    和
    file_size
    (字节数,省略
    data
    ),将每个分片PUT到返回的URL,然后调用
    upload_asset_complete
    ,传入返回的
    upload_id
    和相同的范围。等完成并返回视频资产ID后,将其与源文件和贴图一起归档到集合中(调用
    collection_create
    ,然后调用
    collection_add_assets
    :这是目录工具,通过
    scenario_tool_execute_write
    运行,参数放在
    parameters
    下)。

Common mistakes

常见错误

  • Mapping outputs by position or by the
    source
    field alone: read
    metadata.type
    , and confirm the smoothness label's polarity before inverting.
  • Prompting for bricks, tiles, or planks on a mesh that already models them: the pattern doubles.
  • Asking a PATINA prompt for signage, objects, or lighting: it produces a material, not a scene.
  • Regenerating a family because
    jobs_wait
    timed out or
    model_run
    raised a transport error: re-call with
    pending_job_ids
    , or
    jobs_list
    first.
  • Running the full film before a pilot, or approving it from one still per shot instead of the 2 fps sweep sheet.
  • Editing the config or a script mid-run and expecting the render to resume: the fingerprint changed, so it starts fresh.
  • Hardcoding the PATINA id or the 17 CU figure: re-discover with
    search
    , re-price with
    dry_run
    .
  • 按位置或仅按
    source
    字段映射输出:请读取
    metadata.type
    ,并在反转前确认smoothness标签的极性。
  • 对已经建模了砖块、瓦片或木板结构的网格,提示词还要求生成这些图案:会造成图案重复。
  • 在PATINA提示词中要求生成标识、物体或光照效果:它生成的是材质,不是场景。
  • 因为
    jobs_wait
    超时或
    model_run
    抛出传输错误就重新生成材质族:请使用
    pending_job_ids
    重新调用,或先调用
    jobs_list
    确认状态。
  • 在试点渲染之前就运行完整影片,或仅根据每个镜头的一张静帧就批准影片,而不是使用2fps的扫掠检查图。
  • 在运行过程中编辑配置或脚本,还期望渲染能续传:指纹已经改变,会重新开始渲染。
  • 硬编码PATINA ID或17 CU的数值:请用
    search
    重新查找,用
    dry_run
    重新估算成本。