ComfyPilotComfyPilot
工作流 / 3D 模型 / Patina:图片生材质
Patina:图片生材质

Patina:图片生材质

Patina: Image to Material

用 Patina 把一张表面照片变成可无缝平铺的 PBR 材质。原图定下花纹,Patina 把它重绘成可平铺的材质,同时返回 basecolor、normal、roughness、metalness、height 五张图,彼此逐像素对齐。适合砖、石、木、灰泥、织物、瓷砖等表面;也可以加蒙版,只重绘图片的一部分。

3D 模型 10 个节点 1 个输入 31 次使用 ComfyUI ≥ 0.43.1 ComfyUI 16 KB

下载工作流 JSON 查看官方来源

下载后把文件拖进 ComfyUI 窗口即可打开。

节点构成

SaveImage × 6
SaveText × 1
MarkdownNote × 1
LoadImage × 1
PatinaMaterialNode × 1

官方标注的模型

Patina

工作流 JSON

和上面「下载工作流 JSON」是同一份文件。

1{
2 "id": "65921f96-39e0-48c0-90f0-48a3907755e3",
3 "revision": 0,
4 "last_node_id": 31,
5 "last_link_id": 24,
6 "nodes": [
7 {
8 "id": 21,
9 "type": "SaveImage",
10 "pos": [
11 913.024172616747,
12 8.987101490822187
13 ],
14 "size": [
15 373.6485367550731,
16 421.999244495615
17 ],
18 "flags": [],
19 "order": 4,
20 "mode": 0,
21 "inputs": [
22 {
23 "name": "images",
24 "type": "IMAGE",
25 "link": 18
26 }
27 ],
28 "outputs": [
29 {
30 "name": "images",
31 "type": "IMAGE",
32 "links": null
33 }
34 ],
35 "title": "basecolor",
36 "properties": {
37 "Node name for S&R": "SaveImage"
38 },
39 "widgets_values": [
40 "patina/%year%%month%%day%-%hour%%minute%_basecolor"
41 ],
42 "widgets_values_named": {
43 "filename_prefix": "patina/%year%%month%%day%-%hour%%minute%_basecolor"
44 }
45 },
46 {
47 "id": 22,
48 "type": "SaveImage",
49 "pos": [
50 69.7270991066008,
51 8.987101490822187
52 ],
53 "size": [
54 373.6485367550731,
55 421.999244495615
56 ],
57 "flags": [],
58 "order": 5,
59 "mode": 0,
60 "inputs": [
61 {
62 "name": "images",
63 "type": "IMAGE",
64 "link": 19
65 }
66 ],
67 "outputs": [
68 {
69 "name": "images",
70 "type": "IMAGE",
71 "links": null
72 }
73 ],
74 "title": "normal",
75 "properties": {
76 "Node name for S&R": "SaveImage"
77 },
78 "widgets_values": [
79 "patina/%year%%month%%day%-%hour%%minute%_normal"
80 ],
81 "widgets_values_named": {
82 "filename_prefix": "patina/%year%%month%%day%-%hour%%minute%_normal"
83 }
84 },
85 {
86 "id": 23,
87 "type": "SaveImage",
88 "pos": [
89 491.3756358616739,
90 8.987101490822187
91 ],
92 "size": [
93 373.6485367550731,
94 421.999244495615
95 ],
96 "flags": [],
97 "order": 3,
98 "mode": 0,
99 "inputs": [
100 {
101 "name": "images",
102 "type": "IMAGE",
103 "link": 17
104 }
105 ],
106 "outputs": [
107 {
108 "name": "images",
109 "type": "IMAGE",
110 "links": null
111 }
112 ],
113 "title": "texture",
114 "properties": {
115 "Node name for S&R": "SaveImage"
116 },
117 "widgets_values": [
118 "patina/%year%%month%%day%-%hour%%minute%_texture"
119 ],
120 "widgets_values_named": {
121 "filename_prefix": "patina/%year%%month%%day%-%hour%%minute%_texture"
122 }
123 },
124 {
125 "id": 24,
126 "type": "SaveImage",
127 "pos": [
128 913.024172616747,
129 508.9863459864372
130 ],
131 "size": [
132 373.6485367550731,
133 421.999244495615
134 ],
135 "flags": [],
136 "order": 6,
137 "mode": 0,
138 "inputs": [
139 {
140 "name": "images",
141 "type": "IMAGE",
142 "link": 20
143 }
144 ],
145 "outputs": [
146 {
147 "name": "images",
148 "type": "IMAGE",
149 "links": []
150 }
151 ],
152 "title": "roughness",
153 "properties": {
154 "Node name for S&R": "SaveImage"
155 },
156 "widgets_values": [
157 "patina/%year%%month%%day%-%hour%%minute%_roughness"
158 ],
159 "widgets_values_named": {
160 "filename_prefix": "patina/%year%%month%%day%-%hour%%minute%_roughness"
161 }
162 },
163 {
164 "id": 25,
165 "type": "SaveImage",
166 "pos": [
167 69.7270991066008,
168 508.9863459864372
169 ],
170 "size": [
171 373.6485367550731,
172 421.999244495615
173 ],
174 "flags": [],
175 "order": 7,
176 "mode": 0,
177 "inputs": [
178 {
179 "name": "images",
180 "type": "IMAGE",
181 "link": 21
182 }
183 ],
184 "outputs": [
185 {
186 "name": "images",
187 "type": "IMAGE",
188 "links": []
189 }
190 ],
191 "title": "metalness",
192 "properties": {
193 "Node name for S&R": "SaveImage"
194 },
195 "widgets_values": [
196 "patina/%year%%month%%day%-%hour%%minute%_metalness"
197 ],
198 "widgets_values_named": {
199 "filename_prefix": "patina/%year%%month%%day%-%hour%%minute%_metalness"
200 }
201 },
202 {
203 "id": 26,
204 "type": "SaveImage",
205 "pos": [
206 491.3756358616739,
207 508.9863459864372
208 ],
209 "size": [
210 373.6485367550731,
211 421.999244495615
212 ],
213 "flags": [],
214 "order": 8,
215 "mode": 0,
216 "inputs": [
217 {
218 "name": "images",
219 "type": "IMAGE",
220 "link": 22
221 }
222 ],
223 "outputs": [
224 {
225 "name": "images",
226 "type": "IMAGE",
227 "links": []
228 }
229 ],
230 "title": "height",
231 "properties": {
232 "Node name for S&R": "SaveImage"
233 },
234 "widgets_values": [
235 "patina/%year%%month%%day%-%hour%%minute%_height"
236 ],
237 "widgets_values_named": {
238 "filename_prefix": "patina/%year%%month%%day%-%hour%%minute%_height"
239 }
240 },
241 {
242 "id": 27,
243 "type": "SaveText",
244 "pos": [
245 1344.4437364341845,
246 10.211257943315161
247 ],
248 "size": [
249 402.051097237096,
250 411.75603311460543
251 ],
252 "flags": [],
253 "order": 9,
254 "mode": 0,
255 "inputs": [
256 {
257 "name": "text",
258 "type": "STRING",
259 "link": 23
260 }
261 ],
262 "outputs": [
263 {
264 "name": "text",
265 "type": "STRING",
266 "links": null
267 }
268 ],
269 "title": "expanded prompt",
270 "properties": {
271 "Node name for S&R": "SaveText"
272 },
273 "widgets_values": [
274 "patina/%year%%month%%day%-%hour%%minute%_expanded_prompt",
275 "txt"
276 ],
277 "widgets_values_named": {
278 "filename_prefix": "patina/%year%%month%%day%-%hour%%minute%_expanded_prompt",
279 "format": "txt"
280 }
281 },
282 {
283 "id": 29,
284 "type": "MarkdownNote",
285 "pos": [
286 -1679.9011953297181,
287 5.5507614931625895
288 ],
289 "size": [
290 587.2726037200163,
291 782.0166239750356
292 ],
293 "flags": [],
294 "order": 0,
295 "mode": 0,
296 "inputs": [],
297 "outputs": [],
298 "properties": [],
299 "widgets_values": [
300 "# Patina Material\n\n**Photo -> complete, seamlessly tiling PBR material.** The source image sets the pattern; Patina redraws it as a\ntiling material and returns basecolor / normal / roughness / metalness / height maps from the same latent, so the whole\nset lines up pixel for pixel. Partner (API) node: it runs on Comfy's servers, needs an account, nothing renders locally.\n\n## Input Asset\n\n- [patina_brick_wall.jpg](https://raw.githubusercontent.com/Comfy-Org/workflow_templates/refs/heads/main/input/patina_brick_wall.jpg)\n\n## How to use it\n\n- **Load Image** holds the surface photo. Anything with a regular structure works: brick, stone, wood, plaster, fabric, tile.\n- `prompt` describes the material you want back, not the scene. Name the pattern and the finish, and add\n \"flat even lighting, no perspective\" - that is what makes the result tile.\n- `strength` (advanced, 0.6 here) sets how far it moves away from the photo: low keeps the original texture, high\n rewrites more of it.\n- The optional **mask** input inpaints a region (white = regenerate, black = keep). A mask without an image raises an error.\n- Want a texture from text alone, with no source photo? Use the Patina Material text-to-material template instead.\n Want the maps of a photo without making it tile? The Patina PBR Maps node is the direct converter.\n\n## Outputs - wire in this slot order\n\n`0 texture` . `1 basecolor` . `2 normal` . `3 roughness` . `4 metalness` . `5 height` . `6 expanded_prompt`\n\nEvery map can be switched off, but at least one has to stay on. Fewer maps = a cheaper, faster run.\n\n## Tips that actually matter\n\n- `image_size`: presets 1024², 512², 4:3, 3:4, 16:9, 9:16, or `custom` (512-2048, step 16).\n- `num_inference_steps` tops out at 8 - there is nothing to gain above that.\n- `tile_size` is in latent space: 128 is about 1024 px, 64 about 512 px. `tiling_mode` = both / horizontal / vertical.\n- `prompt_expansion` is **off by default on purpose**: the LLM rewrite reframes the prompt as a photo and tends to wash\n out the metalness map.\n- `upscale_factor` 2 or 4 upscales the **maps only** (SeedVR) - the base texture is never upscaled.\n- Structured materials work best. Free-form marble, flat gradients and anything relying on readable text come back as\n plausible-looking nonsense.\n\n## This workflow\n\nBrick wall photo, basecolor and normal maps on. Every save node writes to `patina/<yyyymmdd>-<hhmm>_<map>`, so one run's\nfiles sit next to each other in the output folder and runs from different days never mix."
301 ],
302 "widgets_values_named": {
303 "text": "# Patina Material\n\n**Photo -> complete, seamlessly tiling PBR material.** The source image sets the pattern; Patina redraws it as a\ntiling material and returns basecolor / normal / roughness / metalness / height maps from the same latent, so the whole\nset lines up pixel for pixel. Partner (API) node: it runs on Comfy's servers, needs an account, nothing renders locally.\n\n## Input Asset\n\n- [patina_brick_wall.jpg](https://raw.githubusercontent.com/Comfy-Org/workflow_templates/refs/heads/main/input/patina_brick_wall.jpg)\n\n## How to use it\n\n- **Load Image** holds the surface photo. Anything with a regular structure works: brick, stone, wood, plaster, fabric, tile.\n- `prompt` describes the material you want back, not the scene. Name the pattern and the finish, and add\n \"flat even lighting, no perspective\" - that is what makes the result tile.\n- `strength` (advanced, 0.6 here) sets how far it moves away from the photo: low keeps the original texture, high\n rewrites more of it.\n- The optional **mask** input inpaints a region (white = regenerate, black = keep). A mask without an image raises an error.\n- Want a texture from text alone, with no source photo? Use the Patina Material text-to-material template instead.\n Want the maps of a photo without making it tile? The Patina PBR Maps node is the direct converter.\n\n## Outputs - wire in this slot order\n\n`0 texture` . `1 basecolor` . `2 normal` . `3 roughness` . `4 metalness` . `5 height` . `6 expanded_prompt`\n\nEvery map can be switched off, but at least one has to stay on. Fewer maps = a cheaper, faster run.\n\n## Tips that actually matter\n\n- `image_size`: presets 1024², 512², 4:3, 3:4, 16:9, 9:16, or `custom` (512-2048, step 16).\n- `num_inference_steps` tops out at 8 - there is nothing to gain above that.\n- `tile_size` is in latent space: 128 is about 1024 px, 64 about 512 px. `tiling_mode` = both / horizontal / vertical.\n- `prompt_expansion` is **off by default on purpose**: the LLM rewrite reframes the prompt as a photo and tends to wash\n out the metalness map.\n- `upscale_factor` 2 or 4 upscales the **maps only** (SeedVR) - the base texture is never upscaled.\n- Structured materials work best. Free-form marble, flat gradients and anything relying on readable text come back as\n plausible-looking nonsense.\n\n## This workflow\n\nBrick wall photo, basecolor and normal maps on. Every save node writes to `patina/<yyyymmdd>-<hhmm>_<map>`, so one run's\nfiles sit next to each other in the output folder and runs from different days never mix."
304 },
305 "color": "#222",
306 "bgcolor": "#000"
307 },
308 {
309 "id": 30,
310 "type": "LoadImage",
311 "pos": [
312 -1042.6017450647105,
313 8.91382408372887
314 ],
315 "size": [
316 510.0382546262741,
317 600.3382496768281
318 ],
319 "flags": [],
320 "order": 1,
321 "mode": 0,
322 "inputs": [],
323 "outputs": [
324 {
325 "name": "IMAGE",
326 "type": "IMAGE",
327 "links": [
328 24
329 ]
330 },
331 {
332 "name": "MASK",
333 "type": "MASK",
334 "links": null
335 }
336 ],
337 "properties": {
338 "Node name for S&R": "LoadImage"
339 },
340 "widgets_values": [
341 "patina_brick_wall.jpg",
342 "image"
343 ],
344 "widgets_values_named": {
345 "image": "patina_brick_wall.jpg",
346 "upload": "image"
347 }
348 },
349 {
350 "id": 31,
351 "type": "PatinaMaterialNode",
352 "pos": [
353 -456.5165783433979,
354 11.06321397085425
355 ],
356 "size": [
357 400,
358 592
359 ],
360 "flags": [],
361 "order": 2,
362 "mode": 0,
363 "inputs": [
364 {
365 "name": "image",
366 "shape": 7,
367 "type": "IMAGE",
368 "link": 24
369 },
370 {
371 "name": "mask",
372 "shape": 7,
373 "type": "MASK",
374 "link": null
375 }
376 ],
377 "outputs": [
378 {
379 "name": "texture",
380 "type": "IMAGE",
381 "links": [
382 17
383 ]
384 },
385 {
386 "name": "basecolor",
387 "type": "IMAGE",
388 "links": [
389 18
390 ]
391 },
392 {
393 "name": "normal",
394 "type": "IMAGE",
395 "links": [
396 19
397 ]
398 },
399 {
400 "name": "roughness",
401 "type": "IMAGE",
402 "links": [
403 20
404 ]
405 },
406 {
407 "name": "metalness",
408 "type": "IMAGE",
409 "links": [
410 21
411 ]
412 },
413 {
414 "name": "height",
415 "type": "IMAGE",
416 "links": [
417 22
418 ]
419 },
420 {
421 "name": "expanded_prompt",
422 "type": "STRING",
423 "links": [
424 23
425 ]
426 }
427 ],
428 "properties": {
429 "Node name for S&R": "PatinaMaterialNode"
430 },
431 "widgets_values": [
432 "seamless tiling grey-brown brick wall, keep the running bond and pale lime mortar joints of the source photo, weathered stone faces with fine grain, flat even lighting, no perspective",
433 "1:1 (1024x1024)",
434 true,
435 true,
436 true,
437 true,
438 true,
439 0,
440 42,
441 "randomize",
442 "both",
443 8,
444 128,
445 64,
446 0.6,
447 false,
448 false
449 ],
450 "widgets_values_named": {
451 "prompt": "seamless tiling grey-brown brick wall, keep the running bond and pale lime mortar joints of the source photo, weathered stone faces with fine grain, flat even lighting, no perspective",
452 "image_size": "1:1 (1024x1024)",
453 "basecolor": true,
454 "normal": true,
455 "roughness": true,
456 "metalness": true,
457 "height": true,
458 "upscale_factor": 0,
459 "seed": 42,
460 "control_after_generate": "randomize",
461 "tiling_mode": "both",
462 "num_inference_steps": 8,
463 "tile_size": 128,
464 "tile_stride": 64,
465 "strength": 0.6,
466 "prompt_expansion": false,
467 "safety_checker": false
468 },
469 "color": "#432",
470 "bgcolor": "#653"
471 }
472 ],
473 "links": [
474 [
475 17,
476 31,
477 0,
478 23,
479 0,
480 "IMAGE"
481 ],
482 [
483 18,
484 31,
485 1,
486 21,
487 0,
488 "IMAGE"
489 ],
490 [
491 19,
492 31,
493 2,
494 22,
495 0,
496 "IMAGE"
497 ],
498 [
499 20,
500 31,
501 3,
502 24,
503 0,
504 "IMAGE"
505 ],
506 [
507 21,
508 31,
509 4,
510 25,
511 0,
512 "IMAGE"
513 ],
514 [
515 22,
516 31,
517 5,
518 26,
519 0,
520 "IMAGE"
521 ],
522 [
523 23,
524 31,
525 6,
526 27,
527 0,
528 "STRING"
529 ],
530 [
531 24,
532 30,
533 0,
534 31,
535 0,
536 "IMAGE"
537 ]
538 ],
539 "groups": [],
540 "config": [],
541 "extra": {
542 "ds": {
543 "scale": 0.538108313002308,
544 "offset": [
545 2019.9525392174532,
546 661.0856369893509
547 ]
548 },
549 "frontendVersion": "1.57.4"
550 },
551 "version": 0.4
552}