BabylonJS/Babylon.js · critical · Error

Missing codebook in SOG version 2 shN data.

Error message

Missing codebook in SOG version 2 shN data.

What it means

When meta.json declares shN (higher-order spherical harmonics) and version 2, SH coefficients are palette entries: labels index centroids, and centroids are indices into data.shN.codebook. This error means version is 2 but the shN entry has no codebook, so higher-order SH values cannot be reconstructed. Only reached when data.shN exists in the metadata.

Source

Thrown at packages/dev/loaders/src/SPLAT/sog.pure.ts:320

        const shCentroids = imageDataArrays[5].bits;
        const shLabelsData = imageDataArrays[6].bits;
        const shCentroidsWidth = imageDataArrays[5].width;

        const shComponentCount = coeffs * 3;

        const textureCount = Math.ceil(shComponentCount / 16); // 4 components can be stored per texture, 4 sh per component
        //let shIndexRead = byteOffset;

        const engine = scene.getEngine();
        const width = engine.getCaps().maxTextureSize;
        const height = Math.ceil(splatCount / width);

        // sh is an array of uint8array that will be used to create sh textures
        const sh = AllocateShBuffers(textureCount, height * width * 4 * 4);

        if (data.version === 2) {
            if (!data.shN.codebook) {
                throw new Error("Missing codebook in SOG version 2 shN data.");
            }

            for (let i = 0; i < splatCount; i++) {
                const n = shLabelsData[i * 4 + 0] + (shLabelsData[i * 4 + 1] << 8);
                const u = (n % 64) * coeffs;
                const v = Math.floor(n / 64);

                for (let k = 0; k < coeffs; k++) {
                    for (let j = 0; j < 3; j++) {
                        const shIndexWrite = k * 3 + j;
                        const textureIndex = Math.floor(shIndexWrite / 16);
                        const shArray = sh[textureIndex];
                        const byteIndexInTexture = shIndexWrite % 16; // [0..15]
                        const offsetPerSplat = i * 16; // 16 sh values per texture per splat.

                        const shValue = data.shN.codebook[shCentroids[(u + k) * 4 + j + v * shCentroidsWidth * 4]] * 127.5 + 127.5;
                        shArray[byteIndexInTexture + offsetPerSplat] = Math.max(0, Math.min(255, shValue));
                    }

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Regenerate the SOG v2 asset so shN.codebook (256 entries) is written into meta.json.
  2. If shN data is v1-encoded, remove version: 2 (or set 1) so the scalar mins/maxs path is used.
  3. Drop the shN section from meta.json entirely if higher-order SH is not needed (the field is optional).
  4. Pre-validate: if (meta.shN && meta.version === 2) require Array.isArray(meta.shN.codebook).

Example fix

// before
"version": 2, "shN": { "bands": 3, "shape": [100000, 45], "dtype": "uint8", "files": ["shN_centroids.webp", "shN_labels.webp"] }
// after
"version": 2, "shN": { "bands": 3, "shape": [100000, 45], "dtype": "uint8", "files": ["shN_centroids.webp", "shN_labels.webp"], "codebook": [-0.12, -0.09, ...] }
Defensive patterns

Strategy: validation

Validate before calling

function validateV2ShN(meta) {
  if (meta.shN && meta.version === 2 && !Array.isArray(meta.shN.codebook)) {
    throw new Error('v2 SOG asset: meta.shN.codebook is required when shN is present');
  }
}

Type guard

function hasValidShN(meta) {
  return !meta.shN || meta.version !== 2 || Array.isArray(meta.shN.codebook);
}

Try / catch

try {
  return await ParseSogMeta(metaOrFiles, rootUrl, scene);
} catch (e) {
  if (e.message.includes('shN')) {
    // shN palette missing: remove shN from meta.json (optional field) or re-export as proper v2
  }
  throw e;
}

Prevention

When it happens

Trigger: ParseSogMeta with a meta.json containing an shN section and version: 2 but no shN.codebook array — e.g. v1-style shN metadata (which uses scalar mins/maxs) paired with version: 2, or a hand-edited meta.json.

Common situations: Assets converted from SOG v1 to v2 by only bumping the version field; encoders that emit shN without the v2 palette; metadata merging tools that keep shN from a different asset version.

Related errors


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