CNA-BUG-277: The glTF importer still refuses a file that requires KHR_materials_specular and warns that renderer bindings are pending, although every PBR renderer samples both specular maps
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit c1c316b9; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
GltfImportCore's registry still leaves KHR_materials_specular unclaimed with a 'renderer bindings are pending' note, so extensionsRequired refuses such a file, although since AM4-085 every PBR renderer samples both specular maps.
- Identifier
CNA-BUG-277- Category
- Bug
- Subsystem
- Models & glTF
- Status
- Open
- Verified against
- CNA
c1c316b9(c1c316b9c7a846ce8002809c151fcd1af14942c9) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- ContentManager glTF import (and the offline converters) for files that list KHR_materials_specular in extensionsRequired or extensionsUsed; the extension-support registry (FindGltfExtensionEXT, IsGltfExtensionSupportedEXT)
Expected behaviour
The importer's extension registry is the one place that states what CNA implements (GLTF-334): an extension is claimed when every renderer that draws PBR materials applies it, and only an unimplemented extension listed in extensionsRequired refuses the file. CNA's own records close the specular-texture work: plans/plan_gltf.md marks GLTF-344 closed for METAL on 2026-10-08 (AM4-085), with no PBR renderer left on that row.
Actual behaviour at TARGET
The KHR_materials_specular record in GltfImportCore.cpp is still ImplementedWithNamedLimit with claimed = false and the note ‘EasyGL, DirectX9, DirectX11, SDL GPU and Vulkan sample both maps; the remaining PBR renderer shader bindings are pending. Required use remains refused and optional use is warned by name.’ IsGltfExtensionSupportedEXT returns the record's claimed flag, so ValidateGltfEXT throws for any file that lists the extension in extensionsRequired, and a file that only uses it loads with a warning that names renderer bindings as missing. Yet GltfRendererPbrFallbackPolicyTests.cpp' SpecularTextureInventoryClassifiesEveryPbrRenderer lists all seven PBR renderers (DIRECTX9, DIRECTX11, EasyGL, SDL_GPU, VULKAN, WEBGPU and, since AM4-085, METAL) as sampling both maps, with an empty factor-only set, and both maps already survive direct import and offline .cnj. gltf-limitations.md repeats the stale classification.
Source locations
modules/content/src/GltfImport/GltfImportCore.cpp— the extension registry's KHR_materials_specular record (ImplementedWithNamedLimit, not claimed); IsGltfExtensionSupportedEXT; ValidateGltfEXT's extensionsRequired refusalmodules/content/tests/CNA/Internal/GltfImport/GltfRendererPbrFallbackPolicyTests.cpp— SpecularTextureInventoryClassifiesEveryPbrRenderer: seven sampling renderers, factorOnly emptymodules/content/tests/CNA/Internal/GltfImport/GltfExtensionRegistryTests.cpp— pins the record as ImplementedWithNamedLimit and unclaimed, 'a renderer whose binding is still pending'modules/content/tests/CNA/Internal/GltfImport/GltfContainerValidationTests.cpp— expects IsGltfExtensionSupportedEXT("KHR_materials_specular") to be falsedocs/gltf-limitations.md— KHR_materials_specular row: IMPLEMENTED_WITH_A_NAMED_LIMIT, remaining renderer bindings pendingplans/plan_gltf.md— GLTF-344 row: METAL closed by AM4-085 on 2026-10-08
Evidence
Read at c1c316b9: the registry record and the extensionsRequired gate, the two tests that pin the record, the renderer inventory test, MetalRenderer.mm's binding of both maps (AM4-085, 66db69bfb) and the GLTF-344 row of CNA's plan; not executed. The two pinning tests still give the old reasons (‘a renderer whose binding is still pending’, ‘the two optional texture inputs the importer still cannot represent’), which the inventory test and the import code contradict. Whether CNA intends to keep the extension unclaimed for another reason is not recorded anywhere.
Focused reproduction
Illustrative; not run.
// scene.gltf: "extensionsUsed": ["KHR_materials_specular"],
// "extensionsRequired": ["KHR_materials_specular"]
Model model = content.Load<Model>("scene");
// throws: 'scene.gltf' lists 'KHR_materials_specular' in extensionsRequired, which CNA does not implement
Current tests
GltfExtensionRegistryTests.cpp and GltfContainerValidationTests.cpp assert the unclaimed state, so they pin the stale classification; the renderer inventory test asserts the opposite fact.
Regression test
Claim the extension (Implemented, claimed = true, no renderer-pending warning), update the two pinning tests to expect support, and add an import test with the extension in extensionsRequired that loads; or, if a real limit remains, name it in the record and the tests.
Blast radius
glTF files that list KHR_materials_specular in extensionsRequired are refused by the runtime importer and the converters; files that only use it load correctly but print a misleading warning. Other extensions and the specular rendering itself are unaffected.
Workaround
Remove KHR_materials_specular from the file's extensionsRequired (keep it in extensionsUsed); the maps are still imported and drawn.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Deep dives
- glTF import: the extension registry
- Known issues
- Bug index