gltf spec updates

This commit is contained in:
keyboardspecialist 2025-08-26 15:59:11 -05:00
parent faf0111926
commit 2448e21e98
6 changed files with 65 additions and 27 deletions

View File

@ -93,28 +93,14 @@ const Cesium3DTileContentFactory = {
const dataView = new DataView(arrayBuffer, byteOffset);
const byteLength = dataView.getUint32(8, true);
const glb = new Uint8Array(arrayBuffer, byteOffset, byteLength);
let hasGaussianSplatExtension = false;
if (tileset.isGltfExtensionRequired instanceof Function) {
hasGaussianSplatExtension = tileset.isGltfExtensionRequired(
"KHR_spz_gaussian_splats_compression",
);
}
if (hasGaussianSplatExtension) {
if (GaussianSplat3DTileContent.tilesetHasGaussianSplattingExt(tileset)) {
return GaussianSplat3DTileContent.fromGltf(tileset, tile, resource, glb);
}
return Model3DTileContent.fromGltf(tileset, tile, resource, glb);
},
gltf: function (tileset, tile, resource, json) {
const forceGaussianSplats =
tileset.debugTreatTilesetAsGaussianSplats ?? false;
let hasGaussianSplatExtension = false;
if (tileset.isGltfExtensionRequired instanceof Function) {
hasGaussianSplatExtension = tileset.isGltfExtensionRequired(
"KHR_spz_gaussian_splats_compression",
);
}
if (forceGaussianSplats || hasGaussianSplatExtension) {
if (GaussianSplat3DTileContent.tilesetHasGaussianSplattingExt(tileset)) {
return GaussianSplat3DTileContent.fromGltf(tileset, tile, resource, json);
}

View File

@ -7,6 +7,7 @@ import GaussianSplatPrimitive from "./GaussianSplatPrimitive.js";
import destroyObject from "../Core/destroyObject.js";
import ModelUtility from "./Model/ModelUtility.js";
import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
import deprecationWarning from "../Core/deprecationWarning.js";
/**
* Represents the contents of a glTF or glb using the {@link https://github.com/CesiumGS/glTF/tree/draft-spz-splat-compression/extensions/2.0/Khronos/KHR_spz_gaussian_splats_compression|KHR_spz_gaussian_splats_compression} extension.
@ -325,6 +326,34 @@ Object.defineProperties(GaussianSplat3DTileContent.prototype, {
},
});
GaussianSplat3DTileContent.tilesetHasGaussianSplattingExt = function (tileset) {
let hasGaussianSplatExtension = false;
let hasLegacyGaussianSplatExtension = false;
if (tileset.isGltfExtensionRequired instanceof Function) {
hasGaussianSplatExtension =
tileset.isGltfExtensionRequired("KHR_gaussian_splatting") &&
tileset.isGltfExtensionRequired(
"KHR_gaussian_splatting_compression_spz_2",
);
hasLegacyGaussianSplatExtension = tileset.isGltfExtensionRequired(
"KHR_spz_gaussian_splats_compression",
);
}
if (hasLegacyGaussianSplatExtension) {
deprecationWarning(
"KHR_spz_gaussian_splats_compression",
"Support for the original KHR_spz_gaussian_splats_compression extension has been deprecated in favor " +
"of the up to date KHR_gaussian_splatting and KHR_gaussian_splatting_compression_spz_2 extensions and will be " +
"removed in CesiumJS 1.134.\n\nPlease retile your tileset with the KHR_gaussian_splatting and " +
"KHR_gaussian_splatting_compression_spz_2 extensions.",
);
}
return hasGaussianSplatExtension || hasLegacyGaussianSplatExtension;
};
/**
* Determine Spherical Harmonics degree and coefficient count from attributes
* @param {Array} attributes - The list of attributes.

View File

@ -2020,8 +2020,16 @@ function loadPrimitive(loader, gltfPrimitive, hasInstances, frameState) {
);
}
const spzExtension = extensions.KHR_spz_gaussian_splats_compression;
if (defined(spzExtension)) {
//support the latest glTF spec and the legacy extension
const gsExtension = extensions.KHR_spz_gaussian_splatting;
const spzExtension =
gsExtension?.extensions.KHR_gaussian_splatting_compression_2;
const legacySpzExtension = extensions.KHR_spz_gaussian_splats_compression;
if (
defined(gsExtension) &&
(defined(spzExtension) || defined(legacySpzExtension))
) {
needsPostProcessing = true;
primitivePlan.needsGaussianSplats = true;
}
@ -2058,7 +2066,7 @@ function loadPrimitive(loader, gltfPrimitive, hasInstances, frameState) {
semanticInfo,
gltfPrimitive,
draco,
spzExtension,
spzExtension || legacySpzExtension,
hasInstances,
needsPostProcessing,
frameState,

View File

@ -306,8 +306,15 @@ async function loadFromSpz(vertexBufferLoader) {
}
}
function getShPrefix(attribute) {
const prefix = attribute.startsWith("KHR_gaussian_splatting:")
? "KHR_gaussian_splatting:"
: "_";
return `${prefix}SH_DEGREE_`;
}
function extractSHDegreeAndCoef(attribute) {
const prefix = "_SH_DEGREE_";
const prefix = getShPrefix(attribute);
const separator = "_COEF_";
const lStart = prefix.length;
@ -327,9 +334,15 @@ function processSpz(vertexBufferLoader) {
if (vertexBufferLoader._attributeSemantic === "POSITION") {
vertexBufferLoader._typedArray = gcloudData.positions;
} else if (vertexBufferLoader._attributeSemantic === "_SCALE") {
} else if (
vertexBufferLoader._attributeSemantic === "_SCALE" ||
vertexBufferLoader._attributeSemantic === "KHR_gaussian_splatting:SCALE"
) {
vertexBufferLoader._typedArray = gcloudData.scales;
} else if (vertexBufferLoader._attributeSemantic === "_ROTATION") {
} else if (
vertexBufferLoader._attributeSemantic === "_ROTATION" ||
vertexBufferLoader._attributeSemantic === "KHR_gaussian_splatting:ROTATION"
) {
vertexBufferLoader._typedArray = gcloudData.rotations;
} else if (vertexBufferLoader._attributeSemantic === "COLOR_0") {
const colors = gcloudData.colors;
@ -357,7 +370,7 @@ function processSpz(vertexBufferLoader) {
255.0,
);
}
} else if (vertexBufferLoader._attributeSemantic.startsWith("_SH_DEGREE_")) {
} else if (vertexBufferLoader._attributeSemantic.includes("SH_DEGREE_")) {
const { l, n } = extractSHDegreeAndCoef(
vertexBufferLoader._attributeSemantic,
);

View File

@ -160,7 +160,7 @@ function PrimitiveLoadPlan(primitive) {
/**
* Set this true to indicate that the primitive has the
* KHR_gaussian_splatting extension and needs to be post-processed
* KHR_gaussian_splatting and KHR_gaussian_splatting_compression_spz_2 extension and needs to be post-processed
*
* @type {boolean}
* @private

View File

@ -79,14 +79,14 @@ const VertexAttributeSemantic = {
* @type {string}
* @constant
*/
SCALE: "_SCALE",
SCALE: "KHR_gaussian_splatting:SCALE",
/**
* Gaussian Splat Rotation
*
* @type {string}
* @constant
*/
ROTATION: "_ROTATION",
ROTATION: "KHR_gaussian_splatting:ROTATION",
};
function semanticToVariableName(semantic) {
@ -193,8 +193,10 @@ VertexAttributeSemantic.fromGltfSemantic = function (gltfSemantic) {
case "_FEATURE_ID":
return VertexAttributeSemantic.FEATURE_ID;
case "_SCALE":
case "KHR_gaussian_splatting:SCALE":
return VertexAttributeSemantic.SCALE;
case "_ROTATION":
case "KHR_gaussian_splatting:ROTATION":
return VertexAttributeSemantic.ROTATION;
}
@ -284,7 +286,7 @@ VertexAttributeSemantic.getGlslType = function (semantic) {
* @param {VertexAttributeSemantic} semantic The semantic.
* @param {number} [setIndex] The set index.
*
* @returns {string} The variable name.
* @returns {string} The varia_SCALEble name.
*
* @private
*/