CNA-GAP-032: Engine-layer PBR limits: one punctual light per PbrEffect draw, 8-bit environment cubes, no back-face normal flip for double-sided materials, no alpha-tested shadow casters
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 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
PbrEffect takes one punctual light, EnvironmentProcessor builds its cubes as SurfaceFormat::Color, no stock or engine-layer shader reads a front-facing input to flip normals, and the shadow-caster shaders write depth without an alpha test.
- Identifier
CNA-GAP-032- Category
- Functional gap
- Subsystem
- Graphics & renderers
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- PbrEffect::setPunctualLightEXT; CNA::Graphics::EnvironmentProcessor; PbrEffect::getDoubleSidedEXTProperty; the engine layer's shadow-caster passes
Expected behaviour
glTF 2.0 reverses the normal of a back face of a double-sided material before lighting and lets alpha-mask materials cut out their shadows; HDR image-based lighting keeps radiance above 1.0.
Actual behaviour at TARGET
PbrEffect.hpp holds a single PunctualLightEXT (documented as a deliberate ceiling in cnaext-engine-layer.md). EnvironmentProcessor.cpp creates every generated cube as SurfaceFormat::Color. The doubleSided mapping in gltf-limitations.md selects CullNone; no shader under modules/ used by the stock PBR or engine-layer paths reads gl_FrontFacing, SV_IsFrontFace or a WGSL/MSL front-facing builtin, so back faces are lit with the front normal. The shadow-caster shaders in modules/graphics-ext/src/shaders/shadow_caster sample no texture and never discard, so alpha-tested geometry casts solid shadows.
Source locations
modules/graphics/include/Microsoft/Xna/Framework/Graphics/PbrEffect.hpp— setPunctualLightEXT: one lightdocs/cnaext-engine-layer.md— One punctual light per draw, a deliberate ceilingmodules/graphics-ext/src/EnvironmentProcessor.cpp— TextureCube created with SurfaceFormat::Colordocs/gltf-limitations.md— doubleSided row: CullNonemodules/graphics-ext/src/shaders/shadow_caster/directional.desktop.frag.glsl— depth-only caster fragment shader (no texture, no discard)
Evidence
Checked by reading at 009d40f5 (the front-facing search was a grep of all of modules/); not executed. The four limits were reported by the living-room-simulator sample @ 2bf3f56b against an earlier CNA revision and re-established individually here.
Independent re-verification: Checked by reading at 009d40f5 (the front-facing search was a grep of all of modules/, docs and tools: front-facing inputs appear only in compiled-effect translation, the Software compiled-effect runtime and PortableGL's rasteriser, not in the stock PBR or engine-layer shaders; doubleSided never reaches GpuDrawParams); not executed. The four limits were reported by the living-room-simulator sample @ 2bf3f56b against an earlier CNA revision and re-established individually here. Tests: engine-layer shadow, IBL and PBR tests exist; the EasyGL_Gltf_AlphaBlend example draws a double-sided back face under CullNone but with ambient-only lighting and no directional light, so no test lights a back face, casts an alpha-masked shadow, or carries HDR radiance through an environment cube.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
Engine-layer shadow, IBL and PBR tests exist; none draws a double-sided back face, an alpha-masked shadow caster or HDR environment radiance.
Regression test
Per limit, once lifted: a back-face lighting pixel test, an alpha-mask shadow test, an IBL test with radiance above 1.0, and a two-punctual-light draw.
Blast radius
glTF scenes with double-sided foliage or cloth, cut-out shadow casters, bright HDR environments, or several shadowed punctual lights per object.
Workaround
Duplicate double-sided geometry with flipped normals; split draws per punctual light.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- CNAEXT engine layer: limits
- Deep dives
- glTF conformance
- Known issues
- Functional gap index