BabylonJS/Babylon.js · error

Texture layers are not supported in Babylon Native

Error message

Texture layers are not supported in Babylon Native

What it means

This createRawTexture-family entry point in ThinNativeEngine rejects any request with a layers count greater than 0, because Babylon Native's bgfx backend does not support texture arrays/layers here. Layered textures must be avoided in this engine.

Source

Thrown at packages/dev/core/src/Engines/thinNativeEngine.pure.ts:2387

        if (type === Constants.TEXTURETYPE_FLOAT && !this._caps.textureFloatLinearFiltering) {
            // if floating point linear (gl.FLOAT) then force to NEAREST_SAMPLINGMODE
            samplingMode = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
        } else if (type === Constants.TEXTURETYPE_HALF_FLOAT && !this._caps.textureHalfFloatLinearFiltering) {
            // if floating point linear (HALF_FLOAT) then force to NEAREST_SAMPLINGMODE
            samplingMode = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
        }
        if (type === Constants.TEXTURETYPE_FLOAT && !this._caps.textureFloat) {
            type = Constants.TEXTURETYPE_UNSIGNED_BYTE;
            Logger.Warn("Float textures are not supported. Type forced to TEXTURETYPE_UNSIGNED_BYTE");
        }

        const texture = new InternalTexture(this, source);
        const width = (<{ width: number; height: number; layers?: number }>size).width ?? <number>size;
        const height = (<{ width: number; height: number; layers?: number }>size).height ?? <number>size;

        const layers = (<{ width: number; height: number; layers?: number }>size).layers || 0;
        if (layers !== 0) {
            throw new Error("Texture layers are not supported in Babylon Native");
        }

        const nativeTexture = texture._hardwareTexture!.underlyingResource;
        const nativeTextureFormat = getNativeTextureFormat(format, type);
        // TODO(bgfx-msaa-mips): stopgap workaround for a bgfx bug -- D3D11/D3D12/Vulkan backends share one
        // texture descriptor between the MSAA render target and the non-MSAA resolve target, so requesting
        // both mips > 1 and samples > 1 makes the API (D3D11 E_INVALIDARG, Vulkan VUID-02257, ...) reject the
        // MSAA texture creation. Force hasMips = false here to keep the combo from reaching bgfx. The fix
        // belongs in bgfx (separate descs per target, like OpenGL/WebGL do with a non-mipped renderbuffer);
        // this guard should be removed once a fixed bgfx ships in a stable BabylonNative npm release. Tracked
        // in BabylonNative#1714. Cost: MSAA RTs on Native lose post-resolve auto-mipgen and diverge from
        // WebGL/WebGPU semantics -- texture.generateMipMaps stays true on the InternalTexture but the
        // underlying bgfx resource has 1 mip.
        const hasMips = samples > 1 ? false : generateMipMaps;
        // REVIEW: We are always setting the renderTarget flag as we don't know whether the texture will be used as a render target.
        this._engine.initializeTexture(nativeTexture, width, height, hasMips, nativeTextureFormat, true, useSRGBBuffer, samples);
        this._setTextureSampling(nativeTexture, getNativeSamplingMode(samplingMode));

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Flatten the texture array into an atlas and adjust UVs.
  2. Create one raw texture per layer and index them in the shader.
  3. Use a 3D texture alternative only if the engine's native path supports it; otherwise restructure the material.

Example fix

// before
engine.createRawTexture(data, { width: 256, height: 256, layers: 4 }, format, ...);

// after
for (let i = 0; i < 4; i++)
  engine.createRawTexture(layerData[i], 256, 256, format, ...);
Defensive patterns

Strategy: validation

Validate before calling

const layers = (typeof size === "object" ? size.layers : 0) ?? 0;
if (layers !== 0) throw new Error("Babylon Native: flatten or split texture arrays before createRawTexture.");

Type guard

const isNonLayeredSize = (size: number | { width: number; height: number; layers?: number }): boolean =>
  typeof size === "number" || !size.layers;

Try / catch

try {
  tex = engine.createRawTexture(data, size, format, sampling);
} catch (e) {
  if (e.message.includes("Texture layers are not supported")) {
    tex = createAtlasFromLayers(data, size); // fallback: atlas or per-layer textures
  } else throw e;
}

Prevention

When it happens

Trigger: Calling createRawTexture (or similar size-object API) with size = { width, height, layers: N } where N !== 0, or passing the layer count through a scene loader that emits array textures.

Common situations: Assets authored as 2D texture arrays (e.g. .ktx arrays) or terrain/splatting systems using layer textures being run under Babylon Native.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/f9cea9530c95d21b. Report an issue: GitHub.