Closed bug report

Component-page 3D viewer ignores GLB materials (renders uniform charcoal)

Drew Owens · 2mo ago ·closed by Colby Knox

The component-page 3D viewer appears to discard GLB materials and render everything flat dark-gray. Repro on adom/essemtec-puma (commit 00d6f93): GLB has 5 distinct PBR materials verified in-file (white 0.90 baseColor, dark 0.16, steel metallic 0.9, black, gray) plus emissiveFactor 0.32x baseColor as a test - render is pixel-identical to the previous all-gray revision after cache:reload of /blob/component/essemtec-puma/models/essemtec-puma.glb (new bytes confirmed served, 1003592 B). adom/kiosk-workcell shows the same flat look. Data points: a materials-free GLB (glTF metallic default 1.0) renders LIGHT gray; any GLB with explicit colored dielectric materials renders DARK charcoal; baseColor and emissive both have zero effect, so it is material handling, not lighting. Draco (KHR_draco_mesh_compression) decodes fine. Ask: keep the glTF materials (Babylon handles PBR+draco natively) or map baseColorFactor onto the instantiated material. adom/essemtec-puma models/essemtec-puma.glb is a ready-made 5-material fixture.

3 Replies

Drew Owens · 2mo ago

CORRECTION after more digging - the materials diagnosis was wrong; the real bug is better. The viewer at /viewer/3d//component/ renders GLB materials perfectly (adom/essemtec-puma now shows a white machine with dark accents and steel fasteners - looks great). What actually happened: (1) GLBs compressed with KHR_draco_mesh_compression or KHR_mesh_quantization fail to load in the viewer, and (2) when the model fails, the overview panel silently falls back to the hero image with no error - which is what I mistook for material replacement. Repro: push a draco or quantized GLB as model_3d_path; the overview shows only hero.png even though has_3d_model=1; push the same GLB uncompressed and the viewer works. Asks: (a) register Babylon's draco decoder (KHR_draco_mesh_compression) - our 12 MB machine model compresses to 1 MB, an 12x page-load win for exactly the big hardware models John wants on the wiki; (b) surface a visible load-error state instead of silently swapping to the hero, this cost me five republish cycles to diagnose. Also happy to note quantize support (KHR_mesh_quantization) is a one-flag loader option in Babylon.

Drew Owens · 2mo ago

Closing the loop with the REAL root causes after full investigation (both my earlier diagnoses were wrong - apologies for the noise):

  1. Draco is FINE. The viewer self-hosts the decoder (viewer-3d.js '#18', /static/vendor/adom-3d-viewer-babylon9/draco/, deployed and returning 200). My draco GLBs never got a chance to load because of (2).

  2. The overview 3D panel disappeared because of a metadata gap, not the viewer: pages created via POST /api/v1/pages never get component_metadata part detection on subsequent pushes - lib/index.js only runs it when the REPO's page.json has a component block. has_3d_model stayed 0 in the DB, and since f0e6280 reordered the overview fallbacks (resolvable hero image now beats the repoFiles .glb scan), the viewer slot silently renders hero.png. The /api route enriches metadata dynamically so it reports has_3d_model:1 while the page route reads the raw row - that disagreement is what sent me chasing ghosts.

Fix PR: https://github.com/adom-inc/git-wiki/pull/269 (run detection always, COALESCE identity fields). Workaround until merged: declare component.parts.model_3d in the repo page.json.

Remaining real nits from this saga: (a) the silent hero fallback still deserves a visible 'model failed/missing' state; (b) the page route could share the API's enrichment so the two never disagree; (c) gltf-transform's EXT_mesh_gpu_instancing warning path in the viewer is a nice precedent for surfacing load problems.

Colby Knox · 2mo ago

Merged and shipped, with a companion fix. Excellent diagnosis work across the three passes; the final one was exactly right on both counts.

Your PR #269 is merged as-is (squashed, 224c90e): part detection now runs for every component regardless of whether the repo page.json carries a component block, and identity fields COALESCE so a blockless reindex can never wipe DB-held values (the authored_with null fix included). Verified with a live repro before merging: API-shaped page, no block, glb pushed, has_3d_model=1 with mpn/manufacturer intact.

The other half was mine and is also fixed: f0e6280's hero resolver finds heroes eagerly (conventional names, iso renders), so the overview's fallback order let a static hero silently bury a working viewer whenever metadata was stale, which is precisely the misdirection that cost you two wrong diagnoses. The headline order is now: any .glb in the repo tree wins the component headline, metadata current or not; the hero is the headline only when there is genuinely no model. A regression net covers both halves (test/pages/component-metadata-autodetect.test.mjs).

Your pages are healed now: adom/essemtec-puma and adom/kiosk-workcell were reindexed on deploy, so detection applied immediately rather than waiting for your next push.

On the remaining nits: (a) the silent hero fallback is structurally gone, when a model exists the viewer always renders, and a LOAD failure now surfaces inside the viewer frame (its own error state) instead of swapping to a hero; (b) with detection running on every push, the page route's raw row and the API's enrichment converge at index time, the disagreement window is gone for any page that has pushed since this deploy; (c) noted as the pattern to follow when we surface loader warnings, filed away for the viewer backlog round.

Closing. The five-material Puma renders the way you described it should: white machine, dark accents, steel fasteners.

Log in to reply.