Footprint-conditioned building massing β vecset diffusion
Status: active research. Not a production model. Every number below is measured on a single 48-building held-out set with one seed. Nothing here has been reproduced independently, and the project's own hard acceptance criterion is not yet met.
This repository holds the weights, the evaluation harness results, and the reasoning trail for a 49M-parameter latent-set ("vecset") diffusion model that turns a building footprint plus a height into a solid 3D mass. It is the geometry stage of a larger hybrid town-generation pipeline.
The interesting content here is not the checkpoint. It is the chain of measurements that killed four plausible approaches, and a set of measurement traps that cost real GPU-hours to learn.
TL;DR
- A decoded-surface loss β supervising the diffusion through a frozen mesh decoder instead of on latent MSE β is the largest single lever found. It bought +0.029 3D IoU for 10 GPU-hours, where tripling training length bought +0.008 for 11.
- Correcting where in the noise schedule that loss is applied (t/T 0.40 β 0.55) produced the first selective carve any model in this project has achieved: on 29 of 48 buildings it removes surplus volume without eroding the shape.
- It is bimodal. On the other 19 buildings it produces hollow shells. This is a reliability problem, not a capability one.
- π Latent distance does not predict decoded quality. Spearman Ο = +0.12 pooled across error families β wrong-signed. A latent-MSE objective cannot rank its own candidates. This one result invalidated a large amount of earlier evidence.
Results
Harness: eval_massing_arms.py, 48 pinned held-out ids, all arms scored in one pass, sampling
strength s=0.5. Artifact: massing_arms_eval_band240000.json.
3D IoU is split into missing (shape the model failed to produce) and extra (surplus volume
it added). That split is the whole reason this project made progress β the aggregate hides which way a
model is failing.
| arm | fp-IoU | missing β | extra β | 3D IoU |
|---|---|---|---|---|
| ground truth | 1.000 | 0.000 | 0.000 | 1.000 |
| codec ceiling (encodeβdecode GT) | 0.997 | 0.000 | 0.001 | 0.999 |
| blockout (extruded footprint β the input) | 1.000 | 0.000 | 0.183 | 0.845 |
surface-loss model (v4) |
0.962 | 0.002 | 0.191 | 0.838 |
band-fix model (v5, this release) |
0.954 | 0.051 | 0.158 | 0.737 |
The band-fix row is a median over a bimodal population, which is misleading on its own. Split:
| subset | n | extra β | 3D IoU |
|---|---|---|---|
solid (missing < 0.15) |
29/48 | 0.149 | 0.833 |
| hollow | 19/48 | 0.162 | 0.353 |
The two modes, same checkpoint. This is what a median of 0.051 missing against a mean of 0.244
actually looks like.
Final checkpoint @240k. Left to right: ground truth Β· blockout input Β· surface-loss model Β· band fix. Row 2 is solid; the other two rows are hollow. Same buildings and camera throughout.
β οΈ A selection effect in the headline number
The project's internal write-up reports the solid subset as "extra 0.149 vs the blockout's 0.183 β a 19% surplus reduction." That comparison is not like-for-like. 0.183 is the blockout's median over all 48 buildings; 0.149 is the model's median over the 29 it happened to succeed on. Scoring the blockout on those same 29 ids gives 0.169.
The honest figure is 0.149 vs 0.169 β an 11.8% surplus reduction, not 19%.
The effect is real and still the first selective carve this project has produced. It is smaller than previously stated, and the subset is selected by the model's own behaviour, so it is a conditional result: "when it works, it removes ~12% of the surplus."
The training trajectory is non-monotonic β do not extrapolate it
| checkpoint | fp-IoU | missing | extra | 3D IoU |
|---|---|---|---|---|
| @190k | 0.912 | 0.777 | 0.135 | 0.195 |
| @220k | 0.903 | 0.773 | 0.145 | 0.200 β renders showed shredded cages |
| @230k | 0.934 | 0.027 | 0.189 | 0.825 β recovered |
| @240k | 0.954 | 0.051 | 0.158 | 0.737 |
A stop was recommended at 220k. The very next checkpoint recovered to 0.825. This is the second time a run in this project was nearly killed during a transient collapse β the earlier one went 0.719 β 0.657 β 0.532 β 0.840 across epochs.
π A 30,000-step window of catastrophic output is not evidence of a dead run in this model.
Method
Task. Footprint polygon (rasterised to a 64Γ64 mask) + height β solid 3D building mass. β οΈ Height is a user input, not inferred. The contribution as it stands is footprint + height β mass. "Footprint alone" is future work.
Representation. A frozen third-party Dora-VAE (CVPR 2025, arXiv 2412.17808, Apache-2.0) encodes each building surface into a latent token set, decoded by cross-attention at arbitrary query points. Dora was chosen over a dense-grid codec because its sharp-edge sampling is a direct, published fix for the exact failure mode this project was fighting β losing crisp edges at the autoencoder level.
Generator. VecsetDenoiser β a DiT-style transformer over the token set:
| parameters | 49.4 M (vs ~947 M for the superseded dense-grid model) |
| width / depth / heads | 768 / 12 / 12 |
| latent channels | 64 |
| conditioning | 64Γ64 footprint mask β 16 tokens, cross-attention; AdaLN for timestep |
| schedule | cosine αΎ± |
| training set | 34,909 LoD2 building meshes |
Generation is projection. The model does not synthesise from noise. It receives the extruded footprint ("blockout") as its starting point and learns to carve it. The blockout is therefore a stage inside the method, not a rival baseline β though it remains a valid ablation on whether the learned step earns its compute.
The decoded-surface loss (the actual contribution)
Standard latent-diffusion training regresses Ξ΅ or xβ in latent space. Measurement showed that objective cannot rank its own candidates (see below), so the loss was changed to supervise through the frozen decoder:
- Predict xΜβ from the noisy latent.
- Decode xΜβ at ~8,192 sampled query points via
DoraCodec(differentiable=True).freeze(). - Regress SDF against ground truth at those points.
Design notes, both of which were error-corrected mid-project:
- No eikonal term. StEik (NeurIPS 2023) shows the plain eikonal loss becomes an unstable PDE as representation power grows. An earlier attempt in this project confirmed it directly: a gradient-TV term at w=0.1 diverged into rubble, because Ξ΅-error is amplified by 1/βαΎ± at high t.
- π The noise band matters more than the loss weight. The first run graded at t/T β 0.40 while
inference runs at 0.5β0.6. Grading near-clean latents taught the model to copy its input β
vs inputsimilarity 0.993. Moving to--surf_t_center 0.55, changing nothing else, produced the selective carve.
Cost is dominated by decode, so it scales with query count, not batch size: 8,192 points = 0.205 s
and 5.04 GB per step, against a 305 ms denoiser step. Freezing the decoder yields 0 parameter
gradients while still passing gradient to the latent.
The decoded-surface loss, before and after. Every metric column improved β the only lever in this project that did.
Why a frozen third-party autoencoder
Reconstruction quality: the superseded ~947M dense-grid codec against frozen Dora-VAE on the same buildings. Measured 0.00328 vs 0.00552 surface roughness.
π What was ruled out, and how
This is the most transferable part of the work. Each of these closed a direction that looked reasonable.
1. Latent distance is decoupled from decoded quality β the objective cannot rank candidates. Spearman Ο of latent distance vs decoded 3D IoU, 144 candidates from two error families:
| pool | n | L2 | cosine |
|---|---|---|---|
| pooled | 144 | +0.120 | β0.113 |
| on-manifold only | 24 | +0.050 | β0.188 |
| off-manifold only | 120 | β0.503 | +0.516 |
A distance metric wants negative Ο. Within one error family it works; pooled β which is the situation any real training run is in β it is worthless and slightly wrong-signed.
The model-free version is starker: a latent at cosine 0.083 decodes to IoU 0.999, while one at cosine 0.995 decodes to IoU 0.053. The 0.083 case is the same mesh re-encoded β furthest-point sampling simply reorders the tokens.
β οΈ Consequence: any "the denoiser is working, cosine improved 0.707 β 0.935" evidence is void. This retroactively invalidated a substantial body of earlier project evidence.
2. Post-hoc correction is exhausted β in both spaces. An SDF-space refiner and a latent-space corrector (zero-init residual 3D U-Net) both plateau at ~0.0047 roughness against a GT floor of 0.0041 and a codec ceiling of 0.0044. Driving latent L1 down 4Γ barely moved decoded roughness.
3. The codec was never the bottleneck. decode(encode(GT)) scores 0.999 3D IoU. A crisp building
is fully representable. The diffusion samples latents that decode badly.
4. Data is not the constraint. All 35,623 meshes audited. β οΈ Two findings that will bite anyone
touching the data: the corpus on disk is inward-wound (35,602 of 35,623) and only comes out correct
via load_surfaces β never read the h5 directly. And the meshes are coarse, median 20 faces,
which bounds what any sharpness supervision can teach.
5. Training length is exhausted. 180k steps / 41 epochs β 3Γ the scored run β bought +0.008 IoU.
6. Building size does not explain the bimodality. (new, this pass) Testing the obvious first hypothesis for what separates the 29 solid from the 19 hollow: median GT volume 50,515 vs 43,554 voxels, Mann-Whitney p=0.246, point-biserial r=0.186 (p=0.204). Not significant at n=48. Size is ruled out; footprint complexity and source corpus remain untested.
β οΈ Measurement traps
These cost GPU-hours and near-miss false negatives. They are the highest-value content here.
| trap | what happened |
|---|---|
| Never extrapolate the training curve | 0.719 β 0.657 β 0.532 β 0.840. Three monotonic points did not predict the fourth. A stop at the dip would have recorded a false negative. |
Always report vs input |
The generator scores near the blockout by declining to act. At s=0.45 it returned its input at 99.9% and inherited its score. A model can look excellent while making no edit at all. |
| Medians lie on bimodal outcomes | Median missing 0.051, mean 0.244. As a median alone this reads clean. The harness should report a collapse rate. |
| The aggregate can be flat while geometry degrades | 190k β 220k moved IoU 0.195 β 0.200 β "better" β while a building went from a box to a shredded cage. |
| n=10 probes are not quotable | Adjacent-checkpoint swing (0.59β0.78) is as large as any apparent trend. |
| Quote the outcome, not the peak | The pre-registered bar was met transiently at 9.5k (extra 0.178) and lost by 60k (0.191). Recorded not-met. |
| Compare on the same ids | See the selection effect above β a subset median against an all-population median inflated a result by 7 points. |
The no-op. A model returning 99.9% of its input, scoring near the blockout because it inherited the blockout's score.
Further renders
| image | what it shows |
|---|---|
harness-baseline-montage.png |
the 48-id harness baseline β all arms, one pass |
convergence-run-montage.png |
the first convergence run that beat the deployed model |
final-41epoch-montage.png |
41 epochs / 180k steps β where training length was exhausted |
band-fix-230000-comparison.jpg |
@230k β the cages filling back in after the collapse |
Acceptance criteria β honest status
| criterion | weight | status |
|---|---|---|
| 1 β visual, human-judged: "would you take the model's output over the extruded footprint?" | primary | β passed (human answered yes) |
| 2 β footprint match | hard, non-negotiable | β οΈ 0.962, needs 1.000 |
| 3 β 3D IoU | diagnostic only | 0.737 median / 0.833 on the solid subset β not a gate |
β οΈ Criterion 2 is the live gap and was under-weighted for an entire work cycle in favour of criterion 3, which the project's own specification marks as diagnostic. Anyone continuing this work should weight footprint fidelity first.
Literature positioning
Family this belongs to β vecset / latent-set 3D diffusion. The dominant recipe for open 3D generative models since 2023.
| work | venue | arXiv | relevance |
|---|---|---|---|
| 3DShape2VecSet | SIGGRAPH/TOG 2023 | 2301.11445 | Introduced the representation. Base recipe for everything below. |
| Michelangelo | NeurIPS 2023 | 2306.17115 | Vecset diffusion conditions cleanly on external modalities. |
| CLAY | SIGGRAPH/TOG 2024 | 2406.13897 | Explicit 3D-aware control from primitives (voxels, boxes, point clouds). Direct precedent that footprint conditioning is a solved pattern, not a research risk. |
| Direct3D | NeurIPS 2024 | 2405.14832 | Continuous latent triplane β the taxonomy is not clean-cut. |
| TRELLIS | CVPR 2025 Spotlight | 2412.01506 | Sparse structured latents; pays for resolution only where geometry exists. |
| Hunyuan3D 2.0 | Tencent 2025 | 2501.12202 | Vecset ShapeVAE + flow DiT. Uses importance sampling on edges and corners to preserve sharp detail. |
| Dora | CVPR 2025 | 2412.17808 | The closest match to this problem. Diagnoses that uniform point sampling loses sharp geometry; fixes it with sharp-edge sampling + dual cross-attention. Matches XCube-VAE with an 8Γ smaller latent. Used frozen here. |
Sharp iso-surface extraction (orthogonal, applies at export): DMTet (NeurIPS 2021), FlexiCubes (SIGGRAPH 2023), GET3D (NeurIPS 2022, notably demonstrated on a buildings category), IGR (ICML 2020, the eikonal term), StEik (NeurIPS 2023 β the stability caution that shaped this loss design).
Where this sits. The vecset recipe, footprint conditioning, and frozen-VAE latent diffusion are all established. What is not standard practice, and is the claim worth testing, is supervising a latent diffusion through its frozen decoder at a deliberately chosen noise band, adopted here because measurement showed the conventional latent objective could not rank its candidates. The band-placement finding β that grading near-clean latents teaches input-copying β is the most transferable result.
β οΈ Scale caveat. Vecset models in the literature train on hundreds of thousands to millions of shapes. This is 34,909. The sharp-edge-sampling training signal transfers at this scale; the capacity/scale advantages CLAY and Hunyuan3D-2 report likely do not.
Files
Start here β the current line of work. These five are scored on the 48-id harness and are what every number above refers to.
| file | size | what |
|---|---|---|
massing-vecset/vecset_v5_surfband_step240000.pth |
189 MB | the band-fix model β final, scored (29/48 solid) |
massing-vecset/vecset_v5_surfband_step230000.pth |
189 MB | best 3D IoU (0.825); post-recovery |
massing-vecset/vecset_v5_surfband_step220000.pth |
189 MB | the collapse checkpoint β kept as evidence |
massing-vecset/vecset_v4_surf.pth |
189 MB | surface-loss model, pre-band-fix (+0.029 IoU) |
massing-vecset/vecset_v3_pair_long_step180000.pth |
189 MB | 41-epoch control, no surface loss |
Historical β the latest checkpoint of every earlier run. Included so no run is lost, not because each is good. None of these are recommended starting points.
| file | size | what |
|---|---|---|
massing-vecset/stage3a_lod2_deployed.pth |
7.2 GB | superseded ~947M dense-grid baseline β comparison arm |
massing-vecset/vecset_v2_pair_step60000.pth |
189 MB | β οΈ pre-frame-fix β trained on transposed latents |
massing-vecset/vecset_v2_plain.pth |
189 MB | β οΈ pre-frame-fix β same defect |
massing-vecset/vecset_v1.pth |
189 MB | first vecset run |
massing-vecset/vecset_pair_v1.pth |
189 MB | first aligned-pair run |
massing-vecset/vqvae_release_res64.pth |
101 MB | released 64Β³ VQVAE codec (dense-grid era) |
massing-vecset/vqvae_clean_ft.pth |
101 MB | cleaned VQVAE fine-tune |
massing-vecset/monolith_v1/v2/v3.pth |
47 MB ea | monolith arms from the composition thesis |
β οΈ The v1/v2 vecset runs are void, not merely weak. Their training cache had x and z
transposed, so they learned a compensating axis swap. Results from them cannot be compared to
anything after the frame fix. They are here for provenance only.
Optimizer state is stripped (checkpoints are inference/fine-tune ready, not resume-ready).
latent_mu / latent_sd are retained and load-bearing β the denoiser trains on globally
normalised latents and decodes to noise without them. Verify with cd massing-vecset && sha256sum -c SHA256SUMS.
β οΈ Keep global latent normalisation. Per-channel normalisation was measured and is harmful β the 16 low-variance channels are collapsed dimensions the decoder ignores.
Also here: the demo serving stack (demo-serving/)
Separate from the massing research above. The repo's FastAPI + three.js demo β town generation from a footprint image, SDF sculpting, texture bake β needs its own weights, which are published here so the demo actually runs from a clone.
| path | size | what |
|---|---|---|
demo-serving/outputs/recipe_param_diffusion_b6/ |
80 MB | recipe-parameter diffusion β proportions/roof/wings. recipe_inference.py:44 |
demo-serving/outputs/recipe_param_diffusion_b6_ema/ |
2.9 MB | EMA variant |
demo-serving/outputs/part_layout_planner_v2/ |
17 MB | window/door/balcony layouts |
demo-serving/outputs/part_set_refiner/ |
53 MB | integrates a sculpted mass into the part set |
demo-serving/outputs/part_composer/ |
1.3 MB | statistical facade detail |
demo-serving/outputs/refiner_v1/ |
22 MB | surface refiner |
demo-serving/logs_building/β¦-ft-final/ckpt/stage3a_steps-latest.pth |
3.6 GB | snap prior, main (refine.py:469) |
demo-serving/logs_building/β¦-ft/ckpt/stage3a_steps-1000.pth |
3.6 GB | snap prior, autoguidance guide (refine.py:471) |
Paths mirror the repo layout, so demo-serving/ unpacks straight over a clone:
hf download danvisimhadri/SDFUSION --include 'demo-serving/*' --local-dir /tmp/demo
cp -r /tmp/demo/demo-serving/* . # into the repo root
./scripts/server/run_web_demo.sh 8099
β οΈ The two snap-prior checkpoints are the same finetune run at different steps β the guide is deliberately the weaker, earlier checkpoint (autoguidance). Don't "upgrade" the guide to the latest; that defeats the mechanism. β οΈ Optimizer state is stripped from both, so they are inference-only. β οΈ SDXL / ControlNet / Depth-Anything (~46 GB) are not here β they auto-download to the HF cache on the first texture or render call.
Reproduction
Code: https://github.com/danvisai/SDFusion (branch massing-solid-gate-retrain).
REPRODUCING.md covers clone β environment β data regeneration β verification. The corpus is
regenerated from 25 MB of committed identity + mesh data rather than shipped: that 25 MB rebuilds a
35 GB SDF field and 17.4 GB of latent caches. Regeneration is equivalent, not bit-identical, and
yields 35,623 rows rather than 35,776.
Attribution
The training corpus derives from three open government datasets, each carrying its own attribution terms, which any downstream use must honour:
- 3DBAG (Netherlands) β 3D BAG, TU Delft
- NRW Open Data (Germany) β Geobasis NRW
- PLATEAU (Japan) β MLIT Japan
The frozen autoencoder is Dora-VAE (Apache-2.0). Model weights here are released Apache-2.0; the data terms above are separate and are not superseded by it.
Limitations
- Bimodal: fails on ~40% of held-out buildings, cause unknown.
- Requires height as an input; does not infer it from footprint.
- Criterion 2 (footprint fidelity 1.000) not met β measured 0.962.
- Single seed, single 48-building held-out set, no independent reproduction.
- Trained on European and Japanese LoD2 building stock; no evidence it generalises beyond that.
- Meshes are coarse (median 20 faces), bounding achievable sharpness.






