Files
fn_registry/docs/capabilities/gamedev-2d.md
T
egutierrez 3980fbbffb feat(gamedev): comfyui_build_normal_map_workflow — normal/depth map de sprite para 2.5D
Builder puro (dict API format) que genera el normal map (o depth/height) de un
sprite existente para iluminacion dinamica 2.5D (Godot normal_map, Unity sprite
normal). Pipeline LoadImage -> preprocesador controlnet_aux -> SaveImage, ~0 VRAM.

method selecciona el nodo (verificados contra /object_info):
- normal (default): BAE-NormalMapPreprocessor, normal canonico azul/violeta usable
  directo en motor.
- normal_midas: MiDaS, unico con control de intensidad (strength -> a).
- normal_dsine: DSINE. depth: DepthAnythingV2 (height en gris).

Nodos de normal NATIVOS, sin necesidad de depth->Sobel post (gap innecesario).
11 tests offline verdes. Probado e2e en GPU (8GB): normal map de un icono de
pocion, prompt_id d47f9943, tono azul/violeta verificado. Report 0150.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 23:01:08 +02:00

10 KiB

Capability group: gamedev / gamedev-2d — assets 2D para Godot (generación + post-proceso + puente)

Cluster de funciones para producir y mover assets 2D de juego entre ComfyUI (generación) y Godot 4 (consumo). Tres capas:

  1. Builders de workflow 2D (gamedev-2d, GPU): construyen el dict (API format) de los workflows ComfyUI para pixel-art, tiles seamless, isométrico, sprites de personaje y VFX en bucle. Son puros (no tocan GPU al construir); el coste GPU está al enviar con comfyui_submit_workflow.
  2. Post-proceso determinista (gamedev, CPU): pixelizar, recortar a alpha.
  3. Puente de assets (gamedev, CPU): coloca el resultado en un proyecto Godot con sus import settings.

Tags: gamedev (post-proceso + puente) y gamedev-2d (builders de workflow). Filtro: mcp__registry__fn_search query="" tag="gamedev-2d".

Documento hermano del grupo comfyui (generación genérica de imágenes/video/3D). Diseño del puente: docs/comfyui-godot-integration.md. Planes origen: reports/0135 (pixelart), reports/0139 (entornos/tiles/iso), reports/0137 (personajes/sprites), reports/0140 (VFX), reports/0143 (ronda 2b: builders), reports/0147 (item icons), reports/0149 (parallax background).

Builders de workflow 2D (gamedev-2d, puros — generación)

Construyen el dict API format listo para comfyui_submit_workflow. Cada uno compone funciones existentes del registry (comfyui_build_txt2img_workflow, comfyui_inject_*, comfyui_build_ipadapter_workflow) — no reinventan el grafo. class_types verificados contra /object_info del server (8GB lowvram). Probados e2e en GPU: pixelart, seamless, VFX (ver reports/0143).

ID Firma corta Qué hace
comfyui_build_pixelart_workflow_py_ml (positive, negative=…, *, ckpt_name="juggernaut_xl_v11…", pixel_lora="pixel-art-xl…", use_lcm=True, …) -> dict Fase 1 pixel-art: SDXL + LoRA pixel-art-xl (+ LCM 8 steps). El pixel-perfect es post (comfyui_pixelize_image).
comfyui_build_seamless_tile_workflow_py_ml (positive, negative="", *, tiling="enable", copy_model="Make a copy", circular_vae=True, material_lora=None, …) -> dict Textura tileable: SeamlessTile (Conv2d circular) + CircularVAEDecode. Coste VRAM ≈0.
comfyui_build_isometric_workflow_py_ml (positive, negative=…, *, iso_lora="isometric_game_assets_sd15…", grid_image=None, …) -> dict Asset iso 2:1: LoRA iso + ControlNet grid opcional.
comfyui_build_sprite_sheet_workflow_py_ml (subject, *, ref_image=None, pose_skeleton=None, char_lora=None, transparent=True, …) -> dict UN sprite de personaje: IPAdapter-FaceID + LoRA + ControlNet OpenPose (Advanced, end<1) + Rembg. Varias poses → sheet. SD1.5.
comfyui_build_vfx_spritesheet_workflow_py_ml (prompt, *, motion_model="mm_sd_v15_v2.ckpt", num_frames=16, closed_loop=True, lora=None, …) -> dict N frames AnimateDiff loop sobre negro (insumo de luma→alpha). 8GB: 16f@512² revienta, usar ≤8f@512² o bajar resolución.
comfyui_build_item_icon_workflow_py_ml (item, *, style="game icon, clean, centered", checkpoint="dreamshaper_8…", size=512, transparent=True, lora=None, …) -> dict UN icono de item de inventario (espada/poción/anillo/libro/escudo): txt2img cuadrado + prompt scaffold de icono + LoRA estilo opcional + Rembg (alpha). Set coherente = mismo style/checkpoint/lora por item. SD1.5.
comfyui_build_portrait_avatar_workflow_py_ml (character, *, style="character portrait", ref_face=None, checkpoint="dreamshaper_8…", size=512, facedetailer=True, lora=None, …) -> dict UN retrato/avatar de personaje (busto centrado, cara al espectador, fondo simple): txt2img + prompt scaffold de retrato + FaceDetailer (cara nítida) + LoRA estilo opcional; ref_face → IPAdapter-FaceID para rostro consistente entre retratos. Diálogo/perfil/selección. SD1.5.
comfyui_build_parallax_background_workflow_py_ml (scene, *, style="game background, side-scroller…", layers=3, checkpoint="dreamshaper_8…", depth_node="DepthAnythingV2Preprocessor", width=1024, height=512, …) -> dict Fondo en capas para parallax 2.5D: genera el fondo apaisado (txt2img) + su depth map (DepthAnythingV2Preprocessor sobre el VAEDecode), dos SaveImage. El split en N bandas por profundidad es post (GAP: split_parallax_layers, aún no creada). Probado e2e en GPU (reports/0149). SD1.5.
comfyui_build_normal_map_workflow_py_ml (image, *, method="normal", strength=1.0, resolution=512, bg_threshold=0.1, filename_prefix="normal_map") -> dict Normal/depth map de un sprite existente para iluminación dinámica 2.5D (Godot CanvasItem normal_map, Unity sprite normal). LoadImage → preprocesador controlnet_aux → SaveImage. method: normal (default, BAE-NormalMapPreprocessor, normal canónico azul/violeta usable directo en motor), normal_midas (MiDaS, único con strengtha, paleta no canónica), normal_dsine (DSINE), depth (DepthAnythingV2, height en gris). image debe estar en input/ de ComfyUI. Coste VRAM ≈0. Probado e2e en GPU (reports/0150).

Funciones de post-proceso y puente (gamedev, CPU)

ID Firma corta Qué hace
comfyui_pixelize_image_py_ml (src, dst, *, downscale=8, colors=16, palette=None, dither=False, upscale_back=True) -> dict Pixel-perfect: downscale nearest + cuantización a N colores o paleta fija (game-boy/pico-8/nes). Fase 2 pixelart. Impura (I/O).
comfyui_matting_luma_to_alpha_py_ml (image_path, *, out_path=None, gamma=1.0, black_point=0.0, premultiply=False, luma_weights=(.299,.587,.114)) -> dict Frame VFX sobre negro -> RGBA usando luminancia como alpha (translúcidos con additive blend). Impura (I/O).
comfyui_export_asset_to_godot_py_pipelines (asset_path, kind, godot_project, *, name=None, reimport=True, godot_bin=None) -> dict Copia el asset a res://assets/<dir>/ por kind + escribe .import + filtro Nearest si pixelart + reimport headless. Pipeline impuro.
godot_map_asset_dir_py_core (kind) -> str Mapea kind -> subcarpeta de res://assets/. Pura.
godot_clean_asset_name_py_core (filename, *, override=None) -> str Normaliza el nombre <prefijo>_NNNNN_.<ext> a snake_case seguro para res://. Pura.

Ejemplo end-to-end con builder (Fase 1 GPU → Fase 2 CPU → Godot)

Flujo completo pixel-art: construir workflow → generar en ComfyUI → pixel-perfect → Godot.

import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_build_pixelart_workflow import comfyui_build_pixelart_workflow
from ml.comfyui_submit_workflow import comfyui_submit_workflow
from ml.comfyui_wait_result import comfyui_wait_result
from ml.comfyui_fetch_output_image import comfyui_fetch_output_image
from ml.comfyui_pixelize_image import comfyui_pixelize_image

# 1. Construir (puro) + 2. generar (GPU)
wf = comfyui_build_pixelart_workflow("isometric tiny house, pixel, 32x32 style", use_lcm=True, seed=42)
pid = comfyui_submit_workflow(wf)["prompt_id"]
outs = comfyui_wait_result(pid, timeout=300)
fn = next(img["filename"] for o in outs.values() for img in o.get("images", []))
raw = comfyui_fetch_output_image(fn, dest_dir="/tmp")["out_path"]
# 3. pixel-perfect (CPU) -> 4. export Godot (ver ejemplo de abajo)
px = comfyui_pixelize_image(raw, "/tmp/house_pixel.png", downscale=8, colors=16)

VFX: comfyui_build_vfx_spritesheet_workflow(prompt, num_frames=8) → submit → fetch N frames → comfyui_matting_luma_to_alpha por frame → montar sheet RGBA con Image.alpha_composite (NO comfyui_build_grid, que aplana el alpha).

Ejemplo canónico de post-proceso

Flujo: crudo generado en ComfyUI -> pixelizar -> exportar a Godot con Nearest.

import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_pixelize_image import comfyui_pixelize_image
from ml.comfyui_matting_luma_to_alpha import comfyui_matting_luma_to_alpha
from pipelines.comfyui_export_asset_to_godot import comfyui_export_asset_to_godot

OUT = os.path.expanduser("~/ComfyUI/output")
PROJ = os.path.expanduser("~/gamedev/projects/crossy_road")

# 1. Pixelizar un sprite crudo (SDXL+pixel-art-xl) a 16 colores
px = comfyui_pixelize_image(f"{OUT}/hero_00001_.png", "/tmp/hero_pixel.png",
                            downscale=8, colors=16)

# 2. Exportarlo a Godot como pixelart (carpeta sprites/, filtro Nearest, reimport)
exp = comfyui_export_asset_to_godot("/tmp/hero_pixel.png", "pixelart", PROJ)
print(exp["dest_res_path"], exp["pixelart_filter_set"], exp["reimported"])

# Rama VFX: frame de humo sobre negro -> RGBA -> carpeta vfx/
rgba = comfyui_matting_luma_to_alpha(f"{OUT}/vfx_loop_00007_.png", gamma=1.2, black_point=0.04)
comfyui_export_asset_to_godot(rgba["out_path"], "vfx", PROJ)

Fronteras (qué NO cubre)

  • Montaje de spritesheet dedicado (grid RGBA + JSON sidecar para Godot/Unity): no hay función propia todavía — el ejemplo VFX monta con Image.alpha_composite inline. comfyui_build_grid NO sirve (aplana el alpha sobre fondo oscuro). Pendiente de R4 (plan reports/0140 F2).
  • Pipelines one-shot (build → submit → wait → fetch → post en una call) para pixelart/sprite/VFX: pendientes. Hoy se encadena a mano (ver ejemplos). Candidatos a promoción a pipeline (issue 0087) cuando el patrón se repita.
  • Sprite turnaround multi-vista (orquestar N poses con identidad fija + juez): el builder comfyui_build_sprite_sheet_workflow produce UN frame; la orquestación multi-pose es pipeline pendiente (plan reports/0137 T2).
  • Paletas lospec por red (load_lospec_palette): no incluido. pixelize usa paletas fijas embebidas (game-boy/pico-8/nes) o lista de hex, sin HTTP.
  • TileSet / SpriteFrames .tres: Godot no los deriva solos; export_asset_to_godot copia la textura y avisa, pero no genera el recurso (paso manual o futura función).

Prerequisitos / notas

  • Godot CLI para el reimport headless: autodetectado en PATH y en ~/godot/Godot_v4.7-stable_linux.x86_64. Si falta, export_asset_to_godot deja el .import escrito y lo anota (no falla).
  • Filtro Nearest (Godot 4): se setea global en project.godot (default_texture_filter=0), no por .import. La función lo asegura para pixelart.
  • CPU-only: Pillow + numpy del venv del registry. Cero VRAM, cero red.