Skip to content
Open
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
8e95f36
spz draft extension
keyboardspecialist Apr 17, 2025
8aab85b
Update extensions/2.0/Khronos/KHR_spz_compression/README.md
keyboardspecialist Apr 18, 2025
0f98cc3
Update extensions/2.0/Khronos/KHR_spz_compression/README.md
keyboardspecialist Apr 18, 2025
c4e5be0
update name
keyboardspecialist Apr 18, 2025
a34025a
renamed extension, lots of tweaks and changes, now written as a singl…
keyboardspecialist Apr 18, 2025
35c6a85
update names
keyboardspecialist Apr 18, 2025
1120b9a
Rendering from texture notes
keyboardspecialist Apr 18, 2025
20cc20d
wording
keyboardspecialist Apr 18, 2025
e89a034
Added conformance requirements around coordinate system
weegeekps Apr 21, 2025
3519e2e
Changing the form of the implementation section to be less possessive.
weegeekps Apr 21, 2025
7c5d3fb
Update extensions/2.0/Khronos/KHR_spz_gaussian_splats_compression/REA…
weegeekps Apr 21, 2025
3ce3e6a
Update extensions/2.0/Khronos/KHR_spz_gaussian_splats_compression/REA…
weegeekps Apr 21, 2025
d7e27f5
Update extensions/2.0/Khronos/KHR_spz_gaussian_splats_compression/REA…
weegeekps Apr 21, 2025
6f80242
Update extensions/2.0/Khronos/KHR_spz_gaussian_splats_compression/REA…
weegeekps Apr 21, 2025
b2d2a86
Added note that _ROTATION is a quaternion.
weegeekps Apr 21, 2025
5295b43
Corrected color attribute description and component type
keyboardspecialist Apr 21, 2025
25f9471
Schema updates
weegeekps May 15, 2025
12c06cd
Updated extension name in schema
weegeekps May 15, 2025
8659840
Made some fields required.
weegeekps May 15, 2025
4135515
SPZ handles versioning itself.
weegeekps May 15, 2025
91a3982
Fixing a small spec error
weegeekps May 15, 2025
1d65ecc
Fixing some glTF spec violations
weegeekps May 15, 2025
d634926
Fix spherical harmonic type
weegeekps May 16, 2025
23d3a14
Fix number of points statement
weegeekps May 16, 2025
cabf099
Clarification around accessors
weegeekps May 16, 2025
aee76a1
Updated authors
weegeekps May 20, 2025
625f2b8
Allow for non-SPZ encoded vertex attributes
Ronald909 Jun 26, 2025
01799af
Merge pull request #85 from Ronald909/ronald909/draft-splat-spz-featu…
weegeekps Jun 30, 2025
068b74f
First pass at splitting 3DGS+SPZ into two extensions
weegeekps Jul 1, 2025
1ad0d78
Updated contributors.
weegeekps Jul 8, 2025
3e89c2d
Simplified inheritance language in the SPZ compression extension
weegeekps Jul 9, 2025
9dac310
Added a small clarification regarding quaternion order
weegeekps Jul 22, 2025
fa056f0
Renamed the SPZ compression extension
weegeekps Jul 25, 2025
03f1934
Updates to the SPZ extension.
weegeekps Jul 25, 2025
df36989
Updated base 3DGS extension with feedback
weegeekps Jul 25, 2025
1f641c2
Added shape and rendering hints to base 3DGS spec
weegeekps Jul 25, 2025
81e73f1
Fixed a spot where I forgot to namespace the custom attributes
weegeekps Jul 31, 2025
e5f8ce1
Added explicit marking of the version for the SPZ library
weegeekps Aug 22, 2025
9968e7b
Allowed normalized byte and short component types for rotation and scale
weegeekps Sep 10, 2025
129ff4a
Changed shape to kernel, and hoisted hints up the tree
weegeekps Sep 10, 2025
8d08f38
Updated contributors based on feedback
weegeekps Sep 10, 2025
3223c8d
Updated spherical harmonics component types for quantization
weegeekps Sep 10, 2025
b97f0af
Dropped the unsigned component types
weegeekps Sep 10, 2025
78565f8
Fixed kernel definition in the schema
weegeekps Sep 11, 2025
06d2146
Added cut-off distance clarification to ellipse kernel
weegeekps Sep 12, 2025
335f534
Split out the SPZ extension into it's own PR
weegeekps Sep 29, 2025
6b46605
Removed the implementation section
weegeekps Oct 3, 2025
5493a4d
Added the INRIA 3D Gaussian Splatting paper to resources
weegeekps Oct 3, 2025
e49661c
Added a property to provide a color space hint.
weegeekps Oct 8, 2025
613ac75
Changed rendering hints to be backed by enum instead of free-form fields
weegeekps Oct 8, 2025
4a6b4cc
Clarified that unsupported color spaces should be clamped to sRGB
weegeekps Oct 8, 2025
b13feb8
Remove linear color space.
weegeekps Oct 8, 2025
f1fc90b
Fixed extensibility of the perspective and sorting hints
weegeekps Oct 9, 2025
d04aaf6
Fixing how the enums are defined.
weegeekps Oct 9, 2025
4c81a59
Updated to JSON Schema 2020-12
weegeekps Oct 10, 2025
63e45d3
Oops. Fixed schema by providing the metaschema.
weegeekps Oct 10, 2025
ed7f13b
Made changes based on the color space decision made on WG call
weegeekps Oct 23, 2025
660f576
Adjusted the color spaces.
weegeekps Oct 23, 2025
c21e3f6
Further clarification to the default color space.
weegeekps Oct 23, 2025
9e1995a
Dropped PQ and changed HLG to BT.2100. Fixed casing in color spaces.
weegeekps Oct 24, 2025
75eddc9
Removed the wide-gamut color spaces from the base spec.
weegeekps Nov 4, 2025
501d37e
Fixing a typo
weegeekps Nov 6, 2025
cf7c6a2
Removed "indices" from example.
weegeekps Nov 6, 2025
9c926f0
Adding non-normative note about sRGB color blending.
weegeekps Nov 10, 2025
c51ffc1
Clarified when blending should occur.
weegeekps Nov 18, 2025
a457dcc
Added clarification around scale and rotation attributes.
weegeekps Dec 2, 2025
1c8e9ee
Further clarification.
weegeekps Dec 2, 2025
8dba6db
Further clarifications around the ellipse kernel.
weegeekps Dec 3, 2025
2a071bb
Expanded possible component types for scale.
weegeekps Dec 3, 2025
90c747e
Fixed a missing attribute prefix.
weegeekps Dec 3, 2025
2a55cd3
Clarified the opacity definition.
weegeekps Dec 3, 2025
25a8127
Further clarification of the opacity.
weegeekps Dec 3, 2025
0dbe3e3
Addressing feedback received during 3DF call
weegeekps Dec 4, 2025
4c974f2
Removed default values on required properties
weegeekps Dec 5, 2025
c25cb07
Merge branch 'draft-splat-spz-simpler' into draft-splat-spz
weegeekps Dec 5, 2025
fe06ac4
Fixing typos in sorting method section
weegeekps Dec 5, 2025
2f6aedc
Fixing a typo in the color space section
weegeekps Dec 8, 2025
a8a12b4
Clarified perspective projection.
weegeekps Dec 8, 2025
bb4e82d
Changed color space values to OIIO format
weegeekps Dec 8, 2025
8974df1
Removed byte and short types from SH
weegeekps Dec 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
314 changes: 314 additions & 0 deletions extensions/2.0/Khronos/KHR_gaussian_splatting/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
<!--
Copyright 2015-2025 The Khronos Group Inc.
SPDX-License-Identifier: CC-BY-4.0
-->

# KHR\_gaussian\_splatting

## Contributors

- Jason Sobotka, Cesium
- Renaud Keriven, Cesium
- Adam Morris, Cesium
- Sean Lilley, Cesium
- Projit Bandyopadhyay, Niantic Spatial
- Daniel Knoblauch, Niantic Spatial
- Ronald Poirrier, Esri
- Jean-Philippe Pons, Esri
- Alexey Knyazev, Khronos
- Marco Hutter, Independent
- Arseny Kapoulkine, Independent
- Nathan Morrical, Nvidia
- Norbert Nopper, Huawei
- Zehui Lin, Huawei
- Chenxi Tu, Huawei
- Michael Nikelsky, Autodesk

## Status

Review Draft

## Dependencies

Written against the glTF 2.0 spec.

## Table of Contents

- [Overview](#overview)
- [Adding 3D Gaussian Splats to Primitives](#adding-3d-gaussian-splats-to-primitives)
- [Geometry Type](#geometry-type)
- [Schema Example](#schema-example)
- [Extension Properties](#extension-properties)
- [Attributes](#attributes)
- [Accessors](#accessors)
- [Known Implementations](#known-implementations)
- [Resources](#resources)

## Overview

This extension defines basic support for storing 3D Gaussian splats in glTF, bringing structure and conformity to the 3D Gaussian splatting space. 3D Gaussian splatting uses fields of Gaussians that can be treated as a point cloud for the purposes of storage. 3D Gaussian splats are defined by their position, rotation, scale, and spherical harmonics which provide both diffuse and specular color. These values are stored as values on a point primitive. Since we treat the 3D Gaussian splats as points primitives, a graceful fallback to treating the data as a sparse point cloud is possible.

A key objective of this extension is to establish a solid foundation for integrating 3D Gaussian splatting into glTF, while enabling future enhancements and innovation. To achieve this, the extension is intentionally designed for to be extended itself, allowing extensions to introduce new kernel types, color spaces, projection methods, and sorting methods over time as 3D Gaussian splatting techniques evolve and become standards within the glTF ecosystem.

## Adding 3D Gaussian Splats to Primitives

When a primitive contains an `extension` property defining `KHR_gaussian_splatting`, this indicates to the client that the primitive should be treated as a 3D Gaussian splatting field.

The extension must be listed in `extensionsUsed`:

```json
"extensionsUsed" : [
"KHR_gaussian_splatting"
]
```

Other extensions that depend on this extension such as 3D Gaussian splatting compression extensions may require that this extension be included in `extensionsRequired`.

## Geometry Type

The `mode` of the `primitive` must be `POINTS`.

## Lighting

At the time of writing, the most common method for lighting 3D Gaussian splats is via spherical harmonics. This extension defines attributes to store spherical harmonic coefficients for each splat. The zeroth-order spherical harmonic coefficients are always required. Higher order coefficients are optional.

These rules may be relaxed by future extensions that define alternative lighting methods or have specific requirements for handling compression, such as when a compression method stores the diffuse color components as linear color values instead of the zeroth-order coefficients.
Comment on lines +73 to +75
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary for future proofing and ensuring we have appropriate flexibility.

From the standpoint of the future, if spherical harmonics are not being used for lighting, then the diffuse color component is unlikely to be based on the zero-order spherical harmonics. A future extension enabling PBR (or whatever future lighting may be) should be allowed to override this requirement.

More immediately, many of the current forms of compression, including SPZ, encode the diffuse color component as a linear color. Those compression extensions need to be able to override this requirement as well.


## Schema Example

Example shown below including optional attributes and properties. This extension only affects any `primitive` nodes containting 3D Gaussian splat data.

```json
"meshes": [{
"primitives": [{
"attributes": {
"POSITION": 0,
"COLOR_0": 1,
"KHR_gaussian_splatting:SCALE": 2,
"KHR_gaussian_splatting:ROTATION": 3,
"KHR_gaussian_splatting:OPACITY": 4,
"KHR_gaussian_splatting:SH_DEGREE_0_COEF_0": 5,
"KHR_gaussian_splatting:SH_DEGREE_1_COEF_0": 6,
"KHR_gaussian_splatting:SH_DEGREE_1_COEF_1": 7,
"KHR_gaussian_splatting:SH_DEGREE_1_COEF_2": 8
},
"mode": 0,
"extensions": {
"KHR_gaussian_splatting": {
"kernel": "ellipse",
"colorSpace": "BT.709-sRGB",
"sortingMethod": "cameraDistance",
"projection": "perspective"
}
}
}]
}]
```

## Extension Properties

### Kernel

Gaussian splats can have a variety of shapes and this has the potential to change over time. The `kernel` property is a required property that provides an indication to the renderer the properties of the kernel used. Renderers are free to ignore any values they do not recognize.

Additional kernel types can be added over time by supplying an extension that defines an alternative shape definition and parameters.

| Kernel Type | Description |
| --- | --- |
| ellipse | A 2D ellipse kernel used to project an ellipsoid shape in 3D space. |

```json
"meshes": [{
"primitives": [{
// snip...
"extensions": {
"KHR_gaussian_splatting": {
"kernel": "ellipse"
}
}
}]
}]
```

#### Ellipse Kernel

A 2D `ellipse` kernel type is often used to represent 3D Gaussian splats in an ellipsoid shape based on the kernel defined in [3D Gaussian Splatting for Real-Time Radiance Field Rendering](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/). This simple type contains no parameters. This is the shape used by the reference renderer implementations for 3D Gaussian splatting. Following the original reference implementation this kernel assumes a _3σ_ cut-off (Mahalanobis distance of 3 units) for correct rendering.

The mean vector for the Gaussian splat is provided by the position of the mesh primitive. This defines the center of the Gaussian splat ellipsoid in global space.

The opacity of a Gaussian splat is defined by the `KHR_gaussian_splatting:OPACITY` attribute for this kernel. It stores a normalized value between _0.0_ (transparent) and _1.0_ (opaque). A sigmoid activation function applied during training ensures the value stays within this range. Out-of-range values are invalid. This guarantees that renderers can use the stored opacity directly for alpha blending without any extra processing.

The scale (`KHR_gaussian_splatting:SCALE`) and rotation (`KHR_gaussian_splatting:ROTATION`) attributes define the size and orientation of the ellipsoid in 3D space. These attributes represent the covariance matrix of the Gaussian in a factored form. The scale attribute values correspond to the spread of the Gaussian along its local principal axes and the rotation attribute values correspond to the orientation of those axes in global space.

`KHR_gaussian_splatting:SCALE` is stored in log-space, so the actual scale along each principal axis is computed as `exp(scale)`. This allows for representing a wide range of scales while maintaining numerical stability.

`KHR_gaussian_splatting:ROTATION` is stored as a unit quaternion in the order (x, y, z, w), where `w` is the scalar component. This quaternion represents the rotation from the local space of the Gaussian to global space.

Together, the scale and rotation can be used to reconstruct the full covariance matrix of the Gaussian splat for rendering purposes. Combined with the position attribute, these values define the identity and shape of the ellipsoid in 3D space.

More details on how to interpret these attributes for rendering can be found in the [3D Gaussian Splatting for Real-Time Radiance Field Rendering](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/) paper.

### Color Space

The `colorSpace` property is a required property that specifies the color space of the 3D Gaussian Splat when spherical harmonics are being used for the lighting. The color space is typically determined by the training process for the splats. This color space value only applies to the 3D Gaussian splatting data and does not affect any other color data in the glTF.

Unless specified otherwise by additional extensions, color space information refers to the reconstructed splat color values, therefore splat reconstruction and alpha blending must be performed on the attribute values as-is, before any color gamut or transfer function conversions.

Additional values can be added over time by defining extensions to add new color spaces. See the section, [Extending the Base Extension](#extending-the-base-extension), for more information.

#### Available Color Spaces

| Color Space | Description |
| --- | --- |
| srgb_rec709_display | BT.709 sRGB (display-referred) color space. |
| lin_rec709_scene | BT.709 linear (scene-referred) color space. |

### Projection

The `projection` property is an optional property that specifies how the Gaussians should be projected onto the kernel shape. This is typically provided by the training process for the splats. This property is meant to be extended in the future as new projections become standardized within the community.

This base extension defines a single projection method, `perspective`, which is the default value. This keeps the behavior consistent with the original 3D Gaussian splatting paper.

_Non-normative Note: See [the original 3D Gaussian Splatting paper](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/) appendix A, "Details of Gradiant Computation," for more details on how the perspective projection is computed._

Additional values can be added over time by defining extensions to add new projection methods. See the section, [Extending the Base Extension](#extending-the-base-extension), for more information.

#### Known Projection Methods

| Projection Method | Description |
| --- | --- |
| perspective | (Default) The typical 3D perspective projection based on scene depth. |

### Sorting Method

The `sortingMethod` property is an optional property that specifies how the Gaussian particles should be sorted during the rendering process. This typically is provided by the training process for the splats. This property is meant to be extended in the future as new sorting methods become standardized within the community.

This base extension defines a single sorting method, `cameraDistance`, which is the default value. This keeps the behavior consistent with the original 3D Gaussian splatting paper.

Additional values can be added over time by defining extensions to add new sorting methods. See the section, [Extending the Base Extension](#extending-the-base-extension), for more information.

#### Known Sorting Methods

| Sorting Method | Description |
| --- | --- |
| cameraDistance | (Default) Sort the splats based on the length of the vector from the splat to the camera origin. |

## Attributes

| Splat Data | glTF Attribute | Accessor Type | Component Type | Required | Notes |
| --- | --- | --- | --- | --- | --- |
| Rotation | KHR_gaussian_splatting:ROTATION | VEC4 | _float_ <br/>_signed byte_ normalized <br/>_signed short_ normalized | yes | Rotation is a quaternion with `w` as the scalar. (xyzw) |
| Scale | KHR_gaussian_splatting:SCALE | VEC3 | _float_ <br/>_signed byte_ <br/>_signed byte_ normalized <br/>_signed short_ <br/>_signed short_ normalized | yes | |
| Opacity | KHR_gaussian_splatting:OPACITY | SCALAR | _float_ <br/>_unsigned byte_ normalized <br/>_unsigned short_ normalized | yes | |
| Spherical Harmonics degree 0 | KHR_gaussian_splatting:SH_DEGREE_0_COEF_0 | VEC3 | _float_ <br/>_signed byte_ normalized <br/>_signed short_ normalized | yes (unless using a different method for lighting) | |
| Spherical Harmonics degree 1 | KHR_gaussian_splatting:SH_DEGREE_1_COEF_n (n = 0 to 2) | VEC3 | _float_ <br/>_signed byte_ normalized <br/>_signed short_ normalized | no (yes if degree 2 or 3 are used) | |
| Spherical Harmonics degree 2 | KHR_gaussian_splatting:SH_DEGREE_2_COEF_n (n = 0 to 4) | VEC3 | _float_ <br/>_signed byte_ normalized <br/>_signed short_ normalized | no (yes if degree 3 is used) | |
| Spherical Harmonics degree 3 | KHR_gaussian_splatting:SH_DEGREE_3_COEF_n (n = 0 to 6) | VEC3 | _float_ <br/>_signed byte_ normalized <br/>_signed short_ normalized | no | |

### Basic Attributes

Each 3D Gaussian splat has the following attributes. At minimum the attributes must contain `POSITION`, `KHR_gaussian_splatting:ROTATION`, `KHR_gaussian_splatting:SCALE`, and `KHR_gaussian_splatting:OPACITY`. `POSITION` is defined by the base glTF specification.

The `KHR_gaussian_splatting:ROTATION` and `KHR_gaussian_splatting:SCALE` attributes support quantized storage using normalized signed `byte` or `short` component types to reduce file size. If quantization is not needed, content creators should use the `float` component type for maximum precision.

The content of `KHR_gaussian_splatting:OPACITY`, `KHR_gaussian_splatting:ROTATION` and `KHR_gaussian_splatting:SCALE` are defined by their kernel. See the [Ellipse Kernel](#ellipse-kernel) section for more information for information about how these are defined for the default `ellipse` kernel.

### Spherical Harmonics Attributes

When spherical harmonics are being used for lighting, the coefficients for the diffuse component must be provided using the `KHR_gaussian_splatting:SH_DEGREE_0_COEF_0` attribute semantic. The zero-order spherical harmonic coefficients are always required to allow for properly handling cases where the diffuse color is not in the _BT.709_ color gamut. The `KHR_gaussian_splatting:SH_DEGREE_ℓ_COEF_n` attributes where ℓ > 0 hold the higher degrees of spherical harmonics data and are not required. If higher degrees of spherical harmonics are used then lower degrees are required implicitly.

Each increasing degree of spherical harmonics requires more coeffecients. At the 1st degree, 3 sets of coeffcients are required, increasing to 5 sets for the 2nd degree, and increasing to 7 sets at the 3rd degree. With all 3 degrees, this results in 45 spherical harmonic coefficients stored in the `KHR_gaussian_splatting:SH_DEGREE_ℓ_COEF_n` attributes.

Spherical harmonic data is packed in an (r, g, b) format within the VEC3 accessor type. Each coefficient contains 3 values representing the red, green, and blue channels of the spherical harmonic coefficient. Spherical harmonic degrees cannot be partially defined. For example, if any degree 2 spherical harmonics attribute sematnics are used, then all degree 2 and degree 1 spherical harmonic coefficients must be provided.

### Improving Fallback with COLOR_0

To support better fallback functionality, the `COLOR_0` attribute semantic from the base glTF specification may be used to provide the diffuse color of the 3D Gaussian splat. This allows renderers to color the points in the sparse point cloud when 3D Gaussian splatting is not supported by a renderer. The value of `COLOR_0` is derived by multiplying the 3 diffuse color components of the 3D Gaussian splat with the constant zeroth-order spherical harmonic (ℓ = 0) for the RGB channels. The alpha channel should contain the opacity of the splat.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weegeekps Plus adding offset=0.5

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of where you expect the 0.5f bias to be used in the renderer? I understand it's importance from the aspect of the training algorithm, but typically the renderer does not need to know this information, just that the color space is sRGB.

Copy link

@NorbertNopper-Huawei NorbertNopper-Huawei Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT: Did again some more research and had an internal discussion on this, so I keep what is important from the original post.


In general, the color is precomputed during load time, so one does not need to convert during runtime (but it is possible) or it is already stored in a specific file format e.g.
https://github.com/kishimisu/Gaussian-Splatting-WebGL/blob/main/src/loader.js#L96
https://github.com/playcanvas/engine/blob/main/src/scene/gsplat/gsplat-data.js#L73
https://github.com/antimatter15/splat/blob/main/convert.py#L32

In the implementation from the original paper this happens here:
https://github.com/graphdeco-inria/gaussian-splatting/blob/main/gaussian_renderer/__init__.py#L80
https://github.com/graphdeco-inria/gaussian-splatting/blob/main/utils/sh_utils.py#L117

During training, this goes forth and back e.g. using:
https://github.com/graphdeco-inria/gaussian-splatting/blob/main/utils/sh_utils.py#L114


The resulting colors are in general in the range of [0, 1], this is what the paper expects and is represented in this extension. So, this 0.5 is fixed by the given math and is added after the evaluation of the spherical harmonics. However, if it is not mandatory for 3DGS, a bias of 0.5 as default can be added.

For display referred images, the range of [0, 1] is given by default, independent if currently used sRGB encoding or for future use cases for PQ or HLG encoded images.

For scene referred images, if the linear color is in the [0, 1] range (e.g. content trained from SDR images and linear color space), this also works pretty well.
This fulfills the requirement for linear color space e.g. like here:
https://ubc-vision.github.io/stochasticsplats/

For the future, having other color spaces like Rec.2020, this also works well.

However, if the scene referred data is trained on HDR data, which contains values below 0 and/or larger 1, then it will not work.
However, the common approach is, that the color data is normalized to [0, 1] before training.
E.g. this paper uses RAW image data:
https://github.com/shreyesss/HDRSplat
To normalize the data, e.g. an offset with scale can be used. However, different approaches are available, to bring the data into the [0; 1] range e.g. using PQ for non-linear training.
This normalization and de-normalization and required parameters does belong into the KHR_gaussian_splatting_wide_gamut_color extension and needs to be further discussed there:
#2539


In summary:

  • No offset and scale or alternatives in this extension needed, as long as the trained image data are in the [0, 1] range.
  • As seen in the links above, the fixed 0.5 is given by the implementations of the paper and also depends on the required math. If required, a default bias of 0.5 can be added, however the text needs to be removed and/or rewritten in the README:

Wrong: "Non-normative Note: If the spherical harmonics are in the BT.709 gamut, the diffuse color can be computed from the KHR_gaussian_splatting:SH_DEGREE_0_COEF_0 attribute by multiplying each of the RGB components by the constant spherical harmonic value of 0.282095."

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we guarantee that SH_DEGREE_0_COEF_0 * 0.282095 + 0.5 will always be in the [0, 1] range? If not, maybe the note should also require clamping so that COLOR_0 values are valid as per glTF 2.0 spec.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, for the base glTF extension, we have this 0.5, like in the implementation of the paper.

Any additional parametrized offsetting and scaling, we do in the other extension.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a deeper look at what CesiumJS, BabylonJS, PlayCanvas, and Inria is doing because Inria is clearly are adding a 0.5f bias to the forward rendering pass and I wanted to ensure I fully understand. Ultimately, I think you are right @NorbertNopper-Huawei, but read on as I did a really deep dive into how all of this works. When I went back through everything this evening, as well as some of my notes from well over a year ago, I realized that this is actually a fairly important detail that I had forgotten.

The purpose of this bias within Inria's renderer is to ensure that the resulting color remains between [0, 1] before clamping. It's a numerical stability trick and as far as I can tell the authors mostly arbitrarily chose it because it works well enough.

As a refresher (because apparently I needed one) the way training works is the forward pass renders an image, compares to the ground truth, and then uses the backwards pass to adjust the SH coefficients. When you apply a bias, such as 0.5f as the authors have done, then the learned coefficients become intrinsically linked to the bias. Since a 3DGS renderer is simply the forward pass logic being run in real time, it needs to know the correct value of the bias.

None of the 3 real-time renderers appear to be doing this on the surface, but I did discover:

  • PlayCanvas has it's own clrOffset and clrScale that they're setting as you pointed out, but these are related to brightness and black point values set within the renderer. Otherwise, I couldn't find anywhere that the 0.5f value was being set. I suspect it is getting handled elsewhere.
  • CesiumJS and BabylonJS implicitly get this 0.5f value through SPZ, which I clearly forgot about. 🤦‍♂️
  • After looking deeper into the math, the 0.5f bias is appropriate for all SDR and HDR content. The key difference between SRGB and any HDR content would be that after the bias any data outside of the [0, 1] range will be clamped and truncated for SRGB and with HDR it would not.

Given all of this, we probably do need to add this bias value as a property, but while I'm leaning towards adding it, I admit I'm still not fully committed yet. I want to talk to some others on the training side of things and get their thoughts as well; in the off chance this is a value that nobody will ever change, then maybe it doesn't belong in the base spec. It is a non-negotiable constant that both the trainer and renderer have to agree on, so maybe it does. Not sure, I'll figure it out in the morning.

Also, as an aside, we should not refer to this value as offset. It's a fine detail, but in the context of Gaussian Splatting, something like colorBias or shBias is more correct given it's purpose.

Copy link

@NorbertNopper-Huawei NorbertNopper-Huawei Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please re-read, as I learned as well and updated the document ☺️
#2490 (comment)


  • For the base extension and probably other future extensions, we keep this 0.5 and it is not the offset anymore I mentioned initially
  • For SDR(!) based content in scene referred space or display referred content in general, the values are between [0, 1]. So, this base extension works out of the box.
  • For other color gamuts, this works as well with the base extension. However, these are handled in a separate extension as discussed
  • For HDR content below 0 and/or above 1, the content is normalized before training, bringing into [0, 1] space (this is done in the HDRSPlat paper as far as I understand this). So, nothing needs to be changed in the trainer and/or the renderer for the general case. However afterwards, one could use an offset and scale to do the de-normalizing, but maybe others want to use PQ to do this. Or something different. This needs somehow defined in a separate extension and e.g. what PlayCanvas is doing with the clrOffset and clrScale is what I suggest in a general approach. And I assume as well, somewhere is the 0.5 visible in their code.

  • What is also important, that SH_DEGREE_0_COEF_0 * 0.282095 can be precomputed, however it is not "yet" the color.
  • SH_DEGREE_0_COEF_0 * 0.282095 + 0.5 can also be precomputed for only degree 0. This is the color.
  • However, both optimizations are up to other extensions etc. and/or the fallback mentioned in the README.

  • In regards of the 0.5 bias, the spherical harmonic coefficients are trained around 0 for numeric stability. If you have the degree 0 only case, the values are somehow around [-1.7, 1.7] as mentioned before in this discussion. If you multiply by 0.282095, you come around the [-0.5, 0.5]. Add 0.5, and one is in the color space.
  • For higher degrees, the intervals are different. However, if summed up properly and added 0.5 at the end(!), the range is again in [0.0, 1.0]
  • So no bias required, it is always 0.5. And if this really needs to be altered in the future, we can create another extension for this.

From my perspective, if folks are catching up with our insights, the base extension is ready to go. Everything else can be handled in the other extensions.


*_Non-normative Note:_* If the spherical harmonics are in the BT.709 gamut, the diffuse color can be computed from the `KHR_gaussian_splatting:SH_DEGREE_0_COEF_0` attribute by multiplying each of the RGB components by the constant spherical harmonic value of _0.282095_.

## Extending the Base Extension

3D Gaussian splatting is an evolving technology with new techniques and methods being developed over time. To provide a solid foundation for 3D Gaussian splatting in glTF while allowing for future growth and innovation, this extension is designed to be extensible. New kernel types, color spaces, projection methods, and sorting methods can be added over time without requiring changes to the base extension.

Extensions may define additional attributes or custom properties as needed to support new features. Attribute semantics should be prefixed with their respective extension name to avoid naming collisions. Extensions may also define additional values for the `kernel`, `colorSpace`, `projection`, and `sortingMethod` properties. Custom properties should be included in the body of the new extension object.

*_Non-normative Note: It is possible to share data between two attributes by using the same accessor index for multiple attribute semantics. This can be useful to optimize the storage of data._*

Compression extensions that operate on 3D Gaussian splatting data should extend this base extension to ensure compatibility. Compression extensions must define how the data can be decoded back into the base 3D Gaussian splatting format defined by this extension, but may also allow optimizations specific to their compression method. (e.g. passing textures or other data directly to the GPU for decoding.)

To use an extensions that extends `KHR_gaussian_splatting`, the extension must be included within the `extensions` property of the `KHR_gaussian_splatting` extension object. The extension must also be listed in `extensionsUsed` at the top level of the glTF.

Extension authors are encouraged to define fallback behaviors for renderers that do not recognize the new extension, but this is not strictly required. If a fallback is not possible, the extension should be listed in `extensionsRequired` to ensure that renderers that do not support the extension do not attempt to render the data incorrectly.

#### Example: Adding additional Kernel Types

*This section is non-normative.*

In order to add additional kernel types, a new extension should be defined that extends `KHR_gaussian_splatting`. This new extension would define the new kernel type and any parameters it may require. A renderer that recognizes the new kernel type can then use the parameters defined in the new extension to render the splats appropriately. Renderers that do not recognize the new kernel type should fall back to the default `ellipse` type.

For example, a new extension `EXT_gaussian_splatting_kernel_customShape` could be defined that adds a new kernel type `customShape` with additional parameters.

```json
"meshes": [{
"primitives": [{
// ...omitted for brevity...
"extensions": {
"KHR_gaussian_splatting": {
"kernel": "customShape",
"extensions": {
"EXT_gaussian_splatting_kernel_customShape": {
"customParameter1": 1.0,
"customParameter2": [0.0, 1.0, 0.0]
}
}
},
}
}]
}]
```

If the kernel type requires additional attributes, those attributes should be defined within the new extension using unique semantics to avoid collisions.

```json
"meshes": [{
"primitives": [{
"attributes": {
"POSITION": 0,
"KHR_gaussian_splatting:SCALE": 1,
"KHR_gaussian_splatting:ROTATION": 2,
"EXT_gaussian_splatting_kernel_customShape:CUSTOM_ATTRIBUTE": 3
},
// ...omitted for brevity...
"extensions": {
"KHR_gaussian_splatting": {
"kernel": "customShape",
"extensions": {
"EXT_gaussian_splatting_kernel_customShape": {
"customParameter1": 1.0
}
}
}
}
}]
}]
```

The extension must also be listed in `extensionsUsed` at the top level of the glTF.

```json
"extensionsUsed" : [
"KHR_gaussian_splatting",
"EXT_gaussian_splatting_kernel_customShape"
]
```

## Known Implementations

This is currently implemented within [3D Tiles and CesiumJS as an experimental feature](https://cesium.com/learn/cesiumjs/ref-doc/Cesium3DTileset.html?classFilter=3D).

## Resources

- [3D Gaussian Splatting for Real-Time Radiance Field Rendering](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/)
- [Gaussian Splatting Algorithm Details](https://github.com/joeyan/gaussian_splatting/blob/main/MATH.md)

Loading