From d6e4d5d84760334555930cf6dd544e50f01b6805 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Fri, 11 Jul 2025 10:22:17 -0400 Subject: [PATCH 01/34] KHR_gaussian_splatting extension --- .../ExtensionKhrGaussianSplatting.h | 42 ++++++ .../ExtensionKhrGaussianSplattingReader.h | 77 +++++++++++ ...ExtensionKhrGaussianSplattingJsonHandler.h | 47 +++++++ .../generated/src/GeneratedJsonHandlers.cpp | 120 ++++++++++++++++++ .../src/registerReaderExtensions.cpp | 4 + .../generated/src/ModelJsonWriter.cpp | 29 +++++ .../generated/src/ModelJsonWriter.h | 14 ++ .../src/registerWriterExtensions.cpp | 4 + tools/generate-classes/glTF.json | 10 ++ tools/generate-classes/package.json | 2 +- 10 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h create mode 100644 CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingReader.h create mode 100644 CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h new file mode 100644 index 000000000..e7e089ec1 --- /dev/null +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h @@ -0,0 +1,42 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include + +namespace CesiumGltf { +/** + * @brief glTF extension for rendering Gaussian splats. + */ +struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final + : public CesiumUtility::ExtensibleObject { + /** + * @brief The original name of this type. + */ + static constexpr const char* TypeName = "ExtensionKhrGaussianSplatting"; + /** @brief The official name of the extension. This should be the same as its + * key in the `extensions` object. */ + static constexpr const char* ExtensionName = "KHR_gaussian_splatting"; + + /** + * @brief Scale used when dequantizing position attribute values + */ + double quantizedPositionScale = 1; + + /** + * @brief Calculates the size in bytes of this object, including the contents + * of all collections, pointers, and strings. This will NOT include the size + * of any extensions attached to the object. Calling this method may be slow + * as it requires traversing the object's entire structure. + */ + int64_t getSizeBytes() const { + int64_t accum = 0; + accum += int64_t(sizeof(ExtensionKhrGaussianSplatting)); + accum += CesiumUtility::ExtensibleObject::getSizeBytes() - + int64_t(sizeof(CesiumUtility::ExtensibleObject)); + + return accum; + } +}; +} // namespace CesiumGltf diff --git a/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingReader.h b/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingReader.h new file mode 100644 index 000000000..bc1b7860c --- /dev/null +++ b/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingReader.h @@ -0,0 +1,77 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include +#include +#include + +#include + +#include +#include + +namespace CesiumGltf { +struct ExtensionKhrGaussianSplatting; +} // namespace CesiumGltf + +namespace CesiumGltfReader { + +/** + * @brief Reads \ref CesiumGltf::ExtensionKhrGaussianSplatting + * "ExtensionKhrGaussianSplatting" instances from JSON. + */ +class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingReader { +public: + /** + * @brief Constructs a new instance. + */ + ExtensionKhrGaussianSplattingReader(); + + /** + * @brief Gets the options controlling how the JSON is read. + */ + CesiumJsonReader::JsonReaderOptions& getOptions(); + + /** + * @brief Gets the options controlling how the JSON is read. + */ + const CesiumJsonReader::JsonReaderOptions& getOptions() const; + + /** + * @brief Reads an instance of ExtensionKhrGaussianSplatting from a byte + * buffer. + * + * @param data The buffer from which to read the instance. + * @return The result of reading the instance. + */ + CesiumJsonReader::ReadJsonResult + readFromJson(const std::span& data) const; + + /** + * @brief Reads an instance of ExtensionKhrGaussianSplatting from a + * rapidJson::Value. + * + * @param value The value from which to read the instance. + * @return The result of reading the instance. + */ + CesiumJsonReader::ReadJsonResult + readFromJson(const rapidjson::Value& value) const; + + /** + * @brief Reads an array of instances of ExtensionKhrGaussianSplatting from a + * rapidJson::Value. + * + * @param value The value from which to read the array of instances. + * @return The result of reading the array of instances. + */ + CesiumJsonReader::ReadJsonResult< + std::vector> + readArrayFromJson(const rapidjson::Value& value) const; + +private: + CesiumJsonReader::JsonReaderOptions _options; +}; + +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h new file mode 100644 index 000000000..d93a2fd89 --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h @@ -0,0 +1,47 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include +#include + +namespace CesiumJsonReader { +class JsonReaderOptions; +} // namespace CesiumJsonReader + +namespace CesiumGltfReader { +class ExtensionKhrGaussianSplattingJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler, + public CesiumJsonReader::IExtensionJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionKhrGaussianSplatting; + + static constexpr const char* ExtensionName = "KHR_gaussian_splatting"; + + explicit ExtensionKhrGaussianSplattingJsonHandler( + const CesiumJsonReader::JsonReaderOptions& options) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrGaussianSplatting* pObject); + + IJsonHandler* readObjectKey(const std::string_view& str) override; + + void reset( + IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) override; + + IJsonHandler& getHandler() override { return *this; } + +protected: + IJsonHandler* readObjectKeyExtensionKhrGaussianSplatting( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrGaussianSplatting& o); + +private: + CesiumGltf::ExtensionKhrGaussianSplatting* _pObject = nullptr; + CesiumJsonReader::DoubleJsonHandler _quantizedPositionScale; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp index d4447faa2..9e9a52276 100644 --- a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp +++ b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp @@ -2974,6 +2974,126 @@ ExtensionExtPrimitiveVoxelsReader::readArrayFromJson( return CesiumJsonReader::JsonReader::readJson(value, handler); } +} // namespace CesiumGltfReader +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +// NOLINTBEGIN(readability-duplicate-include) +#include "ExtensionKhrGaussianSplattingJsonHandler.h" +#include "registerReaderExtensions.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +// NOLINTEND(readability-duplicate-include) + +namespace CesiumGltfReader { + +ExtensionKhrGaussianSplattingJsonHandler:: + ExtensionKhrGaussianSplattingJsonHandler( + const CesiumJsonReader::JsonReaderOptions& options) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(options), + _quantizedPositionScale() {} + +void ExtensionKhrGaussianSplattingJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrGaussianSplatting* pObject) { + CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); + this->_pObject = pObject; +} + +CesiumJsonReader::IJsonHandler* +ExtensionKhrGaussianSplattingJsonHandler::readObjectKey( + const std::string_view& str) { + CESIUM_ASSERT(this->_pObject); + return this->readObjectKeyExtensionKhrGaussianSplatting( + CesiumGltf::ExtensionKhrGaussianSplatting::TypeName, + str, + *this->_pObject); +} + +void ExtensionKhrGaussianSplattingJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { + std::any& value = + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionKhrGaussianSplatting()) + .first->second; + this->reset( + pParentHandler, + &std::any_cast(value)); +} + +CesiumJsonReader::IJsonHandler* ExtensionKhrGaussianSplattingJsonHandler:: + readObjectKeyExtensionKhrGaussianSplatting( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrGaussianSplatting& o) { + using namespace std::string_literals; + + if ("quantizedPositionScale"s == str) { + return property( + "quantizedPositionScale", + this->_quantizedPositionScale, + o.quantizedPositionScale); + } + + return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); +} + +ExtensionKhrGaussianSplattingReader::ExtensionKhrGaussianSplattingReader() { + registerReaderExtensions(this->_options); +} + +CesiumJsonReader::JsonReaderOptions& +ExtensionKhrGaussianSplattingReader::getOptions() { + return this->_options; +} + +const CesiumJsonReader::JsonReaderOptions& +ExtensionKhrGaussianSplattingReader::getOptions() const { + return this->_options; +} + +CesiumJsonReader::ReadJsonResult +ExtensionKhrGaussianSplattingReader::readFromJson( + const std::span& data) const { + ExtensionKhrGaussianSplattingJsonHandler handler(this->_options); + return CesiumJsonReader::JsonReader::readJson(data, handler); +} + +CesiumJsonReader::ReadJsonResult +ExtensionKhrGaussianSplattingReader::readFromJson( + const rapidjson::Value& value) const { + ExtensionKhrGaussianSplattingJsonHandler handler(this->_options); + return CesiumJsonReader::JsonReader::readJson(value, handler); +} + +CesiumJsonReader::ReadJsonResult< + std::vector> +ExtensionKhrGaussianSplattingReader::readArrayFromJson( + const rapidjson::Value& value) const { + CesiumJsonReader::ArrayJsonHandler< + CesiumGltf::ExtensionKhrGaussianSplatting, + ExtensionKhrGaussianSplattingJsonHandler> + handler(this->_options); + return CesiumJsonReader::JsonReader::readJson(value, handler); +} + } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! diff --git a/CesiumGltfReader/generated/src/registerReaderExtensions.cpp b/CesiumGltfReader/generated/src/registerReaderExtensions.cpp index d275caa9e..835175724 100644 --- a/CesiumGltfReader/generated/src/registerReaderExtensions.cpp +++ b/CesiumGltfReader/generated/src/registerReaderExtensions.cpp @@ -16,6 +16,7 @@ #include "ExtensionExtPrimitiveVoxelsJsonHandler.h" #include "ExtensionExtStructuralMetadataJsonHandler.h" #include "ExtensionKhrDracoMeshCompressionJsonHandler.h" +#include "ExtensionKhrGaussianSplattingJsonHandler.h" #include "ExtensionKhrImplicitShapesJsonHandler.h" #include "ExtensionKhrMaterialsUnlitJsonHandler.h" #include "ExtensionKhrTextureBasisuJsonHandler.h" @@ -81,6 +82,9 @@ void registerReaderExtensions(CesiumJsonReader::JsonReaderOptions& options) { options.registerExtension< CesiumGltf::MeshPrimitive, ExtensionExtPrimitiveVoxelsJsonHandler>(); + options.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionKhrGaussianSplattingJsonHandler>(); options.registerExtension< CesiumGltf::Node, ExtensionExtInstanceFeaturesJsonHandler>(); diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp index c0a0a8357..807308517 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -218,6 +219,11 @@ void writeJson( CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); +void writeJson( + const CesiumGltf::ExtensionKhrGaussianSplatting& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context); + void writeJson( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, @@ -1174,6 +1180,22 @@ void writeJson( jsonWriter.EndObject(); } +void writeJson( + const CesiumGltf::ExtensionKhrGaussianSplatting& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context) { + jsonWriter.StartObject(); + + if (obj.quantizedPositionScale != 1) { + jsonWriter.Key("quantizedPositionScale"); + writeJson(obj.quantizedPositionScale, jsonWriter, context); + } + + writeExtensibleObject(obj, jsonWriter, context); + + jsonWriter.EndObject(); +} + void writeJson( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, @@ -2892,6 +2914,13 @@ void ExtensionExtPrimitiveVoxelsJsonWriter::write( writeJson(obj, jsonWriter, context); } +void ExtensionKhrGaussianSplattingJsonWriter::write( + const CesiumGltf::ExtensionKhrGaussianSplatting& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context) { + writeJson(obj, jsonWriter, context); +} + void PaddingJsonWriter::write( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.h b/CesiumGltfWriter/generated/src/ModelJsonWriter.h index 5ab09a241..6df277b5d 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.h +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.h @@ -34,6 +34,7 @@ struct ExtensionKhrImplicitShapes; struct ExtensionExtImplicitEllipsoidRegion; struct ExtensionExtImplicitCylinderRegion; struct ExtensionExtPrimitiveVoxels; +struct ExtensionKhrGaussianSplatting; struct Padding; struct Shape; struct Cylinder; @@ -402,6 +403,19 @@ struct ExtensionExtPrimitiveVoxelsJsonWriter { const CesiumJsonWriter::ExtensionWriterContext& context); }; +struct ExtensionKhrGaussianSplattingJsonWriter { + using ValueType = CesiumGltf::ExtensionKhrGaussianSplatting; + + /** @brief The official name of the extension. This should be the same as its + * key in the `extensions` object. */ + static constexpr const char* ExtensionName = "KHR_gaussian_splatting"; + + static void write( + const CesiumGltf::ExtensionKhrGaussianSplatting& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context); +}; + struct PaddingJsonWriter { using ValueType = CesiumGltf::Padding; diff --git a/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp b/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp index 4ae227e1e..6f76bbaa3 100644 --- a/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp +++ b/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,9 @@ void registerWriterExtensions( context.registerExtension< CesiumGltf::MeshPrimitive, ExtensionExtPrimitiveVoxelsJsonWriter>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionKhrGaussianSplattingJsonWriter>(); context.registerExtension< CesiumGltf::Node, ExtensionExtInstanceFeaturesJsonWriter>(); diff --git a/tools/generate-classes/glTF.json b/tools/generate-classes/glTF.json index fc9e99980..2e59ac897 100644 --- a/tools/generate-classes/glTF.json +++ b/tools/generate-classes/glTF.json @@ -163,6 +163,9 @@ }, "EXT_primitive_voxels glTF Mesh Primitive extension": { "overrideName": "ExtensionExtPrimitiveVoxels" + }, + "KHR_gaussian_splatting glTF primitive extension": { + "overrideName": "ExtensionKhrGaussianSplatting" } }, "extensions": [ @@ -287,6 +290,13 @@ { "extensionName": "EXT_primitive_voxels", "schema": "Vendor/EXT_primitive_voxels/schema/mesh.primitive.EXT_primitive_voxels.schema.json" + }, + { + "extensionName": "KHR_gaussian_splatting", + "schema": "Khronos/KHR_gaussian_splatting/schema/primitive.KHR_gaussian_splatting.schema.json", + "attachTo": [ + "mesh.primitive" + ] } ] } diff --git a/tools/generate-classes/package.json b/tools/generate-classes/package.json index 8bbe67b24..dca58df64 100644 --- a/tools/generate-classes/package.json +++ b/tools/generate-classes/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "generate-3d-tiles": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/tileset.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/common/rootProperty.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/PropertyTable/propertyTable.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Subtree/subtree.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Schema/schema.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Statistics/statistics.schema.json --output ../../Cesium3DTiles --readerOutput ../../Cesium3DTilesReader --writerOutput ../../Cesium3DTilesWriter --extensions https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/extensions/ --namespace Cesium3DTiles --readerNamespace Cesium3DTilesReader --writerNamespace Cesium3DTilesWriter --config 3dTiles.json", - "generate-gltf": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/specification/2.0/schema/glTF.schema.json --output ../../CesiumGltf --readerOutput ../../CesiumGltfReader --writerOutput ../../CesiumGltfWriter --extensions https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/extensions/2.0/ --namespace CesiumGltf --readerNamespace CesiumGltfReader --writerNamespace CesiumGltfWriter --config glTF.json", + "generate-gltf": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/specification/2.0/schema/glTF.schema.json --output ../../CesiumGltf --readerOutput ../../CesiumGltfReader --writerOutput ../../CesiumGltfWriter --extensions https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/extensions/2.0/ https://raw.githubusercontent.com/CesiumGS/glTF/spz-extension/extensions/2.0/ --namespace CesiumGltf --readerNamespace CesiumGltfReader --writerNamespace CesiumGltfWriter --config glTF.json", "generate-quantized-mesh-terrain": "node index.js --schemas ../../CesiumQuantizedMeshTerrain/schema/layer.schema.json --output ../../CesiumQuantizedMeshTerrain --readerOutput ../../CesiumQuantizedMeshTerrain --writerOutput ../../CesiumQuantizedMeshTerrain --extensions ../../CesiumQuantizedMeshTerrain/schema/extensions --namespace CesiumQuantizedMeshTerrain --readerNamespace CesiumQuantizedMeshTerrain --writerNamespace CesiumQuantizedMeshTerrain --config QuantizedMeshTerrain.json" }, "author": "CesiumGS, Inc. and Contributors", From cf5cfe000af60ae262488006a8fb7c4f52a4c3d4 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Fri, 15 Aug 2025 14:11:42 -0400 Subject: [PATCH 02/34] Add SPZ extension, library --- .gitmodules | 3 + .../ExtensionKhrGaussianSplatting.h | 7 +- ...ensionKhrGaussianSplattingCompressionSpz.h | 46 ++++++ .../include/CesiumGltf/ExtensionTextureWebp.h | 2 +- ...KhrGaussianSplattingCompressionSpzReader.h | 79 ++++++++++ ...ussianSplattingCompressionSpzJsonHandler.h | 48 +++++++ ...ExtensionKhrGaussianSplattingJsonHandler.h | 2 - .../generated/src/GeneratedJsonHandlers.cpp | 135 ++++++++++++++++-- .../src/registerReaderExtensions.cpp | 4 + .../generated/src/ModelJsonWriter.cpp | 30 +++- .../generated/src/ModelJsonWriter.h | 15 ++ .../src/registerWriterExtensions.cpp | 4 + extern/CMakeLists.txt | 2 + extern/spz | 1 + tools/generate-classes/glTF.json | 14 +- tools/generate-classes/package.json | 2 +- 16 files changed, 371 insertions(+), 23 deletions(-) create mode 100644 CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz.h create mode 100644 CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpzReader.h create mode 100644 CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h create mode 160000 extern/spz diff --git a/.gitmodules b/.gitmodules index d64ba06db..8cc769630 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "extern/cmake-modules"] path = extern/cmake-modules url = https://github.com/bilke/cmake-modules.git +[submodule "extern/spz"] + path = extern/spz + url = https://github.com/nianticlabs/spz.git diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h index e7e089ec1..a69191399 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h @@ -7,7 +7,7 @@ namespace CesiumGltf { /** - * @brief glTF extension for rendering Gaussian splats. + * @brief Data for a 3D Gaussian Splat primitive. */ struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final : public CesiumUtility::ExtensibleObject { @@ -19,11 +19,6 @@ struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final * key in the `extensions` object. */ static constexpr const char* ExtensionName = "KHR_gaussian_splatting"; - /** - * @brief Scale used when dequantizing position attribute values - */ - double quantizedPositionScale = 1; - /** * @brief Calculates the size in bytes of this object, including the contents * of all collections, pointers, and strings. This will NOT include the size diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz.h new file mode 100644 index 000000000..dc573a0b2 --- /dev/null +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz.h @@ -0,0 +1,46 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include + +#include + +namespace CesiumGltf { +/** + * @brief Compressed data for SPZ primitive. + */ +struct CESIUMGLTF_API ExtensionKhrGaussianSplattingCompressionSpz final + : public CesiumUtility::ExtensibleObject { + /** + * @brief The original name of this type. + */ + static constexpr const char* TypeName = + "ExtensionKhrGaussianSplattingCompressionSpz"; + /** @brief The official name of the extension. This should be the same as its + * key in the `extensions` object. */ + static constexpr const char* ExtensionName = + "KHR_gaussian_splatting_compression_spz"; + + /** + * @brief The index of the bufferView. + */ + int32_t bufferView = -1; + + /** + * @brief Calculates the size in bytes of this object, including the contents + * of all collections, pointers, and strings. This will NOT include the size + * of any extensions attached to the object. Calling this method may be slow + * as it requires traversing the object's entire structure. + */ + int64_t getSizeBytes() const { + int64_t accum = 0; + accum += int64_t(sizeof(ExtensionKhrGaussianSplattingCompressionSpz)); + accum += CesiumUtility::ExtensibleObject::getSizeBytes() - + int64_t(sizeof(CesiumUtility::ExtensibleObject)); + + return accum; + } +}; +} // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionTextureWebp.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionTextureWebp.h index 16fe5b7ac..1f38b77ad 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionTextureWebp.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionTextureWebp.h @@ -22,7 +22,7 @@ struct CESIUMGLTF_API ExtensionTextureWebp final static constexpr const char* ExtensionName = "EXT_texture_webp"; /** - * @brief The index of the images node which points to a WebP image. + * @brief The index of the WebP image. */ int32_t source = -1; diff --git a/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpzReader.h b/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpzReader.h new file mode 100644 index 000000000..c2d8fd1c0 --- /dev/null +++ b/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpzReader.h @@ -0,0 +1,79 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include +#include +#include + +#include + +#include +#include + +namespace CesiumGltf { +struct ExtensionKhrGaussianSplattingCompressionSpz; +} // namespace CesiumGltf + +namespace CesiumGltfReader { + +/** + * @brief Reads \ref CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz + * "ExtensionKhrGaussianSplattingCompressionSpz" instances from JSON. + */ +class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingCompressionSpzReader { +public: + /** + * @brief Constructs a new instance. + */ + ExtensionKhrGaussianSplattingCompressionSpzReader(); + + /** + * @brief Gets the options controlling how the JSON is read. + */ + CesiumJsonReader::JsonReaderOptions& getOptions(); + + /** + * @brief Gets the options controlling how the JSON is read. + */ + const CesiumJsonReader::JsonReaderOptions& getOptions() const; + + /** + * @brief Reads an instance of ExtensionKhrGaussianSplattingCompressionSpz + * from a byte buffer. + * + * @param data The buffer from which to read the instance. + * @return The result of reading the instance. + */ + CesiumJsonReader::ReadJsonResult< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz> + readFromJson(const std::span& data) const; + + /** + * @brief Reads an instance of ExtensionKhrGaussianSplattingCompressionSpz + * from a rapidJson::Value. + * + * @param value The value from which to read the instance. + * @return The result of reading the instance. + */ + CesiumJsonReader::ReadJsonResult< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz> + readFromJson(const rapidjson::Value& value) const; + + /** + * @brief Reads an array of instances of + * ExtensionKhrGaussianSplattingCompressionSpz from a rapidJson::Value. + * + * @param value The value from which to read the array of instances. + * @return The result of reading the array of instances. + */ + CesiumJsonReader::ReadJsonResult< + std::vector> + readArrayFromJson(const rapidjson::Value& value) const; + +private: + CesiumJsonReader::JsonReaderOptions _options; +}; + +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h new file mode 100644 index 000000000..dde1a8c5e --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h @@ -0,0 +1,48 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include +#include + +namespace CesiumJsonReader { +class JsonReaderOptions; +} // namespace CesiumJsonReader + +namespace CesiumGltfReader { +class ExtensionKhrGaussianSplattingCompressionSpzJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler, + public CesiumJsonReader::IExtensionJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz; + + static constexpr const char* ExtensionName = + "KHR_gaussian_splatting_compression_spz"; + + explicit ExtensionKhrGaussianSplattingCompressionSpzJsonHandler( + const CesiumJsonReader::JsonReaderOptions& options) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz* pObject); + + IJsonHandler* readObjectKey(const std::string_view& str) override; + + void reset( + IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) override; + + IJsonHandler& getHandler() override { return *this; } + +protected: + IJsonHandler* readObjectKeyExtensionKhrGaussianSplattingCompressionSpz( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& o); + +private: + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz* _pObject = nullptr; + CesiumJsonReader::IntegerJsonHandler _bufferView; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h index d93a2fd89..cdd22579e 100644 --- a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h @@ -3,7 +3,6 @@ #pragma once #include -#include #include namespace CesiumJsonReader { @@ -42,6 +41,5 @@ class ExtensionKhrGaussianSplattingJsonHandler private: CesiumGltf::ExtensionKhrGaussianSplatting* _pObject = nullptr; - CesiumJsonReader::DoubleJsonHandler _quantizedPositionScale; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp index 9e9a52276..ac5ee04e5 100644 --- a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp +++ b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp @@ -3005,8 +3005,7 @@ namespace CesiumGltfReader { ExtensionKhrGaussianSplattingJsonHandler:: ExtensionKhrGaussianSplattingJsonHandler( const CesiumJsonReader::JsonReaderOptions& options) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(options), - _quantizedPositionScale() {} + : CesiumJsonReader::ExtensibleObjectJsonHandler(options) {} void ExtensionKhrGaussianSplattingJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, @@ -3045,12 +3044,7 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrGaussianSplattingJsonHandler:: CesiumGltf::ExtensionKhrGaussianSplatting& o) { using namespace std::string_literals; - if ("quantizedPositionScale"s == str) { - return property( - "quantizedPositionScale", - this->_quantizedPositionScale, - o.quantizedPositionScale); - } + (void)o; return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3094,6 +3088,131 @@ ExtensionKhrGaussianSplattingReader::readArrayFromJson( return CesiumJsonReader::JsonReader::readJson(value, handler); } +} // namespace CesiumGltfReader +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +// NOLINTBEGIN(readability-duplicate-include) +#include "ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h" +#include "registerReaderExtensions.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +// NOLINTEND(readability-duplicate-include) + +namespace CesiumGltfReader { + +ExtensionKhrGaussianSplattingCompressionSpzJsonHandler:: + ExtensionKhrGaussianSplattingCompressionSpzJsonHandler( + const CesiumJsonReader::JsonReaderOptions& options) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(options), _bufferView() {} + +void ExtensionKhrGaussianSplattingCompressionSpzJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz* pObject) { + CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); + this->_pObject = pObject; +} + +CesiumJsonReader::IJsonHandler* +ExtensionKhrGaussianSplattingCompressionSpzJsonHandler::readObjectKey( + const std::string_view& str) { + CESIUM_ASSERT(this->_pObject); + return this->readObjectKeyExtensionKhrGaussianSplattingCompressionSpz( + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz::TypeName, + str, + *this->_pObject); +} + +void ExtensionKhrGaussianSplattingCompressionSpzJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { + std::any& value = + o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz()) + .first->second; + this->reset( + pParentHandler, + &std::any_cast( + value)); +} + +CesiumJsonReader::IJsonHandler* +ExtensionKhrGaussianSplattingCompressionSpzJsonHandler:: + readObjectKeyExtensionKhrGaussianSplattingCompressionSpz( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& o) { + using namespace std::string_literals; + + if ("bufferView"s == str) { + return property("bufferView", this->_bufferView, o.bufferView); + } + + return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); +} + +ExtensionKhrGaussianSplattingCompressionSpzReader:: + ExtensionKhrGaussianSplattingCompressionSpzReader() { + registerReaderExtensions(this->_options); +} + +CesiumJsonReader::JsonReaderOptions& +ExtensionKhrGaussianSplattingCompressionSpzReader::getOptions() { + return this->_options; +} + +const CesiumJsonReader::JsonReaderOptions& +ExtensionKhrGaussianSplattingCompressionSpzReader::getOptions() const { + return this->_options; +} + +CesiumJsonReader::ReadJsonResult< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz> +ExtensionKhrGaussianSplattingCompressionSpzReader::readFromJson( + const std::span& data) const { + ExtensionKhrGaussianSplattingCompressionSpzJsonHandler handler( + this->_options); + return CesiumJsonReader::JsonReader::readJson(data, handler); +} + +CesiumJsonReader::ReadJsonResult< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz> +ExtensionKhrGaussianSplattingCompressionSpzReader::readFromJson( + const rapidjson::Value& value) const { + ExtensionKhrGaussianSplattingCompressionSpzJsonHandler handler( + this->_options); + return CesiumJsonReader::JsonReader::readJson(value, handler); +} + +CesiumJsonReader::ReadJsonResult< + std::vector> +ExtensionKhrGaussianSplattingCompressionSpzReader::readArrayFromJson( + const rapidjson::Value& value) const { + CesiumJsonReader::ArrayJsonHandler< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz, + ExtensionKhrGaussianSplattingCompressionSpzJsonHandler> + handler(this->_options); + return CesiumJsonReader::JsonReader::readJson(value, handler); +} + } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! diff --git a/CesiumGltfReader/generated/src/registerReaderExtensions.cpp b/CesiumGltfReader/generated/src/registerReaderExtensions.cpp index 835175724..d5397dfae 100644 --- a/CesiumGltfReader/generated/src/registerReaderExtensions.cpp +++ b/CesiumGltfReader/generated/src/registerReaderExtensions.cpp @@ -16,6 +16,7 @@ #include "ExtensionExtPrimitiveVoxelsJsonHandler.h" #include "ExtensionExtStructuralMetadataJsonHandler.h" #include "ExtensionKhrDracoMeshCompressionJsonHandler.h" +#include "ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h" #include "ExtensionKhrGaussianSplattingJsonHandler.h" #include "ExtensionKhrImplicitShapesJsonHandler.h" #include "ExtensionKhrMaterialsUnlitJsonHandler.h" @@ -85,6 +86,9 @@ void registerReaderExtensions(CesiumJsonReader::JsonReaderOptions& options) { options.registerExtension< CesiumGltf::MeshPrimitive, ExtensionKhrGaussianSplattingJsonHandler>(); + options.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionKhrGaussianSplattingCompressionSpzJsonHandler>(); options.registerExtension< CesiumGltf::Node, ExtensionExtInstanceFeaturesJsonHandler>(); diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp index 807308517..b8e6dde21 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,11 @@ void writeJson( CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); +void writeJson( + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context); + void writeJson( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, @@ -1186,9 +1192,20 @@ void writeJson( const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); - if (obj.quantizedPositionScale != 1) { - jsonWriter.Key("quantizedPositionScale"); - writeJson(obj.quantizedPositionScale, jsonWriter, context); + writeExtensibleObject(obj, jsonWriter, context); + + jsonWriter.EndObject(); +} + +void writeJson( + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context) { + jsonWriter.StartObject(); + + if (obj.bufferView > -1) { + jsonWriter.Key("bufferView"); + writeJson(obj.bufferView, jsonWriter, context); } writeExtensibleObject(obj, jsonWriter, context); @@ -2921,6 +2938,13 @@ void ExtensionKhrGaussianSplattingJsonWriter::write( writeJson(obj, jsonWriter, context); } +void ExtensionKhrGaussianSplattingCompressionSpzJsonWriter::write( + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context) { + writeJson(obj, jsonWriter, context); +} + void PaddingJsonWriter::write( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.h b/CesiumGltfWriter/generated/src/ModelJsonWriter.h index 6df277b5d..6676b2148 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.h +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.h @@ -35,6 +35,7 @@ struct ExtensionExtImplicitEllipsoidRegion; struct ExtensionExtImplicitCylinderRegion; struct ExtensionExtPrimitiveVoxels; struct ExtensionKhrGaussianSplatting; +struct ExtensionKhrGaussianSplattingCompressionSpz; struct Padding; struct Shape; struct Cylinder; @@ -416,6 +417,20 @@ struct ExtensionKhrGaussianSplattingJsonWriter { const CesiumJsonWriter::ExtensionWriterContext& context); }; +struct ExtensionKhrGaussianSplattingCompressionSpzJsonWriter { + using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz; + + /** @brief The official name of the extension. This should be the same as its + * key in the `extensions` object. */ + static constexpr const char* ExtensionName = + "KHR_gaussian_splatting_compression_spz"; + + static void write( + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context); +}; + struct PaddingJsonWriter { using ValueType = CesiumGltf::Padding; diff --git a/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp b/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp index 6f76bbaa3..026a6386d 100644 --- a/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp +++ b/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -90,6 +91,9 @@ void registerWriterExtensions( context.registerExtension< CesiumGltf::MeshPrimitive, ExtensionKhrGaussianSplattingJsonWriter>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionKhrGaussianSplattingCompressionSpzJsonWriter>(); context.registerExtension< CesiumGltf::Node, ExtensionExtInstanceFeaturesJsonWriter>(); diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 2ff824bf1..201b0389e 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -20,3 +20,5 @@ add_library(picosha2::picosha2 IMPORTED INTERFACE GLOBAL) set_target_properties(picosha2::picosha2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_BUILD_DIR}/include" ) + +add_subdirectory(spz) \ No newline at end of file diff --git a/extern/spz b/extern/spz new file mode 160000 index 000000000..8767f22a3 --- /dev/null +++ b/extern/spz @@ -0,0 +1 @@ +Subproject commit 8767f22a39c32f8190b2e0f9ba256516c74e7b73 diff --git a/tools/generate-classes/glTF.json b/tools/generate-classes/glTF.json index 2e59ac897..e254ab713 100644 --- a/tools/generate-classes/glTF.json +++ b/tools/generate-classes/glTF.json @@ -164,8 +164,11 @@ "EXT_primitive_voxels glTF Mesh Primitive extension": { "overrideName": "ExtensionExtPrimitiveVoxels" }, - "KHR_gaussian_splatting glTF primitive extension": { + "KHR_gaussian_splatting glTF Mesh Primitive Extension": { "overrideName": "ExtensionKhrGaussianSplatting" + }, + "KHR_gaussian_splatting_compression_spz glTF Mesh Primitive Extension": { + "overrideName": "ExtensionKhrGaussianSplattingCompressionSpz" } }, "extensions": [ @@ -293,7 +296,14 @@ }, { "extensionName": "KHR_gaussian_splatting", - "schema": "Khronos/KHR_gaussian_splatting/schema/primitive.KHR_gaussian_splatting.schema.json", + "schema": "Khronos/KHR_gaussian_splatting/schema/mesh.primitive.KHR_gaussian_splatting.schema.json", + "attachTo": [ + "mesh.primitive" + ] + }, + { + "extensionName": "KHR_gaussian_splatting_compression_spz", + "schema": "Khronos/KHR_gaussian_splatting_compression_spz/schema/mesh.primitive.KHR_gaussian_splatting_compression_spz.schema.json", "attachTo": [ "mesh.primitive" ] diff --git a/tools/generate-classes/package.json b/tools/generate-classes/package.json index dca58df64..07e53fe87 100644 --- a/tools/generate-classes/package.json +++ b/tools/generate-classes/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "generate-3d-tiles": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/tileset.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/common/rootProperty.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/PropertyTable/propertyTable.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Subtree/subtree.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Schema/schema.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Statistics/statistics.schema.json --output ../../Cesium3DTiles --readerOutput ../../Cesium3DTilesReader --writerOutput ../../Cesium3DTilesWriter --extensions https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/extensions/ --namespace Cesium3DTiles --readerNamespace Cesium3DTilesReader --writerNamespace Cesium3DTilesWriter --config 3dTiles.json", - "generate-gltf": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/specification/2.0/schema/glTF.schema.json --output ../../CesiumGltf --readerOutput ../../CesiumGltfReader --writerOutput ../../CesiumGltfWriter --extensions https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/extensions/2.0/ https://raw.githubusercontent.com/CesiumGS/glTF/spz-extension/extensions/2.0/ --namespace CesiumGltf --readerNamespace CesiumGltfReader --writerNamespace CesiumGltfWriter --config glTF.json", + "generate-gltf": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/specification/2.0/schema/glTF.schema.json --output ../../CesiumGltf --readerOutput ../../CesiumGltfReader --writerOutput ../../CesiumGltfWriter --extensions https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/extensions/2.0/ https://raw.githubusercontent.com/CesiumGS/glTF/draft-splat-spz/extensions/2.0/ --namespace CesiumGltf --readerNamespace CesiumGltfReader --writerNamespace CesiumGltfWriter --config glTF.json", "generate-quantized-mesh-terrain": "node index.js --schemas ../../CesiumQuantizedMeshTerrain/schema/layer.schema.json --output ../../CesiumQuantizedMeshTerrain --readerOutput ../../CesiumQuantizedMeshTerrain --writerOutput ../../CesiumQuantizedMeshTerrain --extensions ../../CesiumQuantizedMeshTerrain/schema/extensions --namespace CesiumQuantizedMeshTerrain --readerNamespace CesiumQuantizedMeshTerrain --writerNamespace CesiumQuantizedMeshTerrain --config QuantizedMeshTerrain.json" }, "author": "CesiumGS, Inc. and Contributors", From d687c267dbb7089713d2f7cd39eaf396b3d57530 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 19 Aug 2025 14:43:44 -0400 Subject: [PATCH 03/34] Implement spz decoding --- CesiumGltfReader/CMakeLists.txt | 1 + .../include/CesiumGltfReader/GltfReader.h | 7 + CesiumGltfReader/src/GltfReader.cpp | 9 + CesiumGltfReader/src/decodeSpz.cpp | 358 ++++++++++++++++++ CesiumGltfReader/src/decodeSpz.h | 7 + 5 files changed, 382 insertions(+) create mode 100644 CesiumGltfReader/src/decodeSpz.cpp create mode 100644 CesiumGltfReader/src/decodeSpz.h diff --git a/CesiumGltfReader/CMakeLists.txt b/CesiumGltfReader/CMakeLists.txt index b42adabd5..7ed55f7e5 100644 --- a/CesiumGltfReader/CMakeLists.txt +++ b/CesiumGltfReader/CMakeLists.txt @@ -62,6 +62,7 @@ target_link_libraries(CesiumGltfReader meshoptimizer::meshoptimizer modp_b64::modp_b64 KTX::ktx + spz::spz WebP::webp WebP::webpdecoder $,libjpeg-turbo::turbojpeg,libjpeg-turbo::turbojpeg-static> ) diff --git a/CesiumGltfReader/include/CesiumGltfReader/GltfReader.h b/CesiumGltfReader/include/CesiumGltfReader/GltfReader.h index 6ce9f5728..e7b542f5d 100644 --- a/CesiumGltfReader/include/CesiumGltfReader/GltfReader.h +++ b/CesiumGltfReader/include/CesiumGltfReader/GltfReader.h @@ -89,6 +89,13 @@ struct CESIUMGLTFREADER_API GltfReaderOptions { */ bool decodeMeshOptData = true; + /** + * @brief Whether gaussian splatting data are decompressed as part of the load + * process, or left in the compressed format according to the + * KHR_gaussian_splatting_compression_spz extension. + */ + bool decodeSpz = true; + /** * @brief Whether the quantized mesh data are dequantized and converted to * floating-point values when loading, according to the KHR_mesh_quantization diff --git a/CesiumGltfReader/src/GltfReader.cpp b/CesiumGltfReader/src/GltfReader.cpp index d33117088..0e74433f5 100644 --- a/CesiumGltfReader/src/GltfReader.cpp +++ b/CesiumGltfReader/src/GltfReader.cpp @@ -3,6 +3,7 @@ #include "decodeDataUrls.h" #include "decodeDraco.h" #include "decodeMeshOpt.h" +#include "decodeSpz.h" #include "dequantizeMeshData.h" #include "registerReaderExtensions.h" @@ -358,6 +359,14 @@ void postprocess(GltfReaderResult& readGltf, const GltfReaderOptions& options) { decodeMeshOpt(model, readGltf); } + if (options.decodeSpz && std::find( + model.extensionsUsed.begin(), + model.extensionsUsed.end(), + "KHR_gaussian_splatting_compression_spz") != + model.extensionsUsed.end()) { + decodeSpz(readGltf); + } + if (options.dequantizeMeshData && std::find( model.extensionsUsed.begin(), diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp new file mode 100644 index 000000000..4e2168a47 --- /dev/null +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -0,0 +1,358 @@ +#include "decodeSpz.h" + +#include "CesiumGltf/BufferView.h" +#include "CesiumGltf/MeshPrimitive.h" +#include "splat-types.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace CesiumGltfReader { +namespace { + +const float SH_C0 = 0.282095f; + +std::unique_ptr decodeBufferViewToGaussianCloud( + GltfReaderResult& readGltf, + CesiumGltf::MeshPrimitive& /* primitive */, + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& spz) { + CESIUM_TRACE("CesiumGltfReader::decodeBufferViewToGaussianCloud"); + CESIUM_ASSERT(readGltf.model.has_value()); + CesiumGltf::Model& model = readGltf.model.value(); + + CesiumGltf::BufferView* pBufferView = + CesiumGltf::Model::getSafe(&model.bufferViews, spz.bufferView); + if (!pBufferView) { + readGltf.warnings.emplace_back("SPZ bufferView index is invalid."); + return nullptr; + } + + const CesiumGltf::BufferView& bufferView = *pBufferView; + + CesiumGltf::Buffer* pBuffer = + CesiumGltf::Model::getSafe(&model.buffers, bufferView.buffer); + if (!pBuffer) { + readGltf.warnings.emplace_back( + "SPZ bufferView has an invalid buffer index."); + return nullptr; + } + + CesiumGltf::Buffer& buffer = *pBuffer; + + if (bufferView.byteOffset < 0 || bufferView.byteLength < 0 || + bufferView.byteOffset + bufferView.byteLength > + static_cast(buffer.cesium.data.size())) { + readGltf.warnings.emplace_back("SPZ bufferView extends beyond its buffer."); + return nullptr; + } + + // TODO: we should be able to avoid a copy by just adding an overload of + // `spz::loadSpz` + std::vector data( + reinterpret_cast( + buffer.cesium.data.data() + bufferView.byteOffset), + reinterpret_cast( + buffer.cesium.data.data() + bufferView.byteOffset + + static_cast(bufferView.byteLength))); + + spz::GaussianCloud gaussians = + spz::loadSpz(data, spz::UnpackOptions{spz::CoordinateSystem::LUF}); + + return std::make_unique(std::move(gaussians)); +} + +int32_t findAttributeIndex( + CesiumGltf::MeshPrimitive& primitive, + const std::string& attributeName, + bool mightHavePrefix) { + // In previous versions of the KHR_gaussian_splatting draft, the attributes + // were prefixed with an underscore. Now, they are prefixed with + // `KHR_gaussian_splatting:`. We need to check for both as some tilesets were + // already created with the previous naming conventions. + auto attrIt = primitive.attributes.find(attributeName); + if (attrIt != primitive.attributes.end()) { + return attrIt->second; + } + + if (mightHavePrefix) { + attrIt = primitive.attributes.find( + "KHR_gaussian_splatting:" + attributeName.substr(1)); + if (attrIt != primitive.attributes.end()) { + return attrIt->second; + } + } + + return -1; +} + +CesiumGltf::Accessor* findAccessor( + GltfReaderResult& readGltf, + CesiumGltf::MeshPrimitive& primitive, + const std::string& attributeName, + bool mightHavePrefix) { + const int32_t attributeIndex = + findAttributeIndex(primitive, attributeName, mightHavePrefix); + if (attributeIndex == -1) { + readGltf.warnings.emplace_back( + "Failed to find " + attributeName + + " attribute on KHR_guassian_splatting_compression_spz primitive"); + return nullptr; + } + + CesiumGltf::Accessor* pAccessor = + CesiumGltf::Model::getSafe(&readGltf.model->accessors, attributeIndex); + if (!pAccessor) { + readGltf.warnings.emplace_back( + "Failed to find accessor at index " + std::to_string(attributeIndex)); + return nullptr; + } + + return pAccessor; +} + +void copyShCoeff( + GltfReaderResult& readGltf, + CesiumGltf::MeshPrimitive& primitive, + CesiumGltf::Buffer& buffer, + spz::GaussianCloud* pGaussian, + int degree, + int coeffIndex) { + size_t offset = 0; + if (degree == 1) { + offset = static_cast(coeffIndex * 3); + } else if (degree == 2) { + offset = static_cast(9 + coeffIndex * 3); + } else if (degree == 3) { + offset = static_cast(24 + coeffIndex * 3); + } + + size_t shTotal = 0; + if (pGaussian->shDegree == 1) { + shTotal = static_cast(3 * 3); + } else if (pGaussian->shDegree == 2) { + shTotal = static_cast(8 * 3); + } else if (pGaussian->shDegree == 3) { + shTotal = static_cast(15 * 3); + } + + CesiumGltf::Accessor* pAccessor = findAccessor( + readGltf, + primitive, + fmt::format("_SH_DEGREE_{}_COEF_{}", degree, coeffIndex), + true); + if (!pAccessor) { + return; + } + + pAccessor->bufferView = + static_cast(readGltf.model->bufferViews.size()); + CesiumGltf::BufferView& bufferView = + readGltf.model->bufferViews.emplace_back(); + bufferView.buffer = static_cast(readGltf.model->buffers.size() - 1); + bufferView.byteLength = static_cast( + sizeof(float) * static_cast(pGaussian->numPoints) * 3); + + size_t start = buffer.cesium.data.size(); + bufferView.byteOffset = static_cast(start); + buffer.cesium.data.resize(start + static_cast(bufferView.byteLength)); + for (size_t i = offset; i < pGaussian->sh.size(); i += shTotal) { + memcpy( + buffer.cesium.data.data() + start, + pGaussian->sh.data() + i, + sizeof(float) * 3); + start += sizeof(float) * 3; + } +} + +void decodePrimitive( + GltfReaderResult& readGltf, + CesiumGltf::MeshPrimitive& primitive, + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& spz) { + CESIUM_TRACE("CesiumGltfReader::decodePrimitive"); + CESIUM_ASSERT(readGltf.model.has_value()); + + std::unique_ptr pGaussian = + decodeBufferViewToGaussianCloud(readGltf, primitive, spz); + if (!pGaussian) { + return; + } + + const size_t bufferLength = + sizeof(float) * (pGaussian->positions.size() + pGaussian->scales.size() + + pGaussian->scales.size() + pGaussian->rotations.size() + + pGaussian->alphas.size() + pGaussian->colors.size() + + pGaussian->sh.size()); + + CesiumGltf::Buffer& buffer = readGltf.model->buffers.emplace_back(); + buffer.byteLength = static_cast(bufferLength); + buffer.cesium.data.reserve(bufferLength); + + // Position and rotation can be copied verbatim + CesiumGltf::Accessor* pPosAccessor = + findAccessor(readGltf, primitive, "POSITION", false); + if (pPosAccessor) { + pPosAccessor->bufferView = + static_cast(readGltf.model->bufferViews.size()); + CesiumGltf::BufferView& bufferView = + readGltf.model->bufferViews.emplace_back(); + bufferView.buffer = + static_cast(readGltf.model->buffers.size() - 1); + bufferView.byteLength = + static_cast(sizeof(float) * pGaussian->positions.size()); + + size_t start = buffer.cesium.data.size(); + bufferView.byteOffset = static_cast(start); + buffer.cesium.data.resize( + start + static_cast(bufferView.byteLength)); + memcpy( + buffer.cesium.data.data() + start, + pGaussian->positions.data(), + sizeof(float) * pGaussian->positions.size()); + } + + CesiumGltf::Accessor* pRotAccessor = + findAccessor(readGltf, primitive, "_ROTATION", true); + if (pRotAccessor) { + pRotAccessor->bufferView = + static_cast(readGltf.model->bufferViews.size()); + CesiumGltf::BufferView& bufferView = + readGltf.model->bufferViews.emplace_back(); + bufferView.buffer = + static_cast(readGltf.model->buffers.size() - 1); + bufferView.byteLength = + static_cast(sizeof(float) * pGaussian->rotations.size()); + + size_t start = buffer.cesium.data.size(); + bufferView.byteOffset = static_cast(start); + buffer.cesium.data.resize( + start + static_cast(bufferView.byteLength)); + memcpy( + buffer.cesium.data.data() + start, + pGaussian->rotations.data(), + sizeof(float) * pGaussian->rotations.size()); + } + + // Color needs to be interleaved with alphas and have its values converted + CesiumGltf::Accessor* pColorAccessor = + findAccessor(readGltf, primitive, "COLOR_0", false); + if (pColorAccessor) { + { + pColorAccessor->bufferView = + static_cast(readGltf.model->bufferViews.size()); + CesiumGltf::BufferView& bufferView = + readGltf.model->bufferViews.emplace_back(); + bufferView.buffer = + static_cast(readGltf.model->buffers.size() - 1); + bufferView.byteLength = static_cast( + sizeof(float) * + (pGaussian->colors.size() + pGaussian->alphas.size())); + + size_t start = buffer.cesium.data.size(); + buffer.cesium.data.resize(start + pGaussian->alphas.size() * 4); + bufferView.byteOffset = static_cast(start); + for (size_t i = 0; i < pGaussian->alphas.size(); i++) { + glm::fvec4 color( + 0.5 + pGaussian->colors[i * 3] * SH_C0, + 0.5 + pGaussian->colors[i * 3 + 1] * SH_C0, + 0.5 + pGaussian->colors[i * 3 + 2] * SH_C0, + 1.0 / (1.0 + exp(-pGaussian->alphas[i]))); + memcpy( + buffer.cesium.data.data() + start + i * sizeof(glm::fvec4), + &color, + sizeof(glm::fvec4)); + } + } + + // Scale needs to be converted + CesiumGltf::Accessor* pScaleAccessor = + findAccessor(readGltf, primitive, "_SCALE", true); + if (pScaleAccessor) { + { + pScaleAccessor->bufferView = + static_cast(readGltf.model->bufferViews.size()); + CesiumGltf::BufferView& bufferView = + readGltf.model->bufferViews.emplace_back(); + bufferView.buffer = + static_cast(readGltf.model->buffers.size() - 1); + bufferView.byteLength = + static_cast(sizeof(float) * pGaussian->scales.size()); + + size_t start = buffer.cesium.data.size(); + buffer.cesium.data.resize(start + pGaussian->scales.size()); + bufferView.byteOffset = static_cast(start); + for (size_t i = 0; i < pGaussian->scales.size(); i++) { + float scale = exp(pGaussian->scales[i]); + memcpy( + buffer.cesium.data.data() + start + i * sizeof(float), + &scale, + sizeof(float)); + } + } + } + + if (pGaussian->shDegree > 0) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 0); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 1); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 2); + } + + if (pGaussian->shDegree > 1) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 0); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 1); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 2); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 3); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 4); + } + + if (pGaussian->shDegree > 2) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 0); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 1); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 2); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 3); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 4); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 5); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 6); + } + } // namespace +} +} // namespace + +void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { + CESIUM_TRACE("CesiumGltfReader::decodeSpz"); + if (!readGltf.model) { + return; + } + + CesiumGltf::Model& model = readGltf.model.value(); + + for (CesiumGltf::Mesh& mesh : model.meshes) { + for (CesiumGltf::MeshPrimitive& primitive : mesh.primitives) { + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz* pSpz = + primitive.getExtension< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz>(); + if (!pSpz) { + continue; + } + + decodePrimitive(readGltf, primitive, *pSpz); + + // Remove the SPZ extension as it no longer applies. + primitive.extensions.erase( + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz:: + ExtensionName); + } + } + + model.removeExtensionRequired( + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz::ExtensionName); +} +} // namespace CesiumGltfReader \ No newline at end of file diff --git a/CesiumGltfReader/src/decodeSpz.h b/CesiumGltfReader/src/decodeSpz.h new file mode 100644 index 000000000..ffbf9b4cf --- /dev/null +++ b/CesiumGltfReader/src/decodeSpz.h @@ -0,0 +1,7 @@ +#pragma once + +namespace CesiumGltfReader { +struct GltfReaderResult; + +void decodeSpz(GltfReaderResult& readGltf); +} // namespace CesiumGltfReader From b6896cf8075be4ad752e58181d57f77fc420c329 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 19 Aug 2025 15:20:16 -0400 Subject: [PATCH 04/34] Use overlay port for spz --- .gitmodules | 3 --- CMakeLists.txt | 3 ++- CesiumGltfReader/src/decodeSpz.cpp | 12 +++-------- extern/CMakeLists.txt | 4 +--- extern/spz | 1 - extern/vcpkg/ports/spz/loadSpz.patch | 29 +++++++++++++++++++++++++++ extern/vcpkg/ports/spz/portfile.cmake | 17 ++++++++++++++++ extern/vcpkg/ports/spz/vcpkg.json | 19 ++++++++++++++++++ vcpkg.json | 3 ++- 9 files changed, 73 insertions(+), 18 deletions(-) delete mode 160000 extern/spz create mode 100644 extern/vcpkg/ports/spz/loadSpz.patch create mode 100644 extern/vcpkg/ports/spz/portfile.cmake create mode 100644 extern/vcpkg/ports/spz/vcpkg.json diff --git a/.gitmodules b/.gitmodules index 8cc769630..d64ba06db 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "extern/cmake-modules"] path = extern/cmake-modules url = https://github.com/bilke/cmake-modules.git -[submodule "extern/spz"] - path = extern/spz - url = https://github.com/nianticlabs/spz.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 974cf72d6..d2e86820c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,7 +92,7 @@ set(PACKAGES_PUBLIC asyncplusplus expected-lite fmt glm rapidjson spdlog stb ada set(PACKAGES_PRIVATE abseil draco ktx modp-base64 meshoptimizer openssl s2geometry libjpeg-turbo sqlite3 tinyxml2 libwebp zlib-ng picosha2 - earcut-hpp cpp-httplib[core] libmorton zstd + earcut-hpp cpp-httplib[core] libmorton zstd spz ) # asmjit needed by blend2d on non-iOS platforms (iOS doesn't support JIT) @@ -321,6 +321,7 @@ find_package(tinyxml2 CONFIG REQUIRED) find_package(unofficial-sqlite3 CONFIG REQUIRED) find_package(WebP CONFIG REQUIRED) find_package(blend2d CONFIG REQUIRED) +find_package(spz CONFIG REQUIRED) # asmjit should not be included with iOS builds as iOS doesn't support JIT compilation. if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS") find_package(asmjit CONFIG REQUIRED) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 4e2168a47..2c2b821be 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -55,17 +55,11 @@ std::unique_ptr decodeBufferViewToGaussianCloud( return nullptr; } - // TODO: we should be able to avoid a copy by just adding an overload of - // `spz::loadSpz` - std::vector data( + spz::GaussianCloud gaussians = spz::loadSpz( reinterpret_cast( buffer.cesium.data.data() + bufferView.byteOffset), - reinterpret_cast( - buffer.cesium.data.data() + bufferView.byteOffset + - static_cast(bufferView.byteLength))); - - spz::GaussianCloud gaussians = - spz::loadSpz(data, spz::UnpackOptions{spz::CoordinateSystem::LUF}); + static_cast(bufferView.byteLength), + spz::UnpackOptions{spz::CoordinateSystem::LUF}); return std::make_unique(std::move(gaussians)); } diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 201b0389e..3b59a32e5 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -19,6 +19,4 @@ target_include_directories(earcut INTERFACE "${EARCUT_HPP_INCLUDE_DIRS}") add_library(picosha2::picosha2 IMPORTED INTERFACE GLOBAL) set_target_properties(picosha2::picosha2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_BUILD_DIR}/include" -) - -add_subdirectory(spz) \ No newline at end of file +) \ No newline at end of file diff --git a/extern/spz b/extern/spz deleted file mode 160000 index 8767f22a3..000000000 --- a/extern/spz +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8767f22a39c32f8190b2e0f9ba256516c74e7b73 diff --git a/extern/vcpkg/ports/spz/loadSpz.patch b/extern/vcpkg/ports/spz/loadSpz.patch new file mode 100644 index 000000000..631336073 --- /dev/null +++ b/extern/vcpkg/ports/spz/loadSpz.patch @@ -0,0 +1,29 @@ +diff --git a/src/cc/load-spz.cc b/src/cc/load-spz.cc +index e028445..7388d56 100644 +--- a/src/cc/load-spz.cc ++++ b/src/cc/load-spz.cc +@@ -635,6 +635,10 @@ GaussianCloud loadSpz(const std::vector &data, const UnpackOptions &o) + return unpackGaussians(loadSpzPacked(data), o); + } + ++GaussianCloud loadSpz(const uint8_t *data, int32_t size, const UnpackOptions &o) { ++ return unpackGaussians(loadSpzPacked(data, size), o); ++} ++ + bool saveSpz(const GaussianCloud &g, const PackOptions &o, const std::string &filename) { + std::vector data; + if (!saveSpz(g, o, &data)) { +diff --git a/src/cc/load-spz.h b/src/cc/load-spz.h +index a624f45..a10e696 100644 +--- a/src/cc/load-spz.h ++++ b/src/cc/load-spz.h +@@ -73,6 +73,9 @@ bool saveSpz( + // Loads Gaussian splat from a vector of bytes in packed format. + GaussianCloud loadSpz(const std::vector &data, const UnpackOptions &options); + ++// Loads Gaussian splat from a byte pointer in packed format. ++GaussianCloud loadSpz(const uint8_t *data, int32_t size, const UnpackOptions &options); ++ + // Loads Gaussian splat from a vector of bytes in packed format. + PackedGaussians loadSpzPacked(const std::string &filename); + PackedGaussians loadSpzPacked(const uint8_t *data, int32_t size); diff --git a/extern/vcpkg/ports/spz/portfile.cmake b/extern/vcpkg/ports/spz/portfile.cmake new file mode 100644 index 000000000..e166e1a54 --- /dev/null +++ b/extern/vcpkg/ports/spz/portfile.cmake @@ -0,0 +1,17 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO nianticlabs/spz + REF "v2.0.0" + SHA512 e1ee9314bd0a698e73db6d02937a20eea9419864d45eaa03e184cd9fca07dc08a92c2dfedf8e2415cbfc1ca3917435eb54ad0badd0f584aeeb2038b3bf7f000a + HEAD_REF main + PATCHES + loadSpz.patch +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" +) + +vcpkg_cmake_install() + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/extern/vcpkg/ports/spz/vcpkg.json b/extern/vcpkg/ports/spz/vcpkg.json new file mode 100644 index 000000000..5fd8873bb --- /dev/null +++ b/extern/vcpkg/ports/spz/vcpkg.json @@ -0,0 +1,19 @@ +{ + "name": "spz", + "version": "2.0.0", + "description": [ + "A 3D Gaussians format" + ], + "homepage": "https://github.com/nianticlabs/spz", + "license": "MIT", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +} diff --git a/vcpkg.json b/vcpkg.json index b82571206..891f3f34a 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -40,7 +40,8 @@ { "name": "asmjit", "platform": "!ios" - } + }, + "spz" ] } From 9258a5b79ad9e1ddf0c642ef2eb4d8171c2c706e Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Wed, 20 Aug 2025 11:41:00 -0400 Subject: [PATCH 05/34] Use zlib-ng for spz --- extern/vcpkg/ports/spz/portfile.cmake | 1 + extern/vcpkg/ports/spz/useZlibng.patch | 95 ++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 extern/vcpkg/ports/spz/useZlibng.patch diff --git a/extern/vcpkg/ports/spz/portfile.cmake b/extern/vcpkg/ports/spz/portfile.cmake index e166e1a54..2173d383a 100644 --- a/extern/vcpkg/ports/spz/portfile.cmake +++ b/extern/vcpkg/ports/spz/portfile.cmake @@ -6,6 +6,7 @@ vcpkg_from_github( HEAD_REF main PATCHES loadSpz.patch + useZlibng.patch ) vcpkg_cmake_configure( diff --git a/extern/vcpkg/ports/spz/useZlibng.patch b/extern/vcpkg/ports/spz/useZlibng.patch new file mode 100644 index 000000000..2954a1012 --- /dev/null +++ b/extern/vcpkg/ports/spz/useZlibng.patch @@ -0,0 +1,95 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 8a92969..f1edcd7 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -10,7 +10,7 @@ include(GNUInstallDirs) + option(BUILD_SHARED_LIBS "Build using shared libraries" ON) + + # zlib is required to build the project +-find_package(ZLIB REQUIRED) ++find_package(zlib-ng REQUIRED) + + set(spz_sources + "${CMAKE_CURRENT_SOURCE_DIR}/src/cc/load-spz.cc" +@@ -28,7 +28,7 @@ set(spz_headers + add_library(spz ${spz_sources}) + add_library(spz::spz ALIAS spz) + +-target_link_libraries(spz PRIVATE ZLIB::ZLIB) ++target_link_libraries(spz PRIVATE zlib-ng) + + target_include_directories(spz + PUBLIC $ +diff --git a/src/cc/load-spz.cc b/src/cc/load-spz.cc +index 7388d56..a1f5ffe 100644 +--- a/src/cc/load-spz.cc ++++ b/src/cc/load-spz.cc +@@ -1,6 +1,6 @@ + #include "load-spz.h" + +-#include ++#include + + #ifdef ANDROID + #include +@@ -141,10 +141,10 @@ struct PackedGaussiansHeader { + bool decompressGzippedImpl( + const uint8_t *compressed, size_t size, int32_t windowSize, std::vector *out) { + std::vector buffer(8192); +- z_stream stream = {}; ++ zng_stream stream = {}; + stream.next_in = const_cast(compressed); + stream.avail_in = size; +- if (inflateInit2(&stream, windowSize) != Z_OK) { ++ if (zng_inflateInit2(&stream, windowSize) != Z_OK) { + return false; + } + out->clear(); +@@ -152,7 +152,7 @@ bool decompressGzippedImpl( + while (true) { + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); +- int32_t res = inflate(&stream, Z_NO_FLUSH); ++ int32_t res = zng_inflate(&stream, Z_NO_FLUSH); + if (res != Z_OK && res != Z_STREAM_END) { + break; + } +@@ -162,7 +162,7 @@ bool decompressGzippedImpl( + break; + } + } +- inflateEnd(&stream); ++ zng_inflateEnd(&stream); + return success; + } + +@@ -185,9 +185,9 @@ bool decompressGzipped(const uint8_t *compressed, size_t size, std::string *out) + + bool compressGzipped(const uint8_t *data, size_t size, std::vector *out) { + std::vector buffer(8192); +- z_stream stream = {}; ++ zng_stream stream = {}; + if ( +- deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 16 + MAX_WBITS, 9, Z_DEFAULT_STRATEGY) ++ zng_deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 16 + MAX_WBITS, 9, Z_DEFAULT_STRATEGY) + != Z_OK) { + return false; + } +@@ -199,7 +199,7 @@ bool compressGzipped(const uint8_t *data, size_t size, std::vector *out + while (true) { + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); +- int32_t res = deflate(&stream, Z_FINISH); ++ int32_t res = zng_deflate(&stream, Z_FINISH); + if (res != Z_OK && res != Z_STREAM_END) { + break; + } +@@ -209,7 +209,7 @@ bool compressGzipped(const uint8_t *data, size_t size, std::vector *out + break; + } + } +- deflateEnd(&stream); ++ zng_deflateEnd(&stream); + return success; + } + From 6efafe6bc9a57a657256ba0774567848ffd8a943 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Wed, 20 Aug 2025 13:44:35 -0400 Subject: [PATCH 06/34] Just use non-ng zlib, seems to have fewer issues --- extern/vcpkg/ports/spz/portfile.cmake | 5 +- extern/vcpkg/ports/spz/useZlibng.patch | 95 -------------------------- extern/vcpkg/ports/spz/vcpkg.json | 3 +- 3 files changed, 4 insertions(+), 99 deletions(-) delete mode 100644 extern/vcpkg/ports/spz/useZlibng.patch diff --git a/extern/vcpkg/ports/spz/portfile.cmake b/extern/vcpkg/ports/spz/portfile.cmake index 2173d383a..d2ddcc4be 100644 --- a/extern/vcpkg/ports/spz/portfile.cmake +++ b/extern/vcpkg/ports/spz/portfile.cmake @@ -1,12 +1,11 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO nianticlabs/spz - REF "v2.0.0" - SHA512 e1ee9314bd0a698e73db6d02937a20eea9419864d45eaa03e184cd9fca07dc08a92c2dfedf8e2415cbfc1ca3917435eb54ad0badd0f584aeeb2038b3bf7f000a + REF "8767f22a39c32f8190b2e0f9ba256516c74e7b73" + SHA512 fb0154b8154e252d08b9751df3b66e75baf21cd4c9cec9c8de520f7cee62e86ab1d27f4d5a64f44e8bdac7b72fe465860181aa5b726c252742c6611ed91d9437 HEAD_REF main PATCHES loadSpz.patch - useZlibng.patch ) vcpkg_cmake_configure( diff --git a/extern/vcpkg/ports/spz/useZlibng.patch b/extern/vcpkg/ports/spz/useZlibng.patch deleted file mode 100644 index 2954a1012..000000000 --- a/extern/vcpkg/ports/spz/useZlibng.patch +++ /dev/null @@ -1,95 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 8a92969..f1edcd7 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -10,7 +10,7 @@ include(GNUInstallDirs) - option(BUILD_SHARED_LIBS "Build using shared libraries" ON) - - # zlib is required to build the project --find_package(ZLIB REQUIRED) -+find_package(zlib-ng REQUIRED) - - set(spz_sources - "${CMAKE_CURRENT_SOURCE_DIR}/src/cc/load-spz.cc" -@@ -28,7 +28,7 @@ set(spz_headers - add_library(spz ${spz_sources}) - add_library(spz::spz ALIAS spz) - --target_link_libraries(spz PRIVATE ZLIB::ZLIB) -+target_link_libraries(spz PRIVATE zlib-ng) - - target_include_directories(spz - PUBLIC $ -diff --git a/src/cc/load-spz.cc b/src/cc/load-spz.cc -index 7388d56..a1f5ffe 100644 ---- a/src/cc/load-spz.cc -+++ b/src/cc/load-spz.cc -@@ -1,6 +1,6 @@ - #include "load-spz.h" - --#include -+#include - - #ifdef ANDROID - #include -@@ -141,10 +141,10 @@ struct PackedGaussiansHeader { - bool decompressGzippedImpl( - const uint8_t *compressed, size_t size, int32_t windowSize, std::vector *out) { - std::vector buffer(8192); -- z_stream stream = {}; -+ zng_stream stream = {}; - stream.next_in = const_cast(compressed); - stream.avail_in = size; -- if (inflateInit2(&stream, windowSize) != Z_OK) { -+ if (zng_inflateInit2(&stream, windowSize) != Z_OK) { - return false; - } - out->clear(); -@@ -152,7 +152,7 @@ bool decompressGzippedImpl( - while (true) { - stream.next_out = buffer.data(); - stream.avail_out = buffer.size(); -- int32_t res = inflate(&stream, Z_NO_FLUSH); -+ int32_t res = zng_inflate(&stream, Z_NO_FLUSH); - if (res != Z_OK && res != Z_STREAM_END) { - break; - } -@@ -162,7 +162,7 @@ bool decompressGzippedImpl( - break; - } - } -- inflateEnd(&stream); -+ zng_inflateEnd(&stream); - return success; - } - -@@ -185,9 +185,9 @@ bool decompressGzipped(const uint8_t *compressed, size_t size, std::string *out) - - bool compressGzipped(const uint8_t *data, size_t size, std::vector *out) { - std::vector buffer(8192); -- z_stream stream = {}; -+ zng_stream stream = {}; - if ( -- deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 16 + MAX_WBITS, 9, Z_DEFAULT_STRATEGY) -+ zng_deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 16 + MAX_WBITS, 9, Z_DEFAULT_STRATEGY) - != Z_OK) { - return false; - } -@@ -199,7 +199,7 @@ bool compressGzipped(const uint8_t *data, size_t size, std::vector *out - while (true) { - stream.next_out = buffer.data(); - stream.avail_out = buffer.size(); -- int32_t res = deflate(&stream, Z_FINISH); -+ int32_t res = zng_deflate(&stream, Z_FINISH); - if (res != Z_OK && res != Z_STREAM_END) { - break; - } -@@ -209,7 +209,7 @@ bool compressGzipped(const uint8_t *data, size_t size, std::vector *out - break; - } - } -- deflateEnd(&stream); -+ zng_deflateEnd(&stream); - return success; - } - diff --git a/extern/vcpkg/ports/spz/vcpkg.json b/extern/vcpkg/ports/spz/vcpkg.json index 5fd8873bb..08c14dc61 100644 --- a/extern/vcpkg/ports/spz/vcpkg.json +++ b/extern/vcpkg/ports/spz/vcpkg.json @@ -14,6 +14,7 @@ { "name": "vcpkg-cmake-config", "host": true - } + }, + "zlib" ] } From d2f5d780ce0b232f015d69b5b0425798b79b72e6 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Fri, 22 Aug 2025 11:22:04 -0400 Subject: [PATCH 07/34] Zlib dependency --- CMakeLists.txt | 3 ++- CesiumGltfReader/CMakeLists.txt | 1 + extern/vcpkg/ports/spz/portfile.cmake | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2e86820c..514b97663 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,7 +92,7 @@ set(PACKAGES_PUBLIC asyncplusplus expected-lite fmt glm rapidjson spdlog stb ada set(PACKAGES_PRIVATE abseil draco ktx modp-base64 meshoptimizer openssl s2geometry libjpeg-turbo sqlite3 tinyxml2 libwebp zlib-ng picosha2 - earcut-hpp cpp-httplib[core] libmorton zstd spz + earcut-hpp cpp-httplib[core] libmorton zstd spz zlib ) # asmjit needed by blend2d on non-iOS platforms (iOS doesn't support JIT) @@ -301,6 +301,7 @@ list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}") # targets. If needed, they can be installed with CMake config files # etc. find_package(zlib-ng REQUIRED) +find_package(zlib REQUIRED) find_package(modp_b64 REQUIRED) find_package(ada CONFIG REQUIRED) diff --git a/CesiumGltfReader/CMakeLists.txt b/CesiumGltfReader/CMakeLists.txt index 7ed55f7e5..96a1d5c0b 100644 --- a/CesiumGltfReader/CMakeLists.txt +++ b/CesiumGltfReader/CMakeLists.txt @@ -63,6 +63,7 @@ target_link_libraries(CesiumGltfReader modp_b64::modp_b64 KTX::ktx spz::spz + ZLIB::ZLIB WebP::webp WebP::webpdecoder $,libjpeg-turbo::turbojpeg,libjpeg-turbo::turbojpeg-static> ) diff --git a/extern/vcpkg/ports/spz/portfile.cmake b/extern/vcpkg/ports/spz/portfile.cmake index d2ddcc4be..60f14aeba 100644 --- a/extern/vcpkg/ports/spz/portfile.cmake +++ b/extern/vcpkg/ports/spz/portfile.cmake @@ -10,8 +10,11 @@ vcpkg_from_github( vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -DBUILD_SHARED_LIBS=OFF ) vcpkg_cmake_install() +vcpkg_copy_pdbs() vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") From 01ef36e6ed25d90e5d189f0d007026a3b6ec420b Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 26 Aug 2025 11:45:04 -0400 Subject: [PATCH 08/34] Rename SPZ extension --- .../ExtensionKhrGaussianSplatting.h | 24 ++- ...sionKhrGaussianSplattingCompressionSpz2.h} | 10 +- .../ExtensionKhrGaussianSplattingHintsValue.h | 53 +++++ ...rGaussianSplattingCompressionSpz2Reader.h} | 24 +-- ...sionKhrGaussianSplattingHintsValueReader.h | 79 ++++++++ ...sianSplattingCompressionSpz2JsonHandler.h} | 18 +- ...hrGaussianSplattingHintsValueJsonHandler.h | 38 ++++ ...ExtensionKhrGaussianSplattingJsonHandler.h | 5 + .../generated/src/GeneratedJsonHandlers.cpp | 181 ++++++++++++++---- .../src/registerReaderExtensions.cpp | 9 +- .../generated/src/ModelJsonWriter.cpp | 54 +++++- .../generated/src/ModelJsonWriter.h | 20 +- .../src/registerWriterExtensions.cpp | 9 +- tools/generate-classes/glTF.json | 10 +- 14 files changed, 452 insertions(+), 82 deletions(-) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionKhrGaussianSplattingCompressionSpz.h => ExtensionKhrGaussianSplattingCompressionSpz2.h} (88%) create mode 100644 CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingHintsValue.h rename CesiumGltfReader/generated/include/CesiumGltfReader/{ExtensionKhrGaussianSplattingCompressionSpzReader.h => ExtensionKhrGaussianSplattingCompressionSpz2Reader.h} (81%) create mode 100644 CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingHintsValueReader.h rename CesiumGltfReader/generated/src/{ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h => ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler.h} (74%) create mode 100644 CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingHintsValueJsonHandler.h diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h index a69191399..4dcd7a3be 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h @@ -2,9 +2,13 @@ // DO NOT EDIT THIS FILE! #pragma once +#include #include #include +#include +#include + namespace CesiumGltf { /** * @brief Data for a 3D Gaussian Splat primitive. @@ -19,6 +23,19 @@ struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final * key in the `extensions` object. */ static constexpr const char* ExtensionName = "KHR_gaussian_splatting"; + /** + * @brief The shape of the Gaussian to render. Gaussians may be available in + * different shapes, so this is a freeform field that defaults to ellipsoid. + * See the extension specification for futher known types. + */ + std::string shape = "ellipsoid"; + + /** + * @brief Optional rendering hints for rendering the 3D Gaussian splats. + * Renderers are free to ignore any of these. + */ + std::optional hints; + /** * @brief Calculates the size in bytes of this object, including the contents * of all collections, pointers, and strings. This will NOT include the size @@ -30,7 +47,12 @@ struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final accum += int64_t(sizeof(ExtensionKhrGaussianSplatting)); accum += CesiumUtility::ExtensibleObject::getSizeBytes() - int64_t(sizeof(CesiumUtility::ExtensibleObject)); - + accum += int64_t(this->shape.capacity() * sizeof(char)); + if (this->hints) { + accum += + this->hints->getSizeBytes() - + int64_t(sizeof(CesiumGltf::ExtensionKhrGaussianSplattingHintsValue)); + } return accum; } }; diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h similarity index 88% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h index dc573a0b2..ab233f748 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h @@ -9,19 +9,19 @@ namespace CesiumGltf { /** - * @brief Compressed data for SPZ primitive. + * @brief Compressed data for SPZ v2 primitive. */ -struct CESIUMGLTF_API ExtensionKhrGaussianSplattingCompressionSpz final +struct CESIUMGLTF_API ExtensionKhrGaussianSplattingCompressionSpz2 final : public CesiumUtility::ExtensibleObject { /** * @brief The original name of this type. */ static constexpr const char* TypeName = - "ExtensionKhrGaussianSplattingCompressionSpz"; + "ExtensionKhrGaussianSplattingCompressionSpz2"; /** @brief The official name of the extension. This should be the same as its * key in the `extensions` object. */ static constexpr const char* ExtensionName = - "KHR_gaussian_splatting_compression_spz"; + "KHR_gaussian_splatting_compression_spz_2"; /** * @brief The index of the bufferView. @@ -36,7 +36,7 @@ struct CESIUMGLTF_API ExtensionKhrGaussianSplattingCompressionSpz final */ int64_t getSizeBytes() const { int64_t accum = 0; - accum += int64_t(sizeof(ExtensionKhrGaussianSplattingCompressionSpz)); + accum += int64_t(sizeof(ExtensionKhrGaussianSplattingCompressionSpz2)); accum += CesiumUtility::ExtensibleObject::getSizeBytes() - int64_t(sizeof(CesiumUtility::ExtensibleObject)); diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingHintsValue.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingHintsValue.h new file mode 100644 index 000000000..dc982147f --- /dev/null +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplattingHintsValue.h @@ -0,0 +1,53 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include + +#include + +namespace CesiumGltf { +/** + * @brief Optional rendering hints for rendering the 3D Gaussian splats. + * Renderers are free to ignore any of these. + */ +struct CESIUMGLTF_API ExtensionKhrGaussianSplattingHintsValue final + : public CesiumUtility::ExtensibleObject { + /** + * @brief The original name of this type. + */ + static constexpr const char* TypeName = + "ExtensionKhrGaussianSplattingHintsValue"; + + /** + * @brief Provides a hint specifying how to project the Gaussians to achieve a + * perspective correct value. This is a freeform field that defaults to + * perspective. See the extension specification for further known types. + */ + std::string projection = "perspective"; + + /** + * @brief Provides a hint specifying how to sort the Gaussians during + * rendering. This is a freeform field defaulting to cameraDistance. See the + * extension specification for further known types. + */ + std::string sortingMethod = "cameraDistance"; + + /** + * @brief Calculates the size in bytes of this object, including the contents + * of all collections, pointers, and strings. This will NOT include the size + * of any extensions attached to the object. Calling this method may be slow + * as it requires traversing the object's entire structure. + */ + int64_t getSizeBytes() const { + int64_t accum = 0; + accum += int64_t(sizeof(ExtensionKhrGaussianSplattingHintsValue)); + accum += CesiumUtility::ExtensibleObject::getSizeBytes() - + int64_t(sizeof(CesiumUtility::ExtensibleObject)); + accum += int64_t(this->projection.capacity() * sizeof(char)); + accum += int64_t(this->sortingMethod.capacity() * sizeof(char)); + return accum; + } +}; +} // namespace CesiumGltf diff --git a/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpzReader.h b/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpz2Reader.h similarity index 81% rename from CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpzReader.h rename to CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpz2Reader.h index c2d8fd1c0..9262e72f1 100644 --- a/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpzReader.h +++ b/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpz2Reader.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -13,21 +13,21 @@ #include namespace CesiumGltf { -struct ExtensionKhrGaussianSplattingCompressionSpz; +struct ExtensionKhrGaussianSplattingCompressionSpz2; } // namespace CesiumGltf namespace CesiumGltfReader { /** - * @brief Reads \ref CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz - * "ExtensionKhrGaussianSplattingCompressionSpz" instances from JSON. + * @brief Reads \ref CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2 + * "ExtensionKhrGaussianSplattingCompressionSpz2" instances from JSON. */ -class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingCompressionSpzReader { +class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingCompressionSpz2Reader { public: /** * @brief Constructs a new instance. */ - ExtensionKhrGaussianSplattingCompressionSpzReader(); + ExtensionKhrGaussianSplattingCompressionSpz2Reader(); /** * @brief Gets the options controlling how the JSON is read. @@ -40,36 +40,36 @@ class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingCompressionSpzReader { const CesiumJsonReader::JsonReaderOptions& getOptions() const; /** - * @brief Reads an instance of ExtensionKhrGaussianSplattingCompressionSpz + * @brief Reads an instance of ExtensionKhrGaussianSplattingCompressionSpz2 * from a byte buffer. * * @param data The buffer from which to read the instance. * @return The result of reading the instance. */ CesiumJsonReader::ReadJsonResult< - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz> + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2> readFromJson(const std::span& data) const; /** - * @brief Reads an instance of ExtensionKhrGaussianSplattingCompressionSpz + * @brief Reads an instance of ExtensionKhrGaussianSplattingCompressionSpz2 * from a rapidJson::Value. * * @param value The value from which to read the instance. * @return The result of reading the instance. */ CesiumJsonReader::ReadJsonResult< - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz> + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2> readFromJson(const rapidjson::Value& value) const; /** * @brief Reads an array of instances of - * ExtensionKhrGaussianSplattingCompressionSpz from a rapidJson::Value. + * ExtensionKhrGaussianSplattingCompressionSpz2 from a rapidJson::Value. * * @param value The value from which to read the array of instances. * @return The result of reading the array of instances. */ CesiumJsonReader::ReadJsonResult< - std::vector> + std::vector> readArrayFromJson(const rapidjson::Value& value) const; private: diff --git a/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingHintsValueReader.h b/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingHintsValueReader.h new file mode 100644 index 000000000..ff8afd145 --- /dev/null +++ b/CesiumGltfReader/generated/include/CesiumGltfReader/ExtensionKhrGaussianSplattingHintsValueReader.h @@ -0,0 +1,79 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include +#include +#include + +#include + +#include +#include + +namespace CesiumGltf { +struct ExtensionKhrGaussianSplattingHintsValue; +} // namespace CesiumGltf + +namespace CesiumGltfReader { + +/** + * @brief Reads \ref CesiumGltf::ExtensionKhrGaussianSplattingHintsValue + * "ExtensionKhrGaussianSplattingHintsValue" instances from JSON. + */ +class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingHintsValueReader { +public: + /** + * @brief Constructs a new instance. + */ + ExtensionKhrGaussianSplattingHintsValueReader(); + + /** + * @brief Gets the options controlling how the JSON is read. + */ + CesiumJsonReader::JsonReaderOptions& getOptions(); + + /** + * @brief Gets the options controlling how the JSON is read. + */ + const CesiumJsonReader::JsonReaderOptions& getOptions() const; + + /** + * @brief Reads an instance of ExtensionKhrGaussianSplattingHintsValue from a + * byte buffer. + * + * @param data The buffer from which to read the instance. + * @return The result of reading the instance. + */ + CesiumJsonReader::ReadJsonResult< + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue> + readFromJson(const std::span& data) const; + + /** + * @brief Reads an instance of ExtensionKhrGaussianSplattingHintsValue from a + * rapidJson::Value. + * + * @param value The value from which to read the instance. + * @return The result of reading the instance. + */ + CesiumJsonReader::ReadJsonResult< + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue> + readFromJson(const rapidjson::Value& value) const; + + /** + * @brief Reads an array of instances of + * ExtensionKhrGaussianSplattingHintsValue from a rapidJson::Value. + * + * @param value The value from which to read the array of instances. + * @return The result of reading the array of instances. + */ + CesiumJsonReader::ReadJsonResult< + std::vector> + readArrayFromJson(const rapidjson::Value& value) const; + +private: + CesiumJsonReader::JsonReaderOptions _options; +}; + +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler.h similarity index 74% rename from CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler.h index dde1a8c5e..56172931b 100644 --- a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include @@ -11,20 +11,20 @@ class JsonReaderOptions; } // namespace CesiumJsonReader namespace CesiumGltfReader { -class ExtensionKhrGaussianSplattingCompressionSpzJsonHandler +class ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler, public CesiumJsonReader::IExtensionJsonHandler { public: - using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz; + using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2; static constexpr const char* ExtensionName = - "KHR_gaussian_splatting_compression_spz"; + "KHR_gaussian_splatting_compression_spz_2"; - explicit ExtensionKhrGaussianSplattingCompressionSpzJsonHandler( + explicit ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler( const CesiumJsonReader::JsonReaderOptions& options) noexcept; void reset( IJsonHandler* pParentHandler, - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz* pObject); + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pObject); IJsonHandler* readObjectKey(const std::string_view& str) override; @@ -36,13 +36,13 @@ class ExtensionKhrGaussianSplattingCompressionSpzJsonHandler IJsonHandler& getHandler() override { return *this; } protected: - IJsonHandler* readObjectKeyExtensionKhrGaussianSplattingCompressionSpz( + IJsonHandler* readObjectKeyExtensionKhrGaussianSplattingCompressionSpz2( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& o); + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& o); private: - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz* _pObject = nullptr; + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* _pObject = nullptr; CesiumJsonReader::IntegerJsonHandler _bufferView; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingHintsValueJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingHintsValueJsonHandler.h new file mode 100644 index 000000000..9c0cb364b --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingHintsValueJsonHandler.h @@ -0,0 +1,38 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include +#include +#include + +namespace CesiumJsonReader { +class JsonReaderOptions; +} // namespace CesiumJsonReader + +namespace CesiumGltfReader { +class ExtensionKhrGaussianSplattingHintsValueJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingHintsValue; + + explicit ExtensionKhrGaussianSplattingHintsValueJsonHandler( + const CesiumJsonReader::JsonReaderOptions& options) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue* pObject); + + IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyExtensionKhrGaussianSplattingHintsValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& o); + +private: + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _projection; + CesiumJsonReader::StringJsonHandler _sortingMethod; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h index cdd22579e..11521f836 100644 --- a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h @@ -2,8 +2,11 @@ // DO NOT EDIT THIS FILE! #pragma once +#include "ExtensionKhrGaussianSplattingHintsValueJsonHandler.h" + #include #include +#include namespace CesiumJsonReader { class JsonReaderOptions; @@ -41,5 +44,7 @@ class ExtensionKhrGaussianSplattingJsonHandler private: CesiumGltf::ExtensionKhrGaussianSplatting* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _shape; + ExtensionKhrGaussianSplattingHintsValueJsonHandler _hints; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp index ac5ee04e5..b081bde00 100644 --- a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp +++ b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp @@ -3005,7 +3005,9 @@ namespace CesiumGltfReader { ExtensionKhrGaussianSplattingJsonHandler:: ExtensionKhrGaussianSplattingJsonHandler( const CesiumJsonReader::JsonReaderOptions& options) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(options) {} + : CesiumJsonReader::ExtensibleObjectJsonHandler(options), + _shape(), + _hints(options) {} void ExtensionKhrGaussianSplattingJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, @@ -3044,7 +3046,12 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrGaussianSplattingJsonHandler:: CesiumGltf::ExtensionKhrGaussianSplatting& o) { using namespace std::string_literals; - (void)o; + if ("shape"s == str) { + return property("shape", this->_shape, o.shape); + } + if ("hints"s == str) { + return property("hints", this->_hints, o.hints); + } return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3092,11 +3099,11 @@ ExtensionKhrGaussianSplattingReader::readArrayFromJson( // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! // NOLINTBEGIN(readability-duplicate-include) -#include "ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h" +#include "ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler.h" #include "registerReaderExtensions.h" -#include -#include +#include +#include #include #include #include @@ -3116,29 +3123,29 @@ ExtensionKhrGaussianSplattingReader::readArrayFromJson( namespace CesiumGltfReader { -ExtensionKhrGaussianSplattingCompressionSpzJsonHandler:: - ExtensionKhrGaussianSplattingCompressionSpzJsonHandler( +ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler:: + ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler( const CesiumJsonReader::JsonReaderOptions& options) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(options), _bufferView() {} -void ExtensionKhrGaussianSplattingCompressionSpzJsonHandler::reset( +void ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz* pObject) { + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionKhrGaussianSplattingCompressionSpzJsonHandler::readObjectKey( +ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler::readObjectKey( const std::string_view& str) { CESIUM_ASSERT(this->_pObject); - return this->readObjectKeyExtensionKhrGaussianSplattingCompressionSpz( - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz::TypeName, + return this->readObjectKeyExtensionKhrGaussianSplattingCompressionSpz2( + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2::TypeName, str, *this->_pObject); } -void ExtensionKhrGaussianSplattingCompressionSpzJsonHandler::reset( +void ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { @@ -3146,20 +3153,20 @@ void ExtensionKhrGaussianSplattingCompressionSpzJsonHandler::reset( o.extensions .emplace( extensionName, - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz()) + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2()) .first->second; this->reset( pParentHandler, - &std::any_cast( + &std::any_cast( value)); } CesiumJsonReader::IJsonHandler* -ExtensionKhrGaussianSplattingCompressionSpzJsonHandler:: - readObjectKeyExtensionKhrGaussianSplattingCompressionSpz( +ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler:: + readObjectKeyExtensionKhrGaussianSplattingCompressionSpz2( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& o) { + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& o) { using namespace std::string_literals; if ("bufferView"s == str) { @@ -3169,46 +3176,156 @@ ExtensionKhrGaussianSplattingCompressionSpzJsonHandler:: return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } -ExtensionKhrGaussianSplattingCompressionSpzReader:: - ExtensionKhrGaussianSplattingCompressionSpzReader() { +ExtensionKhrGaussianSplattingCompressionSpz2Reader:: + ExtensionKhrGaussianSplattingCompressionSpz2Reader() { registerReaderExtensions(this->_options); } CesiumJsonReader::JsonReaderOptions& -ExtensionKhrGaussianSplattingCompressionSpzReader::getOptions() { +ExtensionKhrGaussianSplattingCompressionSpz2Reader::getOptions() { return this->_options; } const CesiumJsonReader::JsonReaderOptions& -ExtensionKhrGaussianSplattingCompressionSpzReader::getOptions() const { +ExtensionKhrGaussianSplattingCompressionSpz2Reader::getOptions() const { return this->_options; } CesiumJsonReader::ReadJsonResult< - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz> -ExtensionKhrGaussianSplattingCompressionSpzReader::readFromJson( + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2> +ExtensionKhrGaussianSplattingCompressionSpz2Reader::readFromJson( const std::span& data) const { - ExtensionKhrGaussianSplattingCompressionSpzJsonHandler handler( + ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler handler( this->_options); return CesiumJsonReader::JsonReader::readJson(data, handler); } CesiumJsonReader::ReadJsonResult< - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz> -ExtensionKhrGaussianSplattingCompressionSpzReader::readFromJson( + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2> +ExtensionKhrGaussianSplattingCompressionSpz2Reader::readFromJson( const rapidjson::Value& value) const { - ExtensionKhrGaussianSplattingCompressionSpzJsonHandler handler( + ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler handler( this->_options); return CesiumJsonReader::JsonReader::readJson(value, handler); } CesiumJsonReader::ReadJsonResult< - std::vector> -ExtensionKhrGaussianSplattingCompressionSpzReader::readArrayFromJson( + std::vector> +ExtensionKhrGaussianSplattingCompressionSpz2Reader::readArrayFromJson( + const rapidjson::Value& value) const { + CesiumJsonReader::ArrayJsonHandler< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2, + ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler> + handler(this->_options); + return CesiumJsonReader::JsonReader::readJson(value, handler); +} + +} // namespace CesiumGltfReader +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +// NOLINTBEGIN(readability-duplicate-include) +#include "ExtensionKhrGaussianSplattingHintsValueJsonHandler.h" +#include "registerReaderExtensions.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +// NOLINTEND(readability-duplicate-include) + +namespace CesiumGltfReader { + +ExtensionKhrGaussianSplattingHintsValueJsonHandler:: + ExtensionKhrGaussianSplattingHintsValueJsonHandler( + const CesiumJsonReader::JsonReaderOptions& options) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(options), + _projection(), + _sortingMethod() {} + +void ExtensionKhrGaussianSplattingHintsValueJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue* pObject) { + CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); + this->_pObject = pObject; +} + +CesiumJsonReader::IJsonHandler* +ExtensionKhrGaussianSplattingHintsValueJsonHandler::readObjectKey( + const std::string_view& str) { + CESIUM_ASSERT(this->_pObject); + return this->readObjectKeyExtensionKhrGaussianSplattingHintsValue( + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionKhrGaussianSplattingHintsValueJsonHandler:: + readObjectKeyExtensionKhrGaussianSplattingHintsValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& o) { + using namespace std::string_literals; + + if ("projection"s == str) { + return property("projection", this->_projection, o.projection); + } + if ("sortingMethod"s == str) { + return property("sortingMethod", this->_sortingMethod, o.sortingMethod); + } + + return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); +} + +ExtensionKhrGaussianSplattingHintsValueReader:: + ExtensionKhrGaussianSplattingHintsValueReader() { + registerReaderExtensions(this->_options); +} + +CesiumJsonReader::JsonReaderOptions& +ExtensionKhrGaussianSplattingHintsValueReader::getOptions() { + return this->_options; +} + +const CesiumJsonReader::JsonReaderOptions& +ExtensionKhrGaussianSplattingHintsValueReader::getOptions() const { + return this->_options; +} + +CesiumJsonReader::ReadJsonResult< + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue> +ExtensionKhrGaussianSplattingHintsValueReader::readFromJson( + const std::span& data) const { + ExtensionKhrGaussianSplattingHintsValueJsonHandler handler(this->_options); + return CesiumJsonReader::JsonReader::readJson(data, handler); +} + +CesiumJsonReader::ReadJsonResult< + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue> +ExtensionKhrGaussianSplattingHintsValueReader::readFromJson( + const rapidjson::Value& value) const { + ExtensionKhrGaussianSplattingHintsValueJsonHandler handler(this->_options); + return CesiumJsonReader::JsonReader::readJson(value, handler); +} + +CesiumJsonReader::ReadJsonResult< + std::vector> +ExtensionKhrGaussianSplattingHintsValueReader::readArrayFromJson( const rapidjson::Value& value) const { CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz, - ExtensionKhrGaussianSplattingCompressionSpzJsonHandler> + CesiumGltf::ExtensionKhrGaussianSplattingHintsValue, + ExtensionKhrGaussianSplattingHintsValueJsonHandler> handler(this->_options); return CesiumJsonReader::JsonReader::readJson(value, handler); } diff --git a/CesiumGltfReader/generated/src/registerReaderExtensions.cpp b/CesiumGltfReader/generated/src/registerReaderExtensions.cpp index d5397dfae..87de99b69 100644 --- a/CesiumGltfReader/generated/src/registerReaderExtensions.cpp +++ b/CesiumGltfReader/generated/src/registerReaderExtensions.cpp @@ -16,7 +16,7 @@ #include "ExtensionExtPrimitiveVoxelsJsonHandler.h" #include "ExtensionExtStructuralMetadataJsonHandler.h" #include "ExtensionKhrDracoMeshCompressionJsonHandler.h" -#include "ExtensionKhrGaussianSplattingCompressionSpzJsonHandler.h" +#include "ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler.h" #include "ExtensionKhrGaussianSplattingJsonHandler.h" #include "ExtensionKhrImplicitShapesJsonHandler.h" #include "ExtensionKhrMaterialsUnlitJsonHandler.h" @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -86,9 +87,6 @@ void registerReaderExtensions(CesiumJsonReader::JsonReaderOptions& options) { options.registerExtension< CesiumGltf::MeshPrimitive, ExtensionKhrGaussianSplattingJsonHandler>(); - options.registerExtension< - CesiumGltf::MeshPrimitive, - ExtensionKhrGaussianSplattingCompressionSpzJsonHandler>(); options.registerExtension< CesiumGltf::Node, ExtensionExtInstanceFeaturesJsonHandler>(); @@ -140,5 +138,8 @@ void registerReaderExtensions(CesiumJsonReader::JsonReaderOptions& options) { options.registerExtension< CesiumGltf::Shape, ExtensionExtImplicitCylinderRegionJsonHandler>(); + options.registerExtension< + CesiumGltf::ExtensionKhrGaussianSplatting, + ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler>(); } } // namespace CesiumGltfReader diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp index b8e6dde21..360eadd4d 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp @@ -39,7 +39,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -226,7 +227,12 @@ void writeJson( const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& obj, + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context); + +void writeJson( + const CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); @@ -1192,13 +1198,23 @@ void writeJson( const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); + if (obj.shape != "ellipsoid") { + jsonWriter.Key("shape"); + writeJson(obj.shape, jsonWriter, context); + } + + if (obj.hints) { + jsonWriter.Key("hints"); + writeJson(obj.hints, jsonWriter, context); + } + writeExtensibleObject(obj, jsonWriter, context); jsonWriter.EndObject(); } void writeJson( - const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& obj, + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1213,6 +1229,27 @@ void writeJson( jsonWriter.EndObject(); } +void writeJson( + const CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context) { + jsonWriter.StartObject(); + + if (obj.projection != "perspective") { + jsonWriter.Key("projection"); + writeJson(obj.projection, jsonWriter, context); + } + + if (obj.sortingMethod != "cameraDistance") { + jsonWriter.Key("sortingMethod"); + writeJson(obj.sortingMethod, jsonWriter, context); + } + + writeExtensibleObject(obj, jsonWriter, context); + + jsonWriter.EndObject(); +} + void writeJson( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, @@ -2938,8 +2975,15 @@ void ExtensionKhrGaussianSplattingJsonWriter::write( writeJson(obj, jsonWriter, context); } -void ExtensionKhrGaussianSplattingCompressionSpzJsonWriter::write( - const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& obj, +void ExtensionKhrGaussianSplattingCompressionSpz2JsonWriter::write( + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context) { + writeJson(obj, jsonWriter, context); +} + +void ExtensionKhrGaussianSplattingHintsValueJsonWriter::write( + const CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.h b/CesiumGltfWriter/generated/src/ModelJsonWriter.h index 6676b2148..3f15785e0 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.h +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.h @@ -35,7 +35,8 @@ struct ExtensionExtImplicitEllipsoidRegion; struct ExtensionExtImplicitCylinderRegion; struct ExtensionExtPrimitiveVoxels; struct ExtensionKhrGaussianSplatting; -struct ExtensionKhrGaussianSplattingCompressionSpz; +struct ExtensionKhrGaussianSplattingCompressionSpz2; +struct ExtensionKhrGaussianSplattingHintsValue; struct Padding; struct Shape; struct Cylinder; @@ -417,16 +418,25 @@ struct ExtensionKhrGaussianSplattingJsonWriter { const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionKhrGaussianSplattingCompressionSpzJsonWriter { - using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz; +struct ExtensionKhrGaussianSplattingCompressionSpz2JsonWriter { + using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2; /** @brief The official name of the extension. This should be the same as its * key in the `extensions` object. */ static constexpr const char* ExtensionName = - "KHR_gaussian_splatting_compression_spz"; + "KHR_gaussian_splatting_compression_spz_2"; static void write( - const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& obj, + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& obj, + CesiumJsonWriter::JsonWriter& jsonWriter, + const CesiumJsonWriter::ExtensionWriterContext& context); +}; + +struct ExtensionKhrGaussianSplattingHintsValueJsonWriter { + using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingHintsValue; + + static void write( + const CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; diff --git a/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp b/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp index 026a6386d..b30a8772d 100644 --- a/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp +++ b/CesiumGltfWriter/generated/src/registerWriterExtensions.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -35,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -91,9 +92,6 @@ void registerWriterExtensions( context.registerExtension< CesiumGltf::MeshPrimitive, ExtensionKhrGaussianSplattingJsonWriter>(); - context.registerExtension< - CesiumGltf::MeshPrimitive, - ExtensionKhrGaussianSplattingCompressionSpzJsonWriter>(); context.registerExtension< CesiumGltf::Node, ExtensionExtInstanceFeaturesJsonWriter>(); @@ -144,5 +142,8 @@ void registerWriterExtensions( context.registerExtension< CesiumGltf::Shape, ExtensionExtImplicitCylinderRegionJsonWriter>(); + context.registerExtension< + CesiumGltf::ExtensionKhrGaussianSplatting, + ExtensionKhrGaussianSplattingCompressionSpz2JsonWriter>(); } } // namespace CesiumGltfWriter diff --git a/tools/generate-classes/glTF.json b/tools/generate-classes/glTF.json index e254ab713..cb02b1174 100644 --- a/tools/generate-classes/glTF.json +++ b/tools/generate-classes/glTF.json @@ -167,8 +167,8 @@ "KHR_gaussian_splatting glTF Mesh Primitive Extension": { "overrideName": "ExtensionKhrGaussianSplatting" }, - "KHR_gaussian_splatting_compression_spz glTF Mesh Primitive Extension": { - "overrideName": "ExtensionKhrGaussianSplattingCompressionSpz" + "KHR_gaussian_splatting_compression_spz_2 glTF Mesh Primitive Extension": { + "overrideName": "ExtensionKhrGaussianSplattingCompressionSpz2" } }, "extensions": [ @@ -302,10 +302,10 @@ ] }, { - "extensionName": "KHR_gaussian_splatting_compression_spz", - "schema": "Khronos/KHR_gaussian_splatting_compression_spz/schema/mesh.primitive.KHR_gaussian_splatting_compression_spz.schema.json", + "extensionName": "KHR_gaussian_splatting_compression_spz_2", + "schema": "Khronos/KHR_gaussian_splatting_compression_spz_2/schema/mesh.primitive.KHR_gaussian_splatting_compression_spz_2.schema.json", "attachTo": [ - "mesh.primitive" + "mesh.primitive.KHR_gaussian_splatting" ] } ] From 0d8ef6251702ee59b4ed09078bd4c0ee7f85f8c4 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 26 Aug 2025 13:20:54 -0400 Subject: [PATCH 09/34] Update to match spz2 renaming --- CMakeLists.txt | 2 +- CesiumGltfReader/src/decodeSpz.cpp | 26 ++++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 514b97663..664c803d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -301,7 +301,7 @@ list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}") # targets. If needed, they can be installed with CMake config files # etc. find_package(zlib-ng REQUIRED) -find_package(zlib REQUIRED) +find_package(ZLIB REQUIRED) find_package(modp_b64 REQUIRED) find_package(ada CONFIG REQUIRED) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 2c2b821be..f74a29e6f 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -5,7 +5,8 @@ #include "splat-types.h" #include -#include +#include +#include #include #include @@ -24,7 +25,7 @@ const float SH_C0 = 0.282095f; std::unique_ptr decodeBufferViewToGaussianCloud( GltfReaderResult& readGltf, CesiumGltf::MeshPrimitive& /* primitive */, - const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& spz) { + const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& spz) { CESIUM_TRACE("CesiumGltfReader::decodeBufferViewToGaussianCloud"); CESIUM_ASSERT(readGltf.model.has_value()); CesiumGltf::Model& model = readGltf.model.value(); @@ -98,7 +99,7 @@ CesiumGltf::Accessor* findAccessor( if (attributeIndex == -1) { readGltf.warnings.emplace_back( "Failed to find " + attributeName + - " attribute on KHR_guassian_splatting_compression_spz primitive"); + " attribute on KHR_gaussian_splatting_compression_spz_2 primitive"); return nullptr; } @@ -170,7 +171,7 @@ void copyShCoeff( void decodePrimitive( GltfReaderResult& readGltf, CesiumGltf::MeshPrimitive& primitive, - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz& spz) { + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& spz) { CESIUM_TRACE("CesiumGltfReader::decodePrimitive"); CESIUM_ASSERT(readGltf.model.has_value()); @@ -330,9 +331,14 @@ void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { for (CesiumGltf::Mesh& mesh : model.meshes) { for (CesiumGltf::MeshPrimitive& primitive : mesh.primitives) { - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz* pSpz = - primitive.getExtension< - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz>(); + CesiumGltf::ExtensionKhrGaussianSplatting* pSplat = primitive.getExtension(); + if(!pSplat) { + continue; + } + + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pSpz = + pSplat->getExtension< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>(); if (!pSpz) { continue; } @@ -340,13 +346,13 @@ void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { decodePrimitive(readGltf, primitive, *pSpz); // Remove the SPZ extension as it no longer applies. - primitive.extensions.erase( - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz:: + pSplat->extensions.erase( + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2:: ExtensionName); } } model.removeExtensionRequired( - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz::ExtensionName); + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2::ExtensionName); } } // namespace CesiumGltfReader \ No newline at end of file From 0193409bc027deac5228fc696473074ea6473cff Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 28 Aug 2025 14:11:19 -0400 Subject: [PATCH 10/34] SPZ test, fixes --- CesiumGltfReader/src/GltfReader.cpp | 2 +- CesiumGltfReader/src/decodeSpz.cpp | 153 +++++++++--------- CesiumGltfReader/test/TestGltfReader.cpp | 49 ++++++ CesiumGltfReader/test/data/SpzSplat/basic.glb | Bin 0 -> 1088 bytes 4 files changed, 129 insertions(+), 75 deletions(-) create mode 100644 CesiumGltfReader/test/data/SpzSplat/basic.glb diff --git a/CesiumGltfReader/src/GltfReader.cpp b/CesiumGltfReader/src/GltfReader.cpp index 0e74433f5..6db452d34 100644 --- a/CesiumGltfReader/src/GltfReader.cpp +++ b/CesiumGltfReader/src/GltfReader.cpp @@ -362,7 +362,7 @@ void postprocess(GltfReaderResult& readGltf, const GltfReaderOptions& options) { if (options.decodeSpz && std::find( model.extensionsUsed.begin(), model.extensionsUsed.end(), - "KHR_gaussian_splatting_compression_spz") != + "KHR_gaussian_splatting_compression_spz_2") != model.extensionsUsed.end()) { decodeSpz(readGltf); } diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index f74a29e6f..60d5ee4c5 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -175,6 +175,8 @@ void decodePrimitive( CESIUM_TRACE("CesiumGltfReader::decodePrimitive"); CESIUM_ASSERT(readGltf.model.has_value()); + // TODO: handle different accessor component types + std::unique_ptr pGaussian = decodeBufferViewToGaussianCloud(readGltf, primitive, spz); if (!pGaussian) { @@ -240,84 +242,86 @@ void decodePrimitive( CesiumGltf::Accessor* pColorAccessor = findAccessor(readGltf, primitive, "COLOR_0", false); if (pColorAccessor) { - { - pColorAccessor->bufferView = - static_cast(readGltf.model->bufferViews.size()); - CesiumGltf::BufferView& bufferView = - readGltf.model->bufferViews.emplace_back(); - bufferView.buffer = - static_cast(readGltf.model->buffers.size() - 1); - bufferView.byteLength = static_cast( - sizeof(float) * - (pGaussian->colors.size() + pGaussian->alphas.size())); - - size_t start = buffer.cesium.data.size(); - buffer.cesium.data.resize(start + pGaussian->alphas.size() * 4); - bufferView.byteOffset = static_cast(start); - for (size_t i = 0; i < pGaussian->alphas.size(); i++) { - glm::fvec4 color( - 0.5 + pGaussian->colors[i * 3] * SH_C0, - 0.5 + pGaussian->colors[i * 3 + 1] * SH_C0, - 0.5 + pGaussian->colors[i * 3 + 2] * SH_C0, - 1.0 / (1.0 + exp(-pGaussian->alphas[i]))); - memcpy( - buffer.cesium.data.data() + start + i * sizeof(glm::fvec4), - &color, - sizeof(glm::fvec4)); - } - } + pColorAccessor->bufferView = + static_cast(readGltf.model->bufferViews.size()); + CesiumGltf::BufferView& bufferView = + readGltf.model->bufferViews.emplace_back(); + bufferView.buffer = + static_cast(readGltf.model->buffers.size() - 1); + bufferView.byteLength = static_cast( + (pGaussian->colors.size() + pGaussian->alphas.size())); - // Scale needs to be converted - CesiumGltf::Accessor* pScaleAccessor = - findAccessor(readGltf, primitive, "_SCALE", true); - if (pScaleAccessor) { - { - pScaleAccessor->bufferView = - static_cast(readGltf.model->bufferViews.size()); - CesiumGltf::BufferView& bufferView = - readGltf.model->bufferViews.emplace_back(); - bufferView.buffer = - static_cast(readGltf.model->buffers.size() - 1); - bufferView.byteLength = - static_cast(sizeof(float) * pGaussian->scales.size()); - - size_t start = buffer.cesium.data.size(); - buffer.cesium.data.resize(start + pGaussian->scales.size()); - bufferView.byteOffset = static_cast(start); - for (size_t i = 0; i < pGaussian->scales.size(); i++) { - float scale = exp(pGaussian->scales[i]); - memcpy( - buffer.cesium.data.data() + start + i * sizeof(float), - &scale, - sizeof(float)); - } - } + size_t start = buffer.cesium.data.size(); + buffer.cesium.data.resize( + start + static_cast(bufferView.byteLength)); + bufferView.byteOffset = static_cast(start); + for (size_t i = 0; i < pGaussian->alphas.size(); i++) { + glm::fvec4 color( + 0.5 + pGaussian->colors[i * 3] * SH_C0, + 0.5 + pGaussian->colors[i * 3 + 1] * SH_C0, + 0.5 + pGaussian->colors[i * 3 + 2] * SH_C0, + 1.0 / (1.0 + exp(-pGaussian->alphas[i]))); + glm::u8vec4 coloru8( + (uint8_t)(color.x * 0xff), + (uint8_t)(color.y * 0xff), + (uint8_t)(color.z * 0xff), + (uint8_t)(color.w * 0xff)); + memcpy( + buffer.cesium.data.data() + start + i * sizeof(glm::u8vec4), + &coloru8, + sizeof(glm::u8vec4)); } + } - if (pGaussian->shDegree > 0) { - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 0); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 1); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 2); - } + // Scale needs to be converted + CesiumGltf::Accessor* pScaleAccessor = + findAccessor(readGltf, primitive, "_SCALE", true); + if (pScaleAccessor) { + pScaleAccessor->bufferView = + static_cast(readGltf.model->bufferViews.size()); + CesiumGltf::BufferView& bufferView = + readGltf.model->bufferViews.emplace_back(); + bufferView.buffer = + static_cast(readGltf.model->buffers.size() - 1); + bufferView.byteLength = + static_cast(sizeof(float) * pGaussian->scales.size()); - if (pGaussian->shDegree > 1) { - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 0); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 1); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 2); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 3); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 4); + size_t start = buffer.cesium.data.size(); + buffer.cesium.data.resize( + start + static_cast(bufferView.byteLength)); + bufferView.byteOffset = static_cast(start); + for (size_t i = 0; i < pGaussian->scales.size(); i++) { + float scale = exp(pGaussian->scales[i]); + memcpy( + buffer.cesium.data.data() + start + i * sizeof(float), + &scale, + sizeof(float)); } + } - if (pGaussian->shDegree > 2) { - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 0); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 1); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 2); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 3); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 4); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 5); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 6); - } - } // namespace + if (pGaussian->shDegree > 0) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 0); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 1); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 2); + } + + if (pGaussian->shDegree > 1) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 0); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 1); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 2); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 3); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 4); + } + + if (pGaussian->shDegree > 2) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 0); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 1); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 2); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 3); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 4); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 5); + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 6); + } } } // namespace @@ -331,8 +335,9 @@ void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { for (CesiumGltf::Mesh& mesh : model.meshes) { for (CesiumGltf::MeshPrimitive& primitive : mesh.primitives) { - CesiumGltf::ExtensionKhrGaussianSplatting* pSplat = primitive.getExtension(); - if(!pSplat) { + CesiumGltf::ExtensionKhrGaussianSplatting* pSplat = + primitive.getExtension(); + if (!pSplat) { continue; } diff --git a/CesiumGltfReader/test/TestGltfReader.cpp b/CesiumGltfReader/test/TestGltfReader.cpp index 31c398d43..57ec57396 100644 --- a/CesiumGltfReader/test/TestGltfReader.cpp +++ b/CesiumGltfReader/test/TestGltfReader.cpp @@ -813,3 +813,52 @@ TEST_CASE("GltfReader::postprocessGltf") { CHECK(s == "test"); } } + +TEST_CASE("SPZ decoding works properly") { + SUBCASE("Basic model with one vertex no spherical harmonics") { + GltfReader reader; + GltfReaderResult result = reader.readGltf(readFile( + std::filesystem::path(CesiumGltfReader_TEST_DATA_DIR) / "SpzSplat" / + "basic.glb")); + REQUIRE(result.model); + const Model& model = result.model.value(); + + REQUIRE(model.meshes.size() == 1); + REQUIRE(model.meshes[0].primitives.size() == 1); + + const std::unordered_map& attributes = + model.meshes[0].primitives[0].attributes; + + CHECK(attributes.size() == 4); + + REQUIRE(attributes.contains("POSITION")); + AccessorView positionView(model, attributes.at("POSITION")); + REQUIRE(positionView.status() == AccessorViewStatus::Valid); + REQUIRE(positionView.size() == 1); + CHECK(positionView[0] == glm::vec3(-1.0, 2.0, -3.0)); + + REQUIRE(attributes.contains("COLOR_0")); + AccessorView colorView(model, attributes.at("COLOR_0")); + REQUIRE(colorView.status() == AccessorViewStatus::Valid); + REQUIRE(colorView.size() == 1); + CHECK(colorView[0] == glm::u8vec4(145, 164, 181, 128)); + + REQUIRE(attributes.contains("KHR_gaussian_splatting:ROTATION")); + AccessorView rotationView( + model, + attributes.at("KHR_gaussian_splatting:ROTATION")); + REQUIRE(rotationView.status() == AccessorViewStatus::Valid); + REQUIRE(rotationView.size() == 1); + CHECK( + rotationView[0] == + glm::vec4(-0.003921628, -0.709803939, -0.709804058, 0.0)); + + REQUIRE(attributes.contains("KHR_gaussian_splatting:SCALE")); + AccessorView scaleView( + model, + attributes.at("KHR_gaussian_splatting:SCALE")); + REQUIRE(scaleView.status() == AccessorViewStatus::Valid); + REQUIRE(scaleView.size() == 1); + CHECK(scaleView[0] == glm::vec3(20.085537, 7.38905621, 2.71828175)); + } +} \ No newline at end of file diff --git a/CesiumGltfReader/test/data/SpzSplat/basic.glb b/CesiumGltfReader/test/data/SpzSplat/basic.glb new file mode 100644 index 0000000000000000000000000000000000000000..a15478b3e519d47647d84bc3953083aed66a94de GIT binary patch literal 1088 zcmcIj&5qMB5Vl|s2x%AI05n_;N>Ub~hyzQth(gt@+Oih}vD><>rN-&T&i)Yfz?oOr zC)nGbxbr03;J}R+U~IQrR&6DOM506<=bLY4K7Scax-V}KLY{9C^7AGkuRBSr0&!}D z(lS^2tri1_-@%(#?KI;?6p~MLTB?aOK;7<$ms(4%Qazn;W272w{E+tZY+49}=NA4k zjo>}~qgY!Um9qHn1-aJ3KwQDGC~PYbL-Z(s83o?&V|RI>apVeYx49C^bkC*&;@vQM zLUFTHm>g2b_$k6d8qpd~kxAsaij2#E!~J>L_o?WDWs@zEx;#+~|J zb06Xw9{*~?tDLrtzrn5XI%az5t++S>&W=SFnz@;>e1J|vEv+gF11}0<3hCVz(8c{Q zbW8vCo1r}e)Y4H<(0!pS-F)S_7OVl*nB9Mh|Ne_ci`@Hs3s-pE{-y8iupVPgB7z^0=$N97GUq5YcUwk3?hw Date: Thu, 28 Aug 2025 15:56:33 -0400 Subject: [PATCH 11/34] Quietly map older versions of the SPZ extension --- CesiumGltfReader/src/decodeSpz.cpp | 104 ++++++++++++++++++++++++++++- CesiumGltfReader/src/decodeSpz.h | 1 + 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 60d5ee4c5..b791109a3 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -2,17 +2,19 @@ #include "CesiumGltf/BufferView.h" #include "CesiumGltf/MeshPrimitive.h" -#include "splat-types.h" #include #include #include #include #include +#include +#include #include #include #include +#include #include #include @@ -22,6 +24,10 @@ namespace { const float SH_C0 = 0.282095f; +const std::string ALTERNATE_EXT_NAME1 = "KHR_spz_compression"; +const std::string ALTERNATE_EXT_NAME2 = + "KHR_gaussian_splatting_compression_spz"; + std::unique_ptr decodeBufferViewToGaussianCloud( GltfReaderResult& readGltf, CesiumGltf::MeshPrimitive& /* primitive */, @@ -323,6 +329,79 @@ void decodePrimitive( copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 6); } } + +CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* +addExtensionFromJsonValue( + const std::string& extName, + CesiumGltfReader::GltfReaderResult& readGltf, + CesiumGltf::ExtensionKhrGaussianSplatting& splatting, + CesiumUtility::JsonValue* pKhrJson) { + + if (!pKhrJson->isObject()) { + readGltf.errors.push_back(fmt::format("Invalid {} extension", extName)); + return nullptr; + } + const CesiumUtility::JsonValue::Object::const_iterator it = + pKhrJson->getObject().find("bufferView"); + if (it == pKhrJson->getObject().end()) { + readGltf.errors.push_back( + fmt::format("No `bufferView` property found on {} extension", extName)); + return nullptr; + } + if (!it->second.isInt64()) { + readGltf.errors.push_back(fmt::format( + "`bufferView` property on {} extension must be an integer value", + extName)); + return nullptr; + } + + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& ext = + splatting.addExtension< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>(); + ext.bufferView = static_cast(it->second.getInt64()); + return &ext; +} + +CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* conformExtension( + CesiumGltfReader::GltfReaderResult& readGltf, + CesiumGltf::MeshPrimitive& primitive, + CesiumGltf::ExtensionKhrGaussianSplatting& splatting) { + + // Check for the real thing. + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pSpz = + splatting.getExtension< + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>(); + if (pSpz) { + return pSpz; + } + + // Check for the old versions. + CesiumUtility::JsonValue* pKhrSpz = + primitive.getGenericExtension(ALTERNATE_EXT_NAME1); + if (pKhrSpz != nullptr) { + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pResult = + addExtensionFromJsonValue( + ALTERNATE_EXT_NAME1, + readGltf, + splatting, + pKhrSpz); + primitive.extensions.erase(ALTERNATE_EXT_NAME1); + return pResult; + } + + CesiumUtility::JsonValue* pSpzNoVersion = + primitive.getGenericExtension(ALTERNATE_EXT_NAME2); + if (pSpzNoVersion != nullptr) { + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pResult = + addExtensionFromJsonValue( + ALTERNATE_EXT_NAME2, + readGltf, + splatting, + pKhrSpz); + primitive.extensions.erase(ALTERNATE_EXT_NAME2); + return pResult; + } +} } // namespace void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { @@ -342,8 +421,7 @@ void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { } CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pSpz = - pSplat->getExtension< - CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>(); + conformExtension(readGltf, primitive, *pSplat); if (!pSpz) { continue; } @@ -359,5 +437,25 @@ void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { model.removeExtensionRequired( CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2::ExtensionName); + model.removeExtensionRequired(ALTERNATE_EXT_NAME1); + model.removeExtensionRequired(ALTERNATE_EXT_NAME2); +} + +bool hasSpzExtension(GltfReaderResult& readGltf) { + if (readGltf.model->isExtensionUsed( + CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2:: + ExtensionName)) { + return true; + } + + if (readGltf.model->isExtensionUsed(ALTERNATE_EXT_NAME1)) { + return true; + } + + if (readGltf.model->isExtensionUsed(ALTERNATE_EXT_NAME2)) { + return true; + } + + return false; } } // namespace CesiumGltfReader \ No newline at end of file diff --git a/CesiumGltfReader/src/decodeSpz.h b/CesiumGltfReader/src/decodeSpz.h index ffbf9b4cf..ad314ff68 100644 --- a/CesiumGltfReader/src/decodeSpz.h +++ b/CesiumGltfReader/src/decodeSpz.h @@ -4,4 +4,5 @@ namespace CesiumGltfReader { struct GltfReaderResult; void decodeSpz(GltfReaderResult& readGltf); +bool hasSpzExtension(GltfReaderResult& readGltf); } // namespace CesiumGltfReader From cb2c5a14585d16cb6cf8b02043c1b5a17c661f3b Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 28 Aug 2025 16:00:46 -0400 Subject: [PATCH 12/34] Missing a return... --- CesiumGltfReader/src/decodeSpz.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index b791109a3..4495effb0 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -401,6 +401,8 @@ CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* conformExtension( primitive.extensions.erase(ALTERNATE_EXT_NAME2); return pResult; } + + return nullptr; } } // namespace From 8a72d9357abd3417d4832cca4f7c91a8a29e347f Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 28 Aug 2025 18:21:14 -0400 Subject: [PATCH 13/34] Fix attribute names in SPZ loader --- CesiumGltfReader/src/decodeSpz.cpp | 107 ++++++++++++++--------------- 1 file changed, 52 insertions(+), 55 deletions(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 4495effb0..6c0e7140a 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -71,49 +71,26 @@ std::unique_ptr decodeBufferViewToGaussianCloud( return std::make_unique(std::move(gaussians)); } -int32_t findAttributeIndex( - CesiumGltf::MeshPrimitive& primitive, - const std::string& attributeName, - bool mightHavePrefix) { - // In previous versions of the KHR_gaussian_splatting draft, the attributes - // were prefixed with an underscore. Now, they are prefixed with - // `KHR_gaussian_splatting:`. We need to check for both as some tilesets were - // already created with the previous naming conventions. - auto attrIt = primitive.attributes.find(attributeName); - if (attrIt != primitive.attributes.end()) { - return attrIt->second; - } - - if (mightHavePrefix) { - attrIt = primitive.attributes.find( - "KHR_gaussian_splatting:" + attributeName.substr(1)); - if (attrIt != primitive.attributes.end()) { - return attrIt->second; - } - } - - return -1; -} - CesiumGltf::Accessor* findAccessor( GltfReaderResult& readGltf, CesiumGltf::MeshPrimitive& primitive, - const std::string& attributeName, - bool mightHavePrefix) { - const int32_t attributeIndex = - findAttributeIndex(primitive, attributeName, mightHavePrefix); - if (attributeIndex == -1) { + const std::string& attributeName) { + const std::unordered_map::const_iterator + attributeIt = primitive.attributes.find(attributeName); + if (attributeIt == primitive.attributes.end()) { readGltf.warnings.emplace_back( "Failed to find " + attributeName + " attribute on KHR_gaussian_splatting_compression_spz_2 primitive"); return nullptr; } - CesiumGltf::Accessor* pAccessor = - CesiumGltf::Model::getSafe(&readGltf.model->accessors, attributeIndex); + CesiumGltf::Accessor* pAccessor = CesiumGltf::Model::getSafe( + &readGltf.model->accessors, + attributeIt->second); if (!pAccessor) { readGltf.warnings.emplace_back( - "Failed to find accessor at index " + std::to_string(attributeIndex)); + "Failed to find accessor at index " + + std::to_string(attributeIt->second)); return nullptr; } @@ -148,8 +125,10 @@ void copyShCoeff( CesiumGltf::Accessor* pAccessor = findAccessor( readGltf, primitive, - fmt::format("_SH_DEGREE_{}_COEF_{}", degree, coeffIndex), - true); + fmt::format( + "KHR_gaussian_splatting:SH_DEGREE_{}_COEF_{}", + degree, + coeffIndex)); if (!pAccessor) { return; } @@ -201,7 +180,7 @@ void decodePrimitive( // Position and rotation can be copied verbatim CesiumGltf::Accessor* pPosAccessor = - findAccessor(readGltf, primitive, "POSITION", false); + findAccessor(readGltf, primitive, "POSITION"); if (pPosAccessor) { pPosAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); @@ -223,7 +202,7 @@ void decodePrimitive( } CesiumGltf::Accessor* pRotAccessor = - findAccessor(readGltf, primitive, "_ROTATION", true); + findAccessor(readGltf, primitive, "KHR_gaussian_splatting:ROTATION"); if (pRotAccessor) { pRotAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); @@ -246,7 +225,7 @@ void decodePrimitive( // Color needs to be interleaved with alphas and have its values converted CesiumGltf::Accessor* pColorAccessor = - findAccessor(readGltf, primitive, "COLOR_0", false); + findAccessor(readGltf, primitive, "COLOR_0"); if (pColorAccessor) { pColorAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); @@ -281,7 +260,7 @@ void decodePrimitive( // Scale needs to be converted CesiumGltf::Accessor* pScaleAccessor = - findAccessor(readGltf, primitive, "_SCALE", true); + findAccessor(readGltf, primitive, "KHR_gaussian_splatting:SCALE"); if (pScaleAccessor) { pScaleAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); @@ -306,27 +285,21 @@ void decodePrimitive( } if (pGaussian->shDegree > 0) { - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 0); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 1); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, 2); + for (int i = 0; i < 3; i++) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, i); + } } if (pGaussian->shDegree > 1) { - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 0); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 1); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 2); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 3); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, 4); + for (int i = 0; i < 5; i++) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, i); + } } if (pGaussian->shDegree > 2) { - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 0); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 1); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 2); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 3); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 4); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 5); - copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, 6); + for (int i = 0; i < 7; i++) { + copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, i); + } } } @@ -362,7 +335,30 @@ addExtensionFromJsonValue( return &ext; } -CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* conformExtension( +// Maps attribute names from older versions of the extension to the names from +// the current version of the extension. +void fixAttributeNames(CesiumGltf::MeshPrimitive& primitive) { + std::vector attributesToConvert; + attributesToConvert.reserve(primitive.attributes.size()); + for (std::pair& attribute : + primitive.attributes) { + if (attribute.first == "_SCALE" || attribute.first == "_ROTATION" || + attribute.first.starts_with("_SH_DEGREE_")) { + attributesToConvert.push_back(attribute.first); + } + } + + for (const std::string& oldName : attributesToConvert) { + const int32_t accessorIndex = primitive.attributes[oldName]; + primitive.attributes.erase(oldName); + primitive.attributes.emplace( + "KHR_gaussian_splatting:" + oldName.substr(1), + accessorIndex); + } +} + +CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* +getAndMaybeConvertSpzExtension( CesiumGltfReader::GltfReaderResult& readGltf, CesiumGltf::MeshPrimitive& primitive, CesiumGltf::ExtensionKhrGaussianSplatting& splatting) { @@ -423,11 +419,12 @@ void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { } CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pSpz = - conformExtension(readGltf, primitive, *pSplat); + getAndMaybeConvertSpzExtension(readGltf, primitive, *pSplat); if (!pSpz) { continue; } + fixAttributeNames(primitive); decodePrimitive(readGltf, primitive, *pSpz); // Remove the SPZ extension as it no longer applies. From 641e9f0b9edd2a670f6813d8162d0a079ca327a6 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Fri, 29 Aug 2025 10:57:59 -0400 Subject: [PATCH 14/34] SPZ loading fixes --- CesiumGltfReader/src/GltfReader.cpp | 6 +----- CesiumGltfReader/src/decodeSpz.cpp | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/CesiumGltfReader/src/GltfReader.cpp b/CesiumGltfReader/src/GltfReader.cpp index 6db452d34..7d8012143 100644 --- a/CesiumGltfReader/src/GltfReader.cpp +++ b/CesiumGltfReader/src/GltfReader.cpp @@ -359,11 +359,7 @@ void postprocess(GltfReaderResult& readGltf, const GltfReaderOptions& options) { decodeMeshOpt(model, readGltf); } - if (options.decodeSpz && std::find( - model.extensionsUsed.begin(), - model.extensionsUsed.end(), - "KHR_gaussian_splatting_compression_spz_2") != - model.extensionsUsed.end()) { + if (options.decodeSpz && hasSpzExtension(readGltf)) { decodeSpz(readGltf); } diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 6c0e7140a..5c7728285 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -24,7 +24,7 @@ namespace { const float SH_C0 = 0.282095f; -const std::string ALTERNATE_EXT_NAME1 = "KHR_spz_compression"; +const std::string ALTERNATE_EXT_NAME1 = "KHR_spz_gaussian_splats_compression"; const std::string ALTERNATE_EXT_NAME2 = "KHR_gaussian_splatting_compression_spz"; @@ -66,7 +66,7 @@ std::unique_ptr decodeBufferViewToGaussianCloud( reinterpret_cast( buffer.cesium.data.data() + bufferView.byteOffset), static_cast(bufferView.byteLength), - spz::UnpackOptions{spz::CoordinateSystem::LUF}); + spz::UnpackOptions{spz::CoordinateSystem::UNSPECIFIED}); return std::make_unique(std::move(gaussians)); } @@ -321,7 +321,7 @@ addExtensionFromJsonValue( fmt::format("No `bufferView` property found on {} extension", extName)); return nullptr; } - if (!it->second.isInt64()) { + if (!it->second.isInt64() && !it->second.isUint64()) { readGltf.errors.push_back(fmt::format( "`bufferView` property on {} extension must be an integer value", extName)); @@ -331,7 +331,9 @@ addExtensionFromJsonValue( CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& ext = splatting.addExtension< CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>(); - ext.bufferView = static_cast(it->second.getInt64()); + ext.bufferView = it->second.isInt64() + ? static_cast(it->second.getInt64()) + : static_cast(it->second.getUint64()); return &ext; } @@ -386,14 +388,14 @@ getAndMaybeConvertSpzExtension( } CesiumUtility::JsonValue* pSpzNoVersion = - primitive.getGenericExtension(ALTERNATE_EXT_NAME2); + splatting.getGenericExtension(ALTERNATE_EXT_NAME2); if (pSpzNoVersion != nullptr) { CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pResult = addExtensionFromJsonValue( ALTERNATE_EXT_NAME2, readGltf, splatting, - pKhrSpz); + pSpzNoVersion); primitive.extensions.erase(ALTERNATE_EXT_NAME2); return pResult; } @@ -412,6 +414,12 @@ void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { for (CesiumGltf::Mesh& mesh : model.meshes) { for (CesiumGltf::MeshPrimitive& primitive : mesh.primitives) { + // KHR_spz_gaussian_splats_compression has no KHR_gaussian_splatting + // extension attached Just throw one on there to make this easier + if (primitive.extensions.contains(ALTERNATE_EXT_NAME1)) { + primitive.addExtension(); + } + CesiumGltf::ExtensionKhrGaussianSplatting* pSplat = primitive.getExtension(); if (!pSplat) { @@ -457,4 +465,4 @@ bool hasSpzExtension(GltfReaderResult& readGltf) { return false; } -} // namespace CesiumGltfReader \ No newline at end of file +} // namespace CesiumGltfReader From dc8ce97b1d51697ab897b43d45fbafdc8e3d5fb6 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Fri, 29 Aug 2025 16:46:35 -0400 Subject: [PATCH 15/34] Conform accessor types to required values --- CesiumGltfReader/src/decodeSpz.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 5c7728285..b61b5bfb5 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -133,6 +133,10 @@ void copyShCoeff( return; } + // Some gaussion splats seem to set this value as VEC4, even though the spec + // requires VEC3. + pAccessor->type = CesiumGltf::Accessor::Type::VEC3; + pAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); CesiumGltf::BufferView& bufferView = @@ -182,6 +186,7 @@ void decodePrimitive( CesiumGltf::Accessor* pPosAccessor = findAccessor(readGltf, primitive, "POSITION"); if (pPosAccessor) { + pPosAccessor->type = CesiumGltf::Accessor::Type::VEC3; pPosAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); CesiumGltf::BufferView& bufferView = @@ -204,6 +209,7 @@ void decodePrimitive( CesiumGltf::Accessor* pRotAccessor = findAccessor(readGltf, primitive, "KHR_gaussian_splatting:ROTATION"); if (pRotAccessor) { + pRotAccessor->type = CesiumGltf::Accessor::Type::VEC4; pRotAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); CesiumGltf::BufferView& bufferView = @@ -227,6 +233,7 @@ void decodePrimitive( CesiumGltf::Accessor* pColorAccessor = findAccessor(readGltf, primitive, "COLOR_0"); if (pColorAccessor) { + pColorAccessor->type = CesiumGltf::Accessor::Type::VEC4; pColorAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); CesiumGltf::BufferView& bufferView = @@ -262,6 +269,7 @@ void decodePrimitive( CesiumGltf::Accessor* pScaleAccessor = findAccessor(readGltf, primitive, "KHR_gaussian_splatting:SCALE"); if (pScaleAccessor) { + pScaleAccessor->type = CesiumGltf::Accessor::Type::VEC3; pScaleAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); CesiumGltf::BufferView& bufferView = @@ -309,11 +317,11 @@ addExtensionFromJsonValue( CesiumGltfReader::GltfReaderResult& readGltf, CesiumGltf::ExtensionKhrGaussianSplatting& splatting, CesiumUtility::JsonValue* pKhrJson) { - if (!pKhrJson->isObject()) { readGltf.errors.push_back(fmt::format("Invalid {} extension", extName)); return nullptr; } + const CesiumUtility::JsonValue::Object::const_iterator it = pKhrJson->getObject().find("bufferView"); if (it == pKhrJson->getObject().end()) { @@ -321,6 +329,7 @@ addExtensionFromJsonValue( fmt::format("No `bufferView` property found on {} extension", extName)); return nullptr; } + if (!it->second.isInt64() && !it->second.isUint64()) { readGltf.errors.push_back(fmt::format( "`bufferView` property on {} extension must be an integer value", From 6b45940fd53d2e664fd6c7604beb099ba6f3398d Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Fri, 12 Sep 2025 09:47:03 -0400 Subject: [PATCH 16/34] Write colors directly as floats --- CesiumGltfReader/src/decodeSpz.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index b61b5bfb5..3144d4db6 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -234,6 +234,7 @@ void decodePrimitive( findAccessor(readGltf, primitive, "COLOR_0"); if (pColorAccessor) { pColorAccessor->type = CesiumGltf::Accessor::Type::VEC4; + pColorAccessor->componentType = CesiumGltf::Accessor::ComponentType::FLOAT; pColorAccessor->bufferView = static_cast(readGltf.model->bufferViews.size()); CesiumGltf::BufferView& bufferView = @@ -241,7 +242,7 @@ void decodePrimitive( bufferView.buffer = static_cast(readGltf.model->buffers.size() - 1); bufferView.byteLength = static_cast( - (pGaussian->colors.size() + pGaussian->alphas.size())); + (pGaussian->colors.size() + pGaussian->alphas.size()) * sizeof(float)); size_t start = buffer.cesium.data.size(); buffer.cesium.data.resize( @@ -253,15 +254,10 @@ void decodePrimitive( 0.5 + pGaussian->colors[i * 3 + 1] * SH_C0, 0.5 + pGaussian->colors[i * 3 + 2] * SH_C0, 1.0 / (1.0 + exp(-pGaussian->alphas[i]))); - glm::u8vec4 coloru8( - (uint8_t)(color.x * 0xff), - (uint8_t)(color.y * 0xff), - (uint8_t)(color.z * 0xff), - (uint8_t)(color.w * 0xff)); memcpy( - buffer.cesium.data.data() + start + i * sizeof(glm::u8vec4), - &coloru8, - sizeof(glm::u8vec4)); + buffer.cesium.data.data() + start + i * sizeof(glm::fvec4), + &color, + sizeof(glm::fvec4)); } } From 1ca38cd6e71e316fb728c74dca01f605b5f0b12b Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Fri, 26 Sep 2025 15:36:29 -0400 Subject: [PATCH 17/34] Change to how spherical harmonics are copied to the buffer. --- CesiumGltfReader/src/decodeSpz.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 3144d4db6..23beaaeab 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -104,22 +104,16 @@ void copyShCoeff( spz::GaussianCloud* pGaussian, int degree, int coeffIndex) { - size_t offset = 0; + size_t base = 0; + size_t stride = 0; if (degree == 1) { - offset = static_cast(coeffIndex * 3); + stride = 9; } else if (degree == 2) { - offset = static_cast(9 + coeffIndex * 3); + stride = 24; + base = 9; } else if (degree == 3) { - offset = static_cast(24 + coeffIndex * 3); - } - - size_t shTotal = 0; - if (pGaussian->shDegree == 1) { - shTotal = static_cast(3 * 3); - } else if (pGaussian->shDegree == 2) { - shTotal = static_cast(8 * 3); - } else if (pGaussian->shDegree == 3) { - shTotal = static_cast(15 * 3); + stride = 45; + base = 24; } CesiumGltf::Accessor* pAccessor = findAccessor( @@ -133,7 +127,7 @@ void copyShCoeff( return; } - // Some gaussion splats seem to set this value as VEC4, even though the spec + // Some gaussian splats seem to set this value as VEC4, even though the spec // requires VEC3. pAccessor->type = CesiumGltf::Accessor::Type::VEC3; @@ -148,10 +142,11 @@ void copyShCoeff( size_t start = buffer.cesium.data.size(); bufferView.byteOffset = static_cast(start); buffer.cesium.data.resize(start + static_cast(bufferView.byteLength)); - for (size_t i = offset; i < pGaussian->sh.size(); i += shTotal) { + for (size_t i = 0; i < static_cast(pGaussian->numPoints); i++) { + const size_t idx = i * stride + base + static_cast(coeffIndex) * 3; memcpy( buffer.cesium.data.data() + start, - pGaussian->sh.data() + i, + pGaussian->sh.data() + idx, sizeof(float) * 3); start += sizeof(float) * 3; } From 956a3820a7966b45bdc4017545195d4ba0b5f968 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 14 Oct 2025 14:50:14 -0400 Subject: [PATCH 18/34] Update CHANGES.md --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 7bfa429f3..079b36c8d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,11 @@ - Restored vcpkg commit update to `2025.09.17`. +##### Additions :tada: + +- Added support for the `KHR_gaussian_splatting` extension. + - SPZ payloads for `KHR_guassian_splatting` using the `KHR_gaussian_splatting_compression_spz_2` extension will now be decoded. + ##### Fixes :wrench: - Fixed a bug in `GoogleMapTilesRasterOverlay` that tried to parse credits from an erroneous viewport service response. From eef757a96f4ac605cc809ed504c8b85abcb4fcbc Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 14 Oct 2025 15:04:08 -0400 Subject: [PATCH 19/34] clang-tidy fixes --- CesiumGltfReader/src/decodeSpz.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 23beaaeab..44ba890a9 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -4,12 +4,14 @@ #include "CesiumGltf/MeshPrimitive.h" #include +#include #include #include +#include #include #include -#include #include +#include #include #include @@ -17,7 +19,14 @@ #include #include +#include #include +#include +#include +#include +#include +#include +#include namespace CesiumGltfReader { namespace { @@ -84,6 +93,8 @@ CesiumGltf::Accessor* findAccessor( return nullptr; } + CESIUM_ASSERT(readGltf.model); + CesiumGltf::Accessor* pAccessor = CesiumGltf::Model::getSafe( &readGltf.model->accessors, attributeIt->second); @@ -127,6 +138,8 @@ void copyShCoeff( return; } + CESIUM_ASSERT(readGltf.model); + // Some gaussian splats seem to set this value as VEC4, even though the spec // requires VEC3. pAccessor->type = CesiumGltf::Accessor::Type::VEC3; @@ -144,7 +157,7 @@ void copyShCoeff( buffer.cesium.data.resize(start + static_cast(bufferView.byteLength)); for (size_t i = 0; i < static_cast(pGaussian->numPoints); i++) { const size_t idx = i * stride + base + static_cast(coeffIndex) * 3; - memcpy( + std::memcpy( buffer.cesium.data.data() + start, pGaussian->sh.data() + idx, sizeof(float) * 3); @@ -157,7 +170,7 @@ void decodePrimitive( CesiumGltf::MeshPrimitive& primitive, CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& spz) { CESIUM_TRACE("CesiumGltfReader::decodePrimitive"); - CESIUM_ASSERT(readGltf.model.has_value()); + CESIUM_ASSERT(readGltf.model); // TODO: handle different accessor component types @@ -449,6 +462,8 @@ void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) { } bool hasSpzExtension(GltfReaderResult& readGltf) { + CESIUM_ASSERT(readGltf.model); + if (readGltf.model->isExtensionUsed( CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2:: ExtensionName)) { From d5ca2caf9fd387a75edf3424a9850bc287399c9e Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 14 Oct 2025 15:35:46 -0400 Subject: [PATCH 20/34] Fix tests --- CesiumGltfReader/src/decodeSpz.cpp | 3 ++- CesiumGltfReader/test/TestGltfReader.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 44ba890a9..65dfe696b 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -42,7 +43,7 @@ std::unique_ptr decodeBufferViewToGaussianCloud( CesiumGltf::MeshPrimitive& /* primitive */, const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& spz) { CESIUM_TRACE("CesiumGltfReader::decodeBufferViewToGaussianCloud"); - CESIUM_ASSERT(readGltf.model.has_value()); + CESIUM_ASSERT(readGltf.model); CesiumGltf::Model& model = readGltf.model.value(); CesiumGltf::BufferView* pBufferView = diff --git a/CesiumGltfReader/test/TestGltfReader.cpp b/CesiumGltfReader/test/TestGltfReader.cpp index 57ec57396..4ee352831 100644 --- a/CesiumGltfReader/test/TestGltfReader.cpp +++ b/CesiumGltfReader/test/TestGltfReader.cpp @@ -835,13 +835,15 @@ TEST_CASE("SPZ decoding works properly") { AccessorView positionView(model, attributes.at("POSITION")); REQUIRE(positionView.status() == AccessorViewStatus::Valid); REQUIRE(positionView.size() == 1); - CHECK(positionView[0] == glm::vec3(-1.0, 2.0, -3.0)); + CHECK(positionView[0] == glm::vec3(1.0, 2.0, 3.0)); REQUIRE(attributes.contains("COLOR_0")); - AccessorView colorView(model, attributes.at("COLOR_0")); + AccessorView colorView(model, attributes.at("COLOR_0")); REQUIRE(colorView.status() == AccessorViewStatus::Valid); REQUIRE(colorView.size() == 1); - CHECK(colorView[0] == glm::u8vec4(145, 164, 181, 128)); + CHECK( + colorView[0] == + glm::vec4(0.570062876, 0.643813193, 0.710188448, 0.501960814)); REQUIRE(attributes.contains("KHR_gaussian_splatting:ROTATION")); AccessorView rotationView( @@ -851,7 +853,7 @@ TEST_CASE("SPZ decoding works properly") { REQUIRE(rotationView.size() == 1); CHECK( rotationView[0] == - glm::vec4(-0.003921628, -0.709803939, -0.709804058, 0.0)); + glm::vec4(0.003921628, -0.709803939, 0.709804058, 0.0)); REQUIRE(attributes.contains("KHR_gaussian_splatting:SCALE")); AccessorView scaleView( From 557f2b2898b85d41594652633678e6d7e96ed0c1 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 14 Oct 2025 16:28:45 -0400 Subject: [PATCH 21/34] Fix clang build --- CesiumGltfReader/src/decodeSpz.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 65dfe696b..26e772f46 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -85,8 +85,8 @@ CesiumGltf::Accessor* findAccessor( GltfReaderResult& readGltf, CesiumGltf::MeshPrimitive& primitive, const std::string& attributeName) { - const std::unordered_map::const_iterator - attributeIt = primitive.attributes.find(attributeName); + const std::unordered_map::iterator attributeIt = + primitive.attributes.find(attributeName); if (attributeIt == primitive.attributes.end()) { readGltf.warnings.emplace_back( "Failed to find " + attributeName + From 5a289682836894564190e4e8897cd40bd78dd7c7 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 14 Oct 2025 16:40:08 -0400 Subject: [PATCH 22/34] Will this fix it? --- CesiumGltfReader/src/decodeSpz.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 26e772f46..581fdae88 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -85,7 +85,7 @@ CesiumGltf::Accessor* findAccessor( GltfReaderResult& readGltf, CesiumGltf::MeshPrimitive& primitive, const std::string& attributeName) { - const std::unordered_map::iterator attributeIt = + const std::unordered_map::iterator attributeIt = primitive.attributes.find(attributeName); if (attributeIt == primitive.attributes.end()) { readGltf.warnings.emplace_back( From 1cdb48a8daf12550087256045efdc8f998350000 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 14 Oct 2025 16:45:20 -0400 Subject: [PATCH 23/34] Fix include style --- CesiumGltfReader/src/decodeSpz.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CesiumGltfReader/src/decodeSpz.cpp b/CesiumGltfReader/src/decodeSpz.cpp index 581fdae88..0a8b88d0f 100644 --- a/CesiumGltfReader/src/decodeSpz.cpp +++ b/CesiumGltfReader/src/decodeSpz.cpp @@ -1,13 +1,12 @@ #include "decodeSpz.h" -#include "CesiumGltf/BufferView.h" -#include "CesiumGltf/MeshPrimitive.h" - #include #include +#include #include #include #include +#include #include #include #include From fc680205351d88bd5f7a7290c89ab940123a0876 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Fri, 17 Oct 2025 16:17:01 +1100 Subject: [PATCH 24/34] Remove explicit zlib dependency. --- CesiumGltfReader/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CesiumGltfReader/CMakeLists.txt b/CesiumGltfReader/CMakeLists.txt index 96a1d5c0b..7ed55f7e5 100644 --- a/CesiumGltfReader/CMakeLists.txt +++ b/CesiumGltfReader/CMakeLists.txt @@ -63,7 +63,6 @@ target_link_libraries(CesiumGltfReader modp_b64::modp_b64 KTX::ktx spz::spz - ZLIB::ZLIB WebP::webp WebP::webpdecoder $,libjpeg-turbo::turbojpeg,libjpeg-turbo::turbojpeg-static> ) From 33d5640416ba3a4be6eb69ecf5047d94681aa2cd Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 23 Oct 2025 20:47:46 +1100 Subject: [PATCH 25/34] Update spz overlay port. It now matches the official vcpkg one as of `2025.09.17`, plus it adds the `loadSpz.patch` patch to add an overload of loadSpz taking a raw pointer. --- extern/vcpkg/ports/spz/android-log.diff | 14 ++++++++++++++ extern/vcpkg/ports/spz/portfile.cmake | 16 +++++++++++----- extern/vcpkg/ports/spz/vcpkg.json | 6 ++---- 3 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 extern/vcpkg/ports/spz/android-log.diff diff --git a/extern/vcpkg/ports/spz/android-log.diff b/extern/vcpkg/ports/spz/android-log.diff new file mode 100644 index 000000000..588e58a84 --- /dev/null +++ b/extern/vcpkg/ports/spz/android-log.diff @@ -0,0 +1,14 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index ca49824..01f53ca 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -27,6 +27,9 @@ add_library(spz ${spz_sources}) + add_library(spz::spz ALIAS spz) + + target_link_libraries(spz PRIVATE ZLIB::ZLIB) ++if(ANDROID) ++ target_link_libraries(spz PRIVATE log) ++endif() + + target_include_directories(spz + PUBLIC $ diff --git a/extern/vcpkg/ports/spz/portfile.cmake b/extern/vcpkg/ports/spz/portfile.cmake index 60f14aeba..85d422dbd 100644 --- a/extern/vcpkg/ports/spz/portfile.cmake +++ b/extern/vcpkg/ports/spz/portfile.cmake @@ -1,20 +1,26 @@ +if(VCPKG_TARGET_IS_WINDOWS) + vcpkg_check_linkage(ONLY_STATIC_LIBRARY) +endif() + vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO nianticlabs/spz - REF "8767f22a39c32f8190b2e0f9ba256516c74e7b73" - SHA512 fb0154b8154e252d08b9751df3b66e75baf21cd4c9cec9c8de520f7cee62e86ab1d27f4d5a64f44e8bdac7b72fe465860181aa5b726c252742c6611ed91d9437 + REF v${VERSION} + SHA512 e1ee9314bd0a698e73db6d02937a20eea9419864d45eaa03e184cd9fca07dc08a92c2dfedf8e2415cbfc1ca3917435eb54ad0badd0f584aeeb2038b3bf7f000a HEAD_REF main PATCHES - loadSpz.patch + android-log.diff + loadSpz.patch ) vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" - OPTIONS - -DBUILD_SHARED_LIBS=OFF ) vcpkg_cmake_install() vcpkg_copy_pdbs() +vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/spz") + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/extern/vcpkg/ports/spz/vcpkg.json b/extern/vcpkg/ports/spz/vcpkg.json index 08c14dc61..c0adcaeb3 100644 --- a/extern/vcpkg/ports/spz/vcpkg.json +++ b/extern/vcpkg/ports/spz/vcpkg.json @@ -1,10 +1,8 @@ { "name": "spz", "version": "2.0.0", - "description": [ - "A 3D Gaussians format" - ], - "homepage": "https://github.com/nianticlabs/spz", + "description": "File format for 3D Gaussian splats.", + "homepage": "https://scaniverse.com/spz", "license": "MIT", "dependencies": [ { From 34cc5236a48bc18c71eb6c4a5cd0b1f12f3d490d Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 23 Oct 2025 20:49:26 +1100 Subject: [PATCH 26/34] A little cmake and vcpkg cleanup. --- CMakeLists.txt | 1 - cmake/config/Config.cmake.in | 1 + vcpkg.json | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 407e34a4a..c46c89fa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,7 +309,6 @@ list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}") # find_package, which resolve to our own modules that provide # targets. If needed, they can be installed with CMake config files # etc. -find_package(ZLIB REQUIRED) find_package(modp_b64 REQUIRED) find_package(ada CONFIG REQUIRED) diff --git a/cmake/config/Config.cmake.in b/cmake/config/Config.cmake.in index 8bcd37d27..b70038ea0 100644 --- a/cmake/config/Config.cmake.in +++ b/cmake/config/Config.cmake.in @@ -21,6 +21,7 @@ find_dependency(meshoptimizer CONFIG REQUIRED) find_dependency(OpenSSL REQUIRED) find_dependency(s2 CONFIG REQUIRED) find_dependency(spdlog CONFIG REQUIRED) +find_dependency(spz CONFIG REQUIRED) find_dependency(tinyxml2 CONFIG REQUIRED) find_dependency(unofficial-sqlite3 CONFIG REQUIRED) find_dependency(WebP CONFIG REQUIRED) diff --git a/vcpkg.json b/vcpkg.json index 891f3f34a..e590cda2d 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -41,7 +41,8 @@ "name": "asmjit", "platform": "!ios" }, - "spz" + "spz", + "zlib" ] } From 8df7a1f98df11ee6b36e7e291d34897323cf9f8a Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Tue, 28 Oct 2025 14:45:10 +1100 Subject: [PATCH 27/34] Update spz to v2.1.0. This overlay port comes directly from this PR into vcpkg: https://github.com/microsoft/vcpkg/pull/47983 --- extern/vcpkg/ports/spz/android-log.diff | 14 ------------ extern/vcpkg/ports/spz/loadSpz.patch | 29 ------------------------- extern/vcpkg/ports/spz/portfile.cmake | 7 +++--- extern/vcpkg/ports/spz/vcpkg.json | 2 +- 4 files changed, 4 insertions(+), 48 deletions(-) delete mode 100644 extern/vcpkg/ports/spz/android-log.diff delete mode 100644 extern/vcpkg/ports/spz/loadSpz.patch diff --git a/extern/vcpkg/ports/spz/android-log.diff b/extern/vcpkg/ports/spz/android-log.diff deleted file mode 100644 index 588e58a84..000000000 --- a/extern/vcpkg/ports/spz/android-log.diff +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index ca49824..01f53ca 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -27,6 +27,9 @@ add_library(spz ${spz_sources}) - add_library(spz::spz ALIAS spz) - - target_link_libraries(spz PRIVATE ZLIB::ZLIB) -+if(ANDROID) -+ target_link_libraries(spz PRIVATE log) -+endif() - - target_include_directories(spz - PUBLIC $ diff --git a/extern/vcpkg/ports/spz/loadSpz.patch b/extern/vcpkg/ports/spz/loadSpz.patch deleted file mode 100644 index 631336073..000000000 --- a/extern/vcpkg/ports/spz/loadSpz.patch +++ /dev/null @@ -1,29 +0,0 @@ -diff --git a/src/cc/load-spz.cc b/src/cc/load-spz.cc -index e028445..7388d56 100644 ---- a/src/cc/load-spz.cc -+++ b/src/cc/load-spz.cc -@@ -635,6 +635,10 @@ GaussianCloud loadSpz(const std::vector &data, const UnpackOptions &o) - return unpackGaussians(loadSpzPacked(data), o); - } - -+GaussianCloud loadSpz(const uint8_t *data, int32_t size, const UnpackOptions &o) { -+ return unpackGaussians(loadSpzPacked(data, size), o); -+} -+ - bool saveSpz(const GaussianCloud &g, const PackOptions &o, const std::string &filename) { - std::vector data; - if (!saveSpz(g, o, &data)) { -diff --git a/src/cc/load-spz.h b/src/cc/load-spz.h -index a624f45..a10e696 100644 ---- a/src/cc/load-spz.h -+++ b/src/cc/load-spz.h -@@ -73,6 +73,9 @@ bool saveSpz( - // Loads Gaussian splat from a vector of bytes in packed format. - GaussianCloud loadSpz(const std::vector &data, const UnpackOptions &options); - -+// Loads Gaussian splat from a byte pointer in packed format. -+GaussianCloud loadSpz(const uint8_t *data, int32_t size, const UnpackOptions &options); -+ - // Loads Gaussian splat from a vector of bytes in packed format. - PackedGaussians loadSpzPacked(const std::string &filename); - PackedGaussians loadSpzPacked(const uint8_t *data, int32_t size); diff --git a/extern/vcpkg/ports/spz/portfile.cmake b/extern/vcpkg/ports/spz/portfile.cmake index 85d422dbd..7824629a1 100644 --- a/extern/vcpkg/ports/spz/portfile.cmake +++ b/extern/vcpkg/ports/spz/portfile.cmake @@ -6,15 +6,14 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO nianticlabs/spz REF v${VERSION} - SHA512 e1ee9314bd0a698e73db6d02937a20eea9419864d45eaa03e184cd9fca07dc08a92c2dfedf8e2415cbfc1ca3917435eb54ad0badd0f584aeeb2038b3bf7f000a + SHA512 0e6bd1dd3f8625cc6730c0cc3a53f65a414a0504c463ca108ac972e4f09e949c49fd98d1033e27947080ead573695747c2a0b9c1a3d8aac7a39351abeb70bfc6 HEAD_REF main - PATCHES - android-log.diff - loadSpz.patch ) vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -DCMAKE_CXX_STANDARD=17 ) vcpkg_cmake_install() diff --git a/extern/vcpkg/ports/spz/vcpkg.json b/extern/vcpkg/ports/spz/vcpkg.json index c0adcaeb3..148bae6b6 100644 --- a/extern/vcpkg/ports/spz/vcpkg.json +++ b/extern/vcpkg/ports/spz/vcpkg.json @@ -1,6 +1,6 @@ { "name": "spz", - "version": "2.0.0", + "version": "2.1.0", "description": "File format for 3D Gaussian splats.", "homepage": "https://scaniverse.com/spz", "license": "MIT", From b948b9cbfdb68c21cbd32c239fad11be86b60bc8 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Tue, 28 Oct 2025 17:57:49 +1100 Subject: [PATCH 28/34] Update spz overlay with latest from PR. --- .../ports/spz/optional-build-tools.patch | 20 +++++++++++++++ extern/vcpkg/ports/spz/portfile.cmake | 25 ++++++++++++++++++- extern/vcpkg/ports/spz/vcpkg.json | 7 +++++- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 extern/vcpkg/ports/spz/optional-build-tools.patch diff --git a/extern/vcpkg/ports/spz/optional-build-tools.patch b/extern/vcpkg/ports/spz/optional-build-tools.patch new file mode 100644 index 000000000..8f157a43a --- /dev/null +++ b/extern/vcpkg/ports/spz/optional-build-tools.patch @@ -0,0 +1,20 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 876e29f..4fd6aa9 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -78,6 +78,7 @@ install(EXPORT spzTargets + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/spz" + ) + ++if(BUILD_TOOLS) + # CLI Tools + add_executable(ply_to_spz cli_tools/src/ply_to_spz.cpp) + target_link_libraries(ply_to_spz PRIVATE spz) +@@ -94,6 +95,7 @@ target_include_directories(spz_info PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) + install(TARGETS ply_to_spz spz_to_ply spz_info + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) ++endif() + + # --- Python Bindings Option --- + option(BUILD_PYTHON_BINDINGS "Build Python bindings using nanobind" OFF) diff --git a/extern/vcpkg/ports/spz/portfile.cmake b/extern/vcpkg/ports/spz/portfile.cmake index 7824629a1..3f8dec413 100644 --- a/extern/vcpkg/ports/spz/portfile.cmake +++ b/extern/vcpkg/ports/spz/portfile.cmake @@ -8,15 +8,38 @@ vcpkg_from_github( REF v${VERSION} SHA512 0e6bd1dd3f8625cc6730c0cc3a53f65a414a0504c463ca108ac972e4f09e949c49fd98d1033e27947080ead573695747c2a0b9c1a3d8aac7a39351abeb70bfc6 HEAD_REF main + PATCHES + "optional-build-tools.patch" ) +vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS + FEATURES + tools BUILD_TOOLS +) + +if(tools IN_LIST FEATURES) + # Tools targets are missing C++17 flag + list(APPEND FEATURE_OPTIONS "-DCMAKE_CXX_STANDARD=17") +endif() + vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" OPTIONS - -DCMAKE_CXX_STANDARD=17 + ${FEATURE_OPTIONS} ) vcpkg_cmake_install() + +if(tools IN_LIST FEATURES) + vcpkg_copy_tools( + TOOL_NAMES + ply_to_spz + spz_to_ply + spz_info + AUTO_CLEAN + ) +endif() + vcpkg_copy_pdbs() vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/spz") diff --git a/extern/vcpkg/ports/spz/vcpkg.json b/extern/vcpkg/ports/spz/vcpkg.json index 148bae6b6..b46ed45da 100644 --- a/extern/vcpkg/ports/spz/vcpkg.json +++ b/extern/vcpkg/ports/spz/vcpkg.json @@ -14,5 +14,10 @@ "host": true }, "zlib" - ] + ], + "features": { + "tools": { + "description": "Build tools" + } + } } From 30cc96901b422a6f5bd885a174d95da2160689b8 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 28 Oct 2025 17:44:40 -0400 Subject: [PATCH 29/34] Remove spz overlay port, draft-splat-spz branch of gltf --- .../ports/spz/optional-build-tools.patch | 20 -------- extern/vcpkg/ports/spz/portfile.cmake | 48 ------------------- extern/vcpkg/ports/spz/vcpkg.json | 23 --------- tools/generate-classes/package.json | 2 +- 4 files changed, 1 insertion(+), 92 deletions(-) delete mode 100644 extern/vcpkg/ports/spz/optional-build-tools.patch delete mode 100644 extern/vcpkg/ports/spz/portfile.cmake delete mode 100644 extern/vcpkg/ports/spz/vcpkg.json diff --git a/extern/vcpkg/ports/spz/optional-build-tools.patch b/extern/vcpkg/ports/spz/optional-build-tools.patch deleted file mode 100644 index 8f157a43a..000000000 --- a/extern/vcpkg/ports/spz/optional-build-tools.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 876e29f..4fd6aa9 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -78,6 +78,7 @@ install(EXPORT spzTargets - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/spz" - ) - -+if(BUILD_TOOLS) - # CLI Tools - add_executable(ply_to_spz cli_tools/src/ply_to_spz.cpp) - target_link_libraries(ply_to_spz PRIVATE spz) -@@ -94,6 +95,7 @@ target_include_directories(spz_info PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) - install(TARGETS ply_to_spz spz_to_ply spz_info - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - ) -+endif() - - # --- Python Bindings Option --- - option(BUILD_PYTHON_BINDINGS "Build Python bindings using nanobind" OFF) diff --git a/extern/vcpkg/ports/spz/portfile.cmake b/extern/vcpkg/ports/spz/portfile.cmake deleted file mode 100644 index 3f8dec413..000000000 --- a/extern/vcpkg/ports/spz/portfile.cmake +++ /dev/null @@ -1,48 +0,0 @@ -if(VCPKG_TARGET_IS_WINDOWS) - vcpkg_check_linkage(ONLY_STATIC_LIBRARY) -endif() - -vcpkg_from_github( - OUT_SOURCE_PATH SOURCE_PATH - REPO nianticlabs/spz - REF v${VERSION} - SHA512 0e6bd1dd3f8625cc6730c0cc3a53f65a414a0504c463ca108ac972e4f09e949c49fd98d1033e27947080ead573695747c2a0b9c1a3d8aac7a39351abeb70bfc6 - HEAD_REF main - PATCHES - "optional-build-tools.patch" -) - -vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS - FEATURES - tools BUILD_TOOLS -) - -if(tools IN_LIST FEATURES) - # Tools targets are missing C++17 flag - list(APPEND FEATURE_OPTIONS "-DCMAKE_CXX_STANDARD=17") -endif() - -vcpkg_cmake_configure( - SOURCE_PATH "${SOURCE_PATH}" - OPTIONS - ${FEATURE_OPTIONS} -) - -vcpkg_cmake_install() - -if(tools IN_LIST FEATURES) - vcpkg_copy_tools( - TOOL_NAMES - ply_to_spz - spz_to_ply - spz_info - AUTO_CLEAN - ) -endif() - -vcpkg_copy_pdbs() -vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/spz") - -file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") - -vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/extern/vcpkg/ports/spz/vcpkg.json b/extern/vcpkg/ports/spz/vcpkg.json deleted file mode 100644 index b46ed45da..000000000 --- a/extern/vcpkg/ports/spz/vcpkg.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "spz", - "version": "2.1.0", - "description": "File format for 3D Gaussian splats.", - "homepage": "https://scaniverse.com/spz", - "license": "MIT", - "dependencies": [ - { - "name": "vcpkg-cmake", - "host": true - }, - { - "name": "vcpkg-cmake-config", - "host": true - }, - "zlib" - ], - "features": { - "tools": { - "description": "Build tools" - } - } -} diff --git a/tools/generate-classes/package.json b/tools/generate-classes/package.json index 07e53fe87..8bbe67b24 100644 --- a/tools/generate-classes/package.json +++ b/tools/generate-classes/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "generate-3d-tiles": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/tileset.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/common/rootProperty.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/PropertyTable/propertyTable.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Subtree/subtree.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Schema/schema.schema.json https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/specification/schema/Statistics/statistics.schema.json --output ../../Cesium3DTiles --readerOutput ../../Cesium3DTilesReader --writerOutput ../../Cesium3DTilesWriter --extensions https://raw.githubusercontent.com/CesiumGS/3d-tiles/cesium-native/extensions/ --namespace Cesium3DTiles --readerNamespace Cesium3DTilesReader --writerNamespace Cesium3DTilesWriter --config 3dTiles.json", - "generate-gltf": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/specification/2.0/schema/glTF.schema.json --output ../../CesiumGltf --readerOutput ../../CesiumGltfReader --writerOutput ../../CesiumGltfWriter --extensions https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/extensions/2.0/ https://raw.githubusercontent.com/CesiumGS/glTF/draft-splat-spz/extensions/2.0/ --namespace CesiumGltf --readerNamespace CesiumGltfReader --writerNamespace CesiumGltfWriter --config glTF.json", + "generate-gltf": "node index.js --schemas https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/specification/2.0/schema/glTF.schema.json --output ../../CesiumGltf --readerOutput ../../CesiumGltfReader --writerOutput ../../CesiumGltfWriter --extensions https://raw.githubusercontent.com/CesiumGS/glTF/cesium-native/extensions/2.0/ --namespace CesiumGltf --readerNamespace CesiumGltfReader --writerNamespace CesiumGltfWriter --config glTF.json", "generate-quantized-mesh-terrain": "node index.js --schemas ../../CesiumQuantizedMeshTerrain/schema/layer.schema.json --output ../../CesiumQuantizedMeshTerrain --readerOutput ../../CesiumQuantizedMeshTerrain --writerOutput ../../CesiumQuantizedMeshTerrain --extensions ../../CesiumQuantizedMeshTerrain/schema/extensions --namespace CesiumQuantizedMeshTerrain --readerNamespace CesiumQuantizedMeshTerrain --writerNamespace CesiumQuantizedMeshTerrain --config QuantizedMeshTerrain.json" }, "author": "CesiumGS, Inc. and Contributors", From d3b0ccbeaa99944a843ad9599f831a12d0890f5d Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 28 Oct 2025 18:12:00 -0400 Subject: [PATCH 30/34] Regenerate gltf --- .../ExtensionKhrGaussianSplatting.h | 94 ++++++++++--- ...ExtensionKhrGaussianSplattingJsonHandler.h | 8 +- .../generated/src/GeneratedJsonHandlers.cpp | 130 ++---------------- .../generated/src/ModelJsonWriter.cpp | 59 +++----- .../generated/src/ModelJsonWriter.h | 10 -- tools/generate-classes/makeIdentifier.js | 2 +- 6 files changed, 116 insertions(+), 187 deletions(-) diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h index 4dcd7a3be..aab5ec892 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionKhrGaussianSplatting.h @@ -2,16 +2,14 @@ // DO NOT EDIT THIS FILE! #pragma once -#include #include #include -#include #include namespace CesiumGltf { /** - * @brief Data for a 3D Gaussian Splat primitive. + * @brief Data defining a 3D Gaussian Splat primitive. */ struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final : public CesiumUtility::ExtensibleObject { @@ -24,17 +22,86 @@ struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final static constexpr const char* ExtensionName = "KHR_gaussian_splatting"; /** - * @brief The shape of the Gaussian to render. Gaussians may be available in - * different shapes, so this is a freeform field that defaults to ellipsoid. - * See the extension specification for futher known types. + * @brief Known values for Optional property specifying how to project the + * Gaussians to achieve a perspective correct value. This property defaults to + * perspective. */ - std::string shape = "ellipsoid"; + struct Projection { + /** @brief `perspective` */ + inline static const std::string perspective = "perspective"; + + /** @brief `orthographic` */ + inline static const std::string orthographic = "orthographic"; + }; + + /** + * @brief Known values for Optional property specifying how to sort the + * Gaussians during rendering. This property defaults to cameraDistance. + */ + struct SortingMethod { + /** @brief `cameraDistance` */ + inline static const std::string cameraDistance = "cameraDistance"; + + /** @brief `zDepth` */ + inline static const std::string zDepth = "zDepth"; + }; + + /** + * @brief Known values for Optional property specifying the color space of the + * spherical harmonics. This property defaults to BT.709. + */ + struct ColorSpace { + /** @brief `BT.709` */ + inline static const std::string BT_709 = "BT.709"; + + /** @brief `BT.2020-ITU` */ + inline static const std::string BT_2020_ITU = "BT.2020-ITU"; + + /** @brief `BT.2020-HLG` */ + inline static const std::string BT_2020_HLG = "BT.2020-HLG"; + + /** @brief `BT.2020-PQ` */ + inline static const std::string BT_2020_PQ = "BT.2020-PQ"; + + /** @brief `Display-P3` */ + inline static const std::string Display_P3 = "Display-P3"; + + /** @brief `linear` */ + inline static const std::string linear = "linear"; + }; + + /** + * @brief Optional property specifying parameters regarding the kernel used to + * generate the Gaussians. This property defaults to ellipse. + */ + std::string kernel = "ellipse"; + + /** + * @brief Optional property specifying how to project the Gaussians to achieve + * a perspective correct value. This property defaults to perspective. + * + * Known values are defined in {@link Projection}. + * + */ + std::string projection = Projection::perspective; + + /** + * @brief Optional property specifying how to sort the Gaussians during + * rendering. This property defaults to cameraDistance. + * + * Known values are defined in {@link SortingMethod}. + * + */ + std::string sortingMethod = SortingMethod::cameraDistance; /** - * @brief Optional rendering hints for rendering the 3D Gaussian splats. - * Renderers are free to ignore any of these. + * @brief Optional property specifying the color space of the spherical + * harmonics. This property defaults to BT.709. + * + * Known values are defined in {@link ColorSpace}. + * */ - std::optional hints; + std::string colorSpace = ColorSpace::BT_709; /** * @brief Calculates the size in bytes of this object, including the contents @@ -47,12 +114,7 @@ struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final accum += int64_t(sizeof(ExtensionKhrGaussianSplatting)); accum += CesiumUtility::ExtensibleObject::getSizeBytes() - int64_t(sizeof(CesiumUtility::ExtensibleObject)); - accum += int64_t(this->shape.capacity() * sizeof(char)); - if (this->hints) { - accum += - this->hints->getSizeBytes() - - int64_t(sizeof(CesiumGltf::ExtensionKhrGaussianSplattingHintsValue)); - } + accum += int64_t(this->kernel.capacity() * sizeof(char)); return accum; } }; diff --git a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h index 11521f836..ec984a0ce 100644 --- a/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionKhrGaussianSplattingJsonHandler.h @@ -2,8 +2,6 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "ExtensionKhrGaussianSplattingHintsValueJsonHandler.h" - #include #include #include @@ -44,7 +42,9 @@ class ExtensionKhrGaussianSplattingJsonHandler private: CesiumGltf::ExtensionKhrGaussianSplatting* _pObject = nullptr; - CesiumJsonReader::StringJsonHandler _shape; - ExtensionKhrGaussianSplattingHintsValueJsonHandler _hints; + CesiumJsonReader::StringJsonHandler _kernel; + CesiumJsonReader::StringJsonHandler _projection; + CesiumJsonReader::StringJsonHandler _sortingMethod; + CesiumJsonReader::StringJsonHandler _colorSpace; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp index b081bde00..1cef212aa 100644 --- a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp +++ b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp @@ -3006,8 +3006,10 @@ ExtensionKhrGaussianSplattingJsonHandler:: ExtensionKhrGaussianSplattingJsonHandler( const CesiumJsonReader::JsonReaderOptions& options) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(options), - _shape(), - _hints(options) {} + _kernel(), + _projection(), + _sortingMethod(), + _colorSpace() {} void ExtensionKhrGaussianSplattingJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, @@ -3046,11 +3048,17 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrGaussianSplattingJsonHandler:: CesiumGltf::ExtensionKhrGaussianSplatting& o) { using namespace std::string_literals; - if ("shape"s == str) { - return property("shape", this->_shape, o.shape); + if ("kernel"s == str) { + return property("kernel", this->_kernel, o.kernel); + } + if ("projection"s == str) { + return property("projection", this->_projection, o.projection); + } + if ("sortingMethod"s == str) { + return property("sortingMethod", this->_sortingMethod, o.sortingMethod); } - if ("hints"s == str) { - return property("hints", this->_hints, o.hints); + if ("colorSpace"s == str) { + return property("colorSpace", this->_colorSpace, o.colorSpace); } return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); @@ -3220,116 +3228,6 @@ ExtensionKhrGaussianSplattingCompressionSpz2Reader::readArrayFromJson( return CesiumJsonReader::JsonReader::readJson(value, handler); } -} // namespace CesiumGltfReader -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -// NOLINTBEGIN(readability-duplicate-include) -#include "ExtensionKhrGaussianSplattingHintsValueJsonHandler.h" -#include "registerReaderExtensions.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -// NOLINTEND(readability-duplicate-include) - -namespace CesiumGltfReader { - -ExtensionKhrGaussianSplattingHintsValueJsonHandler:: - ExtensionKhrGaussianSplattingHintsValueJsonHandler( - const CesiumJsonReader::JsonReaderOptions& options) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(options), - _projection(), - _sortingMethod() {} - -void ExtensionKhrGaussianSplattingHintsValueJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionKhrGaussianSplattingHintsValue* pObject) { - CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); - this->_pObject = pObject; -} - -CesiumJsonReader::IJsonHandler* -ExtensionKhrGaussianSplattingHintsValueJsonHandler::readObjectKey( - const std::string_view& str) { - CESIUM_ASSERT(this->_pObject); - return this->readObjectKeyExtensionKhrGaussianSplattingHintsValue( - CesiumGltf::ExtensionKhrGaussianSplattingHintsValue::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionKhrGaussianSplattingHintsValueJsonHandler:: - readObjectKeyExtensionKhrGaussianSplattingHintsValue( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& o) { - using namespace std::string_literals; - - if ("projection"s == str) { - return property("projection", this->_projection, o.projection); - } - if ("sortingMethod"s == str) { - return property("sortingMethod", this->_sortingMethod, o.sortingMethod); - } - - return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); -} - -ExtensionKhrGaussianSplattingHintsValueReader:: - ExtensionKhrGaussianSplattingHintsValueReader() { - registerReaderExtensions(this->_options); -} - -CesiumJsonReader::JsonReaderOptions& -ExtensionKhrGaussianSplattingHintsValueReader::getOptions() { - return this->_options; -} - -const CesiumJsonReader::JsonReaderOptions& -ExtensionKhrGaussianSplattingHintsValueReader::getOptions() const { - return this->_options; -} - -CesiumJsonReader::ReadJsonResult< - CesiumGltf::ExtensionKhrGaussianSplattingHintsValue> -ExtensionKhrGaussianSplattingHintsValueReader::readFromJson( - const std::span& data) const { - ExtensionKhrGaussianSplattingHintsValueJsonHandler handler(this->_options); - return CesiumJsonReader::JsonReader::readJson(data, handler); -} - -CesiumJsonReader::ReadJsonResult< - CesiumGltf::ExtensionKhrGaussianSplattingHintsValue> -ExtensionKhrGaussianSplattingHintsValueReader::readFromJson( - const rapidjson::Value& value) const { - ExtensionKhrGaussianSplattingHintsValueJsonHandler handler(this->_options); - return CesiumJsonReader::JsonReader::readJson(value, handler); -} - -CesiumJsonReader::ReadJsonResult< - std::vector> -ExtensionKhrGaussianSplattingHintsValueReader::readArrayFromJson( - const rapidjson::Value& value) const { - CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::ExtensionKhrGaussianSplattingHintsValue, - ExtensionKhrGaussianSplattingHintsValueJsonHandler> - handler(this->_options); - return CesiumJsonReader::JsonReader::readJson(value, handler); -} - } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp index 360eadd4d..0252fafa3 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -231,11 +230,6 @@ void writeJson( CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); -void writeJson( - const CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& obj, - CesiumJsonWriter::JsonWriter& jsonWriter, - const CesiumJsonWriter::ExtensionWriterContext& context); - void writeJson( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, @@ -1198,14 +1192,27 @@ void writeJson( const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); - if (obj.shape != "ellipsoid") { - jsonWriter.Key("shape"); - writeJson(obj.shape, jsonWriter, context); + if (obj.kernel != "ellipse") { + jsonWriter.Key("kernel"); + writeJson(obj.kernel, jsonWriter, context); } - if (obj.hints) { - jsonWriter.Key("hints"); - writeJson(obj.hints, jsonWriter, context); + if (obj.projection != + CesiumGltf::ExtensionKhrGaussianSplatting::Projection::perspective) { + jsonWriter.Key("projection"); + writeJson(obj.projection, jsonWriter, context); + } + + if (obj.sortingMethod != CesiumGltf::ExtensionKhrGaussianSplatting:: + SortingMethod::cameraDistance) { + jsonWriter.Key("sortingMethod"); + writeJson(obj.sortingMethod, jsonWriter, context); + } + + if (obj.colorSpace != + CesiumGltf::ExtensionKhrGaussianSplatting::ColorSpace::BT_709) { + jsonWriter.Key("colorSpace"); + writeJson(obj.colorSpace, jsonWriter, context); } writeExtensibleObject(obj, jsonWriter, context); @@ -1229,27 +1236,6 @@ void writeJson( jsonWriter.EndObject(); } -void writeJson( - const CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& obj, - CesiumJsonWriter::JsonWriter& jsonWriter, - const CesiumJsonWriter::ExtensionWriterContext& context) { - jsonWriter.StartObject(); - - if (obj.projection != "perspective") { - jsonWriter.Key("projection"); - writeJson(obj.projection, jsonWriter, context); - } - - if (obj.sortingMethod != "cameraDistance") { - jsonWriter.Key("sortingMethod"); - writeJson(obj.sortingMethod, jsonWriter, context); - } - - writeExtensibleObject(obj, jsonWriter, context); - - jsonWriter.EndObject(); -} - void writeJson( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, @@ -2982,13 +2968,6 @@ void ExtensionKhrGaussianSplattingCompressionSpz2JsonWriter::write( writeJson(obj, jsonWriter, context); } -void ExtensionKhrGaussianSplattingHintsValueJsonWriter::write( - const CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& obj, - CesiumJsonWriter::JsonWriter& jsonWriter, - const CesiumJsonWriter::ExtensionWriterContext& context) { - writeJson(obj, jsonWriter, context); -} - void PaddingJsonWriter::write( const CesiumGltf::Padding& obj, CesiumJsonWriter::JsonWriter& jsonWriter, diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.h b/CesiumGltfWriter/generated/src/ModelJsonWriter.h index 3f15785e0..3ec02c82f 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.h +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.h @@ -36,7 +36,6 @@ struct ExtensionExtImplicitCylinderRegion; struct ExtensionExtPrimitiveVoxels; struct ExtensionKhrGaussianSplatting; struct ExtensionKhrGaussianSplattingCompressionSpz2; -struct ExtensionKhrGaussianSplattingHintsValue; struct Padding; struct Shape; struct Cylinder; @@ -432,15 +431,6 @@ struct ExtensionKhrGaussianSplattingCompressionSpz2JsonWriter { const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionKhrGaussianSplattingHintsValueJsonWriter { - using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingHintsValue; - - static void write( - const CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& obj, - CesiumJsonWriter::JsonWriter& jsonWriter, - const CesiumJsonWriter::ExtensionWriterContext& context); -}; - struct PaddingJsonWriter { using ValueType = CesiumGltf::Padding; diff --git a/tools/generate-classes/makeIdentifier.js b/tools/generate-classes/makeIdentifier.js index c00988dbc..d468f3e0d 100644 --- a/tools/generate-classes/makeIdentifier.js +++ b/tools/generate-classes/makeIdentifier.js @@ -1,5 +1,5 @@ function makeIdentifier(s) { - return s.replace(/\//g, "_"); + return s.replace(/[\/\.-]/g, "_"); } module.exports = makeIdentifier; From 90a24654f768defa7bc7006ef5ac3efbd30600b0 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Wed, 29 Oct 2025 17:45:56 -0400 Subject: [PATCH 31/34] Update vcpkg commit --- CMakeLists.txt | 2 +- vcpkg-configuration.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c46c89fa8..a9847b581 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ if(CESIUM_USE_EZVCPKG) list(APPEND PACKAGES_ALL ${PACKAGES_TEST}) ezvcpkg_fetch( - COMMIT 2025.09.17 + COMMIT b8e63019c668742cefe81a6212ee91ffef4f1c71 PACKAGES ${PACKAGES_ALL} # Clean the build trees after building, so that we don't use a ton a disk space on the CI cache CLEAN_BUILDTREES diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index c933accb9..42e4a3269 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -1,7 +1,7 @@ { "default-registry": { "kind": "git", - "baseline": "4334d8b4c8916018600212ab4dd4bbdc343065d1", + "baseline": "b8e63019c668742cefe81a6212ee91ffef4f1c71", "repository": "https://github.com/microsoft/vcpkg" }, "registries": [ From 7734cff91c264084352bff00503e2f3c5808d3e8 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 30 Oct 2025 10:24:28 -0400 Subject: [PATCH 32/34] More recent vcpkg commit for cmake fix --- CMakeLists.txt | 2 +- vcpkg-configuration.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9847b581..df678dd41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ if(CESIUM_USE_EZVCPKG) list(APPEND PACKAGES_ALL ${PACKAGES_TEST}) ezvcpkg_fetch( - COMMIT b8e63019c668742cefe81a6212ee91ffef4f1c71 + COMMIT d80785c4ee1df22a4119a3451452f59e978e06aa PACKAGES ${PACKAGES_ALL} # Clean the build trees after building, so that we don't use a ton a disk space on the CI cache CLEAN_BUILDTREES diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index 42e4a3269..bc70841f1 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -1,7 +1,7 @@ { "default-registry": { "kind": "git", - "baseline": "b8e63019c668742cefe81a6212ee91ffef4f1c71", + "baseline": "d80785c4ee1df22a4119a3451452f59e978e06aa", "repository": "https://github.com/microsoft/vcpkg" }, "registries": [ From 54c22fddb5e4e65b33b7fcfff4a902de7d2cc8e6 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 30 Oct 2025 13:47:19 -0400 Subject: [PATCH 33/34] Add include to fix glm issue --- CesiumGltf/src/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/CesiumGltf/src/Model.cpp b/CesiumGltf/src/Model.cpp index d65bdd6a3..226643623 100644 --- a/CesiumGltf/src/Model.cpp +++ b/CesiumGltf/src/Model.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include From 097ca8c26ace7012f62565b9c8f6a278eb0f5dd1 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 30 Oct 2025 14:34:57 -0400 Subject: [PATCH 34/34] Tell clang-tidy to not worry about it --- CesiumGltf/src/Model.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CesiumGltf/src/Model.cpp b/CesiumGltf/src/Model.cpp index 226643623..41586a9c3 100644 --- a/CesiumGltf/src/Model.cpp +++ b/CesiumGltf/src/Model.cpp @@ -44,8 +44,11 @@ #include #include #include -#include #include +// Despite what clang-tidy will say, we *do* actually need this include or we'll +// get a "missing mat4_cast" error. +// NOLINTNEXTLINE +#include #include #include