← Back to project

Why do our generations look oily? A four-layer material audit

metallic saturation traced through data → model → decode → export · 2026-07-30
PBRmaterialdiagnosisnegative-resultdeployment

0 · TL;DR

Demo outputs looked oily / chrome-plated. A generated GLB measured metallic 0.996 across the whole surface, where clean assets should sit near 0. We audited every layer of the pipeline: training data, the tex flow, the decoder and the GLB export are all correct — in-distribution the model reproduces GT material faithfully (mean metallic 0.078 vs GT 0.016 over 8 assets). The failure is specific to real photographs: seven user uploads produced metallic 0.49–0.996, while every training-style render produced ≈0.00. We also refuted the obvious explanation — photometric perturbation (exposure, specular highlight, contrast, saturation) does not move metallic at all.

So this is not a code bug to patch; it is an out-of-distribution material-decomposition failure. The lead explanation is a domain gap we measured a month ago and never closed: every conditioning render in training is flat-lit (no specular, no environment reflection), while every real photograph is not.

1 · Symptom

The deployed demo (image → SS 64³ → shape SLAT-512 → tex SLAT-512 → GLB) produced results that read as wet plastic / polished chrome. Reading the material of one generated GLB:

channelvaluewhat it means
metallic (glTF MR texture, B)mean 0.996, p10 0.988the entire object is treated as metal
roughness (G)0.394semi-glossy
baseColor(0.43, 0.48, 0.52)grey-blue

metallic ≈ 1 with roughness ≈ 0.4 under an environment map is exactly the "oily film" look: every surface mirrors the environment.

2 · Four-layer audit — every layer is clean

Rather than guess, each stage was measured against ground truth on real assets.

#layermeasurementmetallicverdict
1Training data (GT pbr_latent_512 decoded, 6.0M voxels, 5 assets)decode GT latents through the deployed tex decoder0.016 (p50 0.000, only 1.5% of voxels > 0.5)✅ clean — GT is non-metallic, roughness 0.906
2Export path (build_mw → to_glb → glTF)feed GT latents through the exact demo export, read the GLB back0.002 (roughness 0.929)✅ correct — no channel swap, no MR mix-up
3Tex flow (s3_tex_40k/ckpt-37000, teacher-forced GT coords+shape)sample, unnormalize, decode0.000; latent stats mean +0.374 / std 2.534 vs GT +0.314 / 2.830✅ on-distribution and faithful
4Full cascade (generated occupancy + generated shape + generated tex → GLB)instrumented every stepdecode 0.000 → attrs 0.000 → GLB B 0.004✅ end-to-end correct on a render input
All four layers reproduce GT material. The 0.996 GLB was produced by the same code — so the difference must be the input, not the pipeline.

3 · In-distribution fidelity — the model is not globally biased

Eight assets, teacher-forced (GT coords + GT shape so the geometry stages cannot be blamed), predicted material vs each asset's own GT:

assetGT metallicpred metallicGT roughpred roughΔ metallic
418d858d0.0000.0000.9211.000−0.000
3f45107c0.0000.0030.9930.668+0.003
ed7510840.0000.0330.9800.752+0.033
68dd18f30.0840.0990.6830.918+0.015
38a5b1fb0.0160.4370.8660.617+0.421
b98120390.0010.0040.3600.342+0.003
511bde430.0090.0190.9430.861+0.009
03dc0b5a0.0180.0250.5910.519+0.007
mean GT 0.016 · mean pred 0.078 · bias +0.061 · only 1/8 exceeds GT+0.1

Seven of eight assets are faithful to within 0.03. One asset (38a5b1fb) flips to 0.437 — so the failure mode exists in-distribution but is rare. Note the roughness column is noisier than metallic (e.g. 0.993 → 0.668), i.e. the model is less certain about gloss than about metalness.

4 · Refuted: it is NOT exposure or specular highlights

The intuitive explanation — real photos carry baked-in lighting and specular highlights, which get misread as metal — is exactly the failure Seed3D 2.0 names ("specular highlights on non-metal surfaces misclassified as metallic responses"). We tested it directly: one training render, one property perturbed at a time, same seed, teacher-forced.

variantmetallicroughnessalbedo
0 · original render0.0001.0000.394
1 · exposure ×1.50.0001.0000.428
2 · exposure ×2.00.0001.0000.354
3 · added specular highlight0.0000.7150.565
4 · contrast ×1.60.0001.0000.413
5 · saturation ×1.80.0001.0000.374
6 · saturation ×0.30.0001.0000.405
Negative result: no photometric perturbation moves metallic — every variant stays at 0.000. The synthetic highlight is perceived (roughness drops 1.000 → 0.715, i.e. "smoother") but never as metal. Low-level pixel statistics are therefore not the trigger, and simple exposure/tone normalisation in preprocessing would not fix the oiliness.

5 · What actually separates the two regimes

Grouping every GLB the demo has produced by input type:

inputmetallic (GLB, B channel)
training-style renders (examples, 3 runs)0.288 / 0.012 / 0.004
controlled end-to-end on a render (this audit)0.004
real photographs (7 user uploads)0.514 / 0.530 / 0.623 / 0.488 / 0.687 / 0.516 / 0.996

The split is clean and it is not a code-version effect: one of the high-metallic runs predates the most recent demo rebuild, i.e. the same binary produces ≈0.00 on renders and ≈0.5–1.0 on photos.

Conclusion: an out-of-distribution material-decomposition failure on real photographs. The training renders are produced by a fixed rig where material and lighting are separated by construction; a photograph entangles them, and the entanglement is not reducible to exposure/highlight/contrast/saturation — those were tested and cleared.

6 · Where the field is, and what we propose

Reading the three current systems, material realism is a main axis of competition, and one of them states our exact failure mode and its fix.

systemrelevant technique
Seed3D 2.0 (ByteDance, 2026-04)Replaces 1.0's cascaded RGB→material with a unified PBR model emitting multi-view albedo + metallic-roughness directly (MMDiT two-stream + MoE), and adds VLM-generated descriptions of material type and surface characteristics as conditioning tokens injected into the DiT blocks, explicitly to fix "specular highlights on non-metal surfaces misclassified as metallic". Geometry stays a separate coarse-to-fine stage (VecSet latents → Dual Marching Cubes up to 1536³).
Tripo P1.0 / H3.1 (GDC 2026)"Native 3D diffusion" — resolves global structure holistically in a unified probabilistic space rather than sequential token prediction; clean topology, up to 2M polygons. PBR described only as "optimized"; no architecture disclosed.
Meshy 6 (2026-01)Multi-view conditioning (front/side/back) to stop the model hallucinating unseen angles; refined geometry, low-poly mode, multi-colour print export.

The strongest remaining hypothesis: our conditioning renders are flat-lit

Mining the project history surfaced a measurement from 2026-06-25 that reframes this whole audit. Checking renders_cond against a known-metal asset (an ABO step ladder) showed the conditioning renders carry only soft grey gradients — no sharp specular, no environment reflection. Metal is rendered as matte grey; a captioner calls it "metal" from shape and commonsense, not from material cues. The conclusion recorded at the time was that these renders are unsuitable for material work — and the rig was never changed.

Every image the tex flow has ever been conditioned on is flat-lit. A photograph is not: it carries environment reflections, coloured bounce light and real specular structure. That is a domain gap the model has literally never seen, and it is not reproducible by perturbing a flat render — which is exactly why the exposure/highlight/contrast ablation above came back flat at 0.000. A pasted white blob is a bright pixel; it is not a reflection.

This also explains the asymmetry in Seed3D 2.0's setup: they render training views under random HDRI so highlights and reflections are visible, and then add VLM material tokens to disambiguate what those highlights mean. We have neither half. Two concrete levers follow, in dependency order:

  1. HDRI-lit conditioning renders (or photo-domain augmentation) so specular and reflection appear in training at all — without this the model has no basis for separating "shiny dielectric" from "metal".
  2. Material-semantic conditioning from the VLM, to resolve the residual ambiguity that lighting alone cannot.

Proposed direction: VLM-native material semantics

Material decomposition from a single photo is ill-posed — a white highlight can be metal or a lit dielectric, and pixels alone cannot separate them. The disambiguating signal is semantic: knowing the object is a wooden chair fixes metallic ≈ 0. Seed3D 2.0 validates this route with a light touch (a few VLM description tokens). Our architecture conditions on a VLM throughout, so the same idea can go further:

Caveat kept explicit: this report establishes where the failure is (photo-domain material decomposition) and rules out the pipeline and the simple photometric explanation. It does not yet prove that material-text conditioning moves metallic on photo inputs — that is the next experiment, and it is cheap because the text→material path already exists in the T modality.
WilD3DGen · material audit · GT decode (6.0M voxels) · 8-asset fidelity · 7-variant photometric ablation · deployed ckpts s3_{ss,shape,tex}_40k/checkpoint-37000