Nodes/From 3D to Campaign/Casa · quality gate
ComfyUI Node

Casa · quality gate

The node that tells you your render invented a balcony

By meryboth·Created 25 days ago·Updated 25 days ago· 0
Casa · quality gate
  • render
  • reference
  • lines
  • mask
  • passed
  • report
  • edge_recall
  • delta_e
  • niqe
◄edge_recall_min0.70►
◄delta_e_max10.0►
◄check_colortrue►
◄check_realismtrue►
◄niqe_max5.0►
◄p_photo_min0.50►

Every archviz thread in this corner of the internet ends up at the same complaint. You render a 3D scene, you push it through depth or normals plus a realistic checkpoint, and it comes back with cabinet gaps that changed width, handles that melted, and - the one from the actual thread - "a patio door randomly turning into a giant oven." You can see it's wrong. You just can't measure it, so you keep eyeballing 30 candidates.

This node measures it. Three checks, four numbers, one pass/fail.

What it measures

Edge recall answers "is this still the same building?" It takes the 3D line map, keeps only the pixels inside your mask, extracts Sobel edges from the render (top 12% by magnitude, dilated 2px so a ±2px wobble still counts as matched), and reports the share of model lines that show up as image edges. Drift, invented openings and vanishing cornices all pull it down.

ΔE answers "is it still the brand's colour?" CIE76 Lab distance between the render and the reference beauty, per region, after a gray-world white balance - because otherwise golden-hour light reads as "wrong paint". Rule of thumb: under 10 is close, 10–25 is visibly different, over 25 is a different colour.

Realism answers "does it read as a photograph?" That's two metrics: NIQE from pyiqa (lower is more natural) and p_photo, a CLIP ViT-L/14 zero-shot probability that the image is a real photograph rather than a 3D render or game screenshot. In the pack's own benchmarks NIQE separated the cases cleanly - raw 3D beauty 9.8, local img2img 3.5–5.8, cloud edit ~2.9, straight text-to-image ~2.0 - while CLIP saturated around 0.97–0.99 and is kept only as a coarse filter.

The inputs and outputs you set

Wire render (the decoded sample), reference (the beauty pass from CasaRender3D) and lines, plus mask if you have it - and you really want the mask. Without one, m.sum() > 500 in the source means the whole frame is eligible and a busy sky can flatter your edge recall while the building drifts.

Six knobs, and the interesting thing is that four of them are thresholds you're expected to tune:

  • edge_recall_min 0.70, delta_e_max 10, niqe_max 5.0, p_photo_min 0.50.
  • check_color and check_realism toggle the last two metric families off.

On thresholds: pick up the repo's config/qa.json reasoning or you'll set 0.9 and fail everything. The beauty pass only scores 0.78 against its own line map - that's the ceiling, because the metric compares an anti-aliased render to hard 3D lines. 0.70 is where the author landed after seeing that line-only conditioning produced 0.51–0.63 on the balcony incident.

Outputs: passed (BOOLEAN), report (STRING, PASS edge 0.882 deltaE 1.5 niqe 4.37 plus a bulleted list of reasons when it fails), and edge_recall, delta_e, niqe as separate FLOATs you can log or chart. The report is the one to wire into CasaLogRun's notes - that's exactly what the master graph does, so the gate verdict rides along in the same run line as the cost.

Get the metrics installed, or don't

Out of the box the gate runs geometry and colour and writes realism skipped into the report. NIQE and CLIP need two packages, and they are deliberately not dependencies, because both pull their own torch build and would cheerfully replace the CUDA torch your ComfyUI is running on:

<ComfyUI-python> -m pip install --no-deps open_clip_torch pyiqa

That --no-deps is the whole trick. The node catches the ImportError and tells you which packages are missing, so you never get a mystery crash - you get a gate that checks two things instead of four.

Install

ComfyUI Manager → From 3D to Campaign, or clone into ComfyUI/custom_nodes. The pack needs numpy and pillow (already in ComfyUI). No models are required for the gate itself - though the threshold that makes sense for you depends on which checkpoint you're rendering with. The pack assumes RealVisXL V5, a torch-serious SDXL realism merge that wants 30+ steps at its documented settings; that's a different texture profile from a Lightning-accelerated 8-step pass, and NIQE notices.

Where it goes wrong

Fidelity and realism pull in opposite directions. The settings with the best geometry read most like CG. That's why there are two thresholds and not one score - if you tighten niqe_max without loosening the geometry check, you've built a gate that rejects everything.

Colour check skips on aerials, and that's correct. The facade is 0.37% of an aerial frame; a ΔE computed from a sliver of pixels across a huge mask is noise. The CLI version of this gate enforces a coverage floor for exactly that reason. Same logic applies to your own masks.

The thresholds are eyeballed, and the config file admits it. config/qa.json notes that v1 was calibrated on 18 street renders and v1.1 revised after reviewing a 3×3 grid's failures - then says to recalibrate with a human or VLM judge before trusting any of it at scale. So treat 0.70 and 10 as a worked example tuned for one building, not a spec.

Categoryfrom 3d to campaign

Inputs (10)

NameTypeDefaultDescription
renderIMAGE—
referenceIMAGE—
linesIMAGE—
edge_recall_minFLOAT0.700–1—
delta_e_maxFLOAT10.00–60—
check_colorBOOLEANtrue—
check_realismBOOLEANtrue—
niqe_maxFLOAT5.01–20—
p_photo_minFLOAT0.500–1—
maskoptMASK—

Outputs (5)

NameTypeDescription
passedBOOLEAN—
reportSTRING—
edge_recallFLOAT—
delta_eFLOAT—
niqeFLOAT—