From e3dfed16c2688ab280fb963325a3106233b44f60 Mon Sep 17 00:00:00 2001 From: Felix Herbst Date: Wed, 19 Aug 2026 17:43:06 +0200 Subject: [PATCH 1/3] WebGLNodesHandler: Fix error with `getCanvasTarget` in WebGLRenderer. (#34303) --- examples/jsm/tsl/WebGLNodesHandler.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/jsm/tsl/WebGLNodesHandler.js b/examples/jsm/tsl/WebGLNodesHandler.js index 70ccdd04024857..5ba71c8e5829da 100644 --- a/examples/jsm/tsl/WebGLNodesHandler.js +++ b/examples/jsm/tsl/WebGLNodesHandler.js @@ -230,6 +230,12 @@ class RendererProxy { } + getCanvasTarget() { + + return null; + + } + hasCompatibility( name ) { if ( name === Compatibility.TEXTURE_COMPARE ) { From 2e1894fdfa181e762a83358b3219622ccdf1ee47 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Wed, 19 Aug 2026 18:14:43 +0200 Subject: [PATCH 2/3] Docs: Improve `BundleGroup`. (#34305) --- src/renderers/common/BundleGroup.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/renderers/common/BundleGroup.js b/src/renderers/common/BundleGroup.js index 4be14ac23b743e..00608588423b8a 100644 --- a/src/renderers/common/BundleGroup.js +++ b/src/renderers/common/BundleGroup.js @@ -6,6 +6,10 @@ import { Group } from '../../objects/Group.js'; * are considered as one render bundle and processed as such by * the renderer. * + * Only renderable 3D objects are allowed in a bundle group. Other + * types like lights are not supported and must be added to the scene + * outside of the group. + * * This module is only fully supported by `WebGPURenderer` with a WebGPU backend. * With a WebGL backend, the group can technically be rendered but without * any performance improvements. From 5d5ebcff9f94e660934bd7741e26492d53e33d0c Mon Sep 17 00:00:00 2001 From: WestLangley Date: Wed, 19 Aug 2026 13:15:22 -0400 Subject: [PATCH 3/3] Rename: GaussianSplatMesh -> GaussianSplat (#34306) --- examples/jsm/Addons.js | 2 +- .../GLTFGaussianSplatLoaderExtension.js | 12 +++++------ .../jsm/loaders/GaussianSplatPLYLoader.js | 2 +- examples/jsm/loaders/KSPLATLoader.js | 4 ++-- examples/jsm/loaders/SPLATLoader.js | 4 ++-- examples/jsm/loaders/SPZLoader.js | 4 ++-- ...{GaussianSplatMesh.js => GaussianSplat.js} | 20 +++++++++---------- examples/webgpu_gaussian_splat.html | 4 ++-- test/unit/addons/loaders/GLTFLoader.tests.js | 4 ++-- 9 files changed, 28 insertions(+), 28 deletions(-) rename examples/jsm/objects/{GaussianSplatMesh.js => GaussianSplat.js} (98%) diff --git a/examples/jsm/Addons.js b/examples/jsm/Addons.js index 48d7bef4436230..449434321d2a84 100644 --- a/examples/jsm/Addons.js +++ b/examples/jsm/Addons.js @@ -164,7 +164,7 @@ export * from './modifiers/SimplifyModifier.js'; export * from './modifiers/TessellateModifier.js'; export * from './objects/GroundedSkybox.js'; -export * from './objects/GaussianSplatMesh.js'; +export * from './objects/GaussianSplat.js'; export * from './objects/Lensflare.js'; export * from './objects/MarchingCubes.js'; export * from './objects/Reflector.js'; diff --git a/examples/jsm/loaders/GLTFGaussianSplatLoaderExtension.js b/examples/jsm/loaders/GLTFGaussianSplatLoaderExtension.js index 7c115410b8543b..421a8b9070144c 100644 --- a/examples/jsm/loaders/GLTFGaussianSplatLoaderExtension.js +++ b/examples/jsm/loaders/GLTFGaussianSplatLoaderExtension.js @@ -2,7 +2,7 @@ import { Group } from 'three'; -import { GaussianSplatMesh } from '../objects/GaussianSplatMesh.js'; +import { GaussianSplat } from '../objects/GaussianSplat.js'; import { SH_BAND_WORDS, createGaussianSplatGeometry, createPackedSphericalHarmonicsBand, writeColorBytesFromSH0, writeCovariance } from '../utils/GaussianSplatUtils.js'; const EXTENSION_NAME = 'KHR_gaussian_splatting'; @@ -14,7 +14,7 @@ const ATTRIBUTES = { /** * A glTF loader plugin for `KHR_gaussian_splatting`. * - * This plugin must be registered explicitly because {@link GaussianSplatMesh} + * This plugin must be registered explicitly because {@link GaussianSplat} * requires {@link WebGPURenderer}. * * ```js @@ -46,7 +46,7 @@ class GLTFGaussianSplatLoaderExtension { * Loads a glTF mesh containing gaussian splat primitives. * * @param {number} meshIndex - The mesh index. - * @return {?Promise} The loaded mesh or `null` when the mesh does not use this extension. + * @return {?Promise} The loaded mesh or `null` when the mesh does not use this extension. */ loadMesh( meshIndex ) { @@ -77,7 +77,7 @@ class GLTFGaussianSplatLoaderExtension { } - const mesh = createGaussianSplatMesh( geometry, primitive ); + const mesh = createGaussianSplat( geometry, primitive ); mesh.name = parser.createUniqueName( meshDef.name || ( 'mesh_' + meshIndex ) ); assignExtrasToUserData( mesh, meshDef ); @@ -117,7 +117,7 @@ function isGaussianSplatPrimitive( primitiveDef ) { } -function createGaussianSplatMesh( geometry, primitiveDef ) { +function createGaussianSplat( geometry, primitiveDef ) { const extensionDef = primitiveDef.extensions[ EXTENSION_NAME ]; @@ -194,7 +194,7 @@ function createGaussianSplatMesh( geometry, primitiveDef ) { } - const mesh = new GaussianSplatMesh( createGaussianSplatGeometry( centers, covariances, colors, sphericalHarmonics ) ); + const mesh = new GaussianSplat( createGaussianSplatGeometry( centers, covariances, colors, sphericalHarmonics ) ); mesh.userData.gltfExtensions = mesh.userData.gltfExtensions || {}; mesh.userData.gltfExtensions[ EXTENSION_NAME ] = Object.assign( {}, extensionDef ); diff --git a/examples/jsm/loaders/GaussianSplatPLYLoader.js b/examples/jsm/loaders/GaussianSplatPLYLoader.js index 4db2368f853510..9bbd85f4206c06 100644 --- a/examples/jsm/loaders/GaussianSplatPLYLoader.js +++ b/examples/jsm/loaders/GaussianSplatPLYLoader.js @@ -56,7 +56,7 @@ const _restPropertyPattern = /^f_rest_\d+$/; * ```js * const loader = new GaussianSplatPLYLoader(); * const geometry = await loader.loadAsync( './models/gsplat/point_cloud.ply' ); - * scene.add( new GaussianSplatMesh( geometry ) ); + * scene.add( new GaussianSplat( geometry ) ); * ``` * * @augments Loader diff --git a/examples/jsm/loaders/KSPLATLoader.js b/examples/jsm/loaders/KSPLATLoader.js index 4e32ab487150c2..deed6a21ded6ba 100644 --- a/examples/jsm/loaders/KSPLATLoader.js +++ b/examples/jsm/loaders/KSPLATLoader.js @@ -58,7 +58,7 @@ const COMPRESSION_LEVELS = { * A loader for GaussianSplats3D `.ksplat` files. * * This loader decodes the format into `BufferGeometry` for use with - * `GaussianSplatMesh`. Higher-order spherical harmonics are exposed as optional + * `GaussianSplat`. Higher-order spherical harmonics are exposed as optional * `sphericalHarmonics1` through `sphericalHarmonics3` packed uint32 geometry * attributes (`SH_BAND_WORDS[ degree ]` words per splat). Coefficients use the * clamped-byte encoding `( value - 128 ) / 128`, four bytes per word. @@ -66,7 +66,7 @@ const COMPRESSION_LEVELS = { * ```js * const loader = new KSPLATLoader(); * const data = await loader.loadAsync( './models/gsplat/example.ksplat' ); - * scene.add( new GaussianSplatMesh( data ) ); + * scene.add( new GaussianSplat( data ) ); * ``` * * @augments Loader diff --git a/examples/jsm/loaders/SPLATLoader.js b/examples/jsm/loaders/SPLATLoader.js index a0087954d44361..ecc24753b4a254 100644 --- a/examples/jsm/loaders/SPLATLoader.js +++ b/examples/jsm/loaders/SPLATLoader.js @@ -11,13 +11,13 @@ const ROW_SIZE_BYTES = 32; * A loader for standard fixed-width Gaussian splat `.splat` files. * * This loader decodes the format into `BufferGeometry` for use with - * `GaussianSplatMesh`. Each 32-byte row stores center, scale, color and + * `GaussianSplat`. Each 32-byte row stores center, scale, color and * rotation data for one splat. * * ```js * const loader = new SPLATLoader(); * const data = await loader.loadAsync( './models/gsplat/example.splat' ); - * scene.add( new GaussianSplatMesh( data ) ); + * scene.add( new GaussianSplat( data ) ); * ``` * * @augments Loader diff --git a/examples/jsm/loaders/SPZLoader.js b/examples/jsm/loaders/SPZLoader.js index 509f75701e789a..456aa33e7c6e10 100644 --- a/examples/jsm/loaders/SPZLoader.js +++ b/examples/jsm/loaders/SPZLoader.js @@ -49,7 +49,7 @@ const _quaternion = [ 0, 0, 0, 0 ]; * A loader for compressed Gaussian splat `.spz` files. * * This loader decodes the format into `BufferGeometry` for use with - * `GaussianSplatMesh`. Higher-order spherical harmonics are exposed as optional + * `GaussianSplat`. Higher-order spherical harmonics are exposed as optional * `sphericalHarmonics1` through `sphericalHarmonics3` packed uint32 geometry * attributes (`SH_BAND_WORDS[ degree ]` words per splat). Coefficients use the * clamped-byte encoding `( value - 128 ) / 128`, four bytes per word. @@ -57,7 +57,7 @@ const _quaternion = [ 0, 0, 0, 0 ]; * ```js * const loader = new SPZLoader(); * const data = await loader.loadAsync( './models/gsplat/example.spz' ); - * scene.add( new GaussianSplatMesh( data ) ); + * scene.add( new GaussianSplat( data ) ); * ``` * * @augments Loader diff --git a/examples/jsm/objects/GaussianSplatMesh.js b/examples/jsm/objects/GaussianSplat.js similarity index 98% rename from examples/jsm/objects/GaussianSplatMesh.js rename to examples/jsm/objects/GaussianSplat.js index 317afc6dce22d3..21cd11d84951e0 100644 --- a/examples/jsm/objects/GaussianSplatMesh.js +++ b/examples/jsm/objects/GaussianSplat.js @@ -73,14 +73,14 @@ const _vector = /*@__PURE__*/ new Vector3(); * both `three/webgpu` and `three/tsl`. * * ```js - * const splats = new GaussianSplatMesh( geometry ); + * const splats = new GaussianSplat( geometry ); * scene.add( splats ); * ``` * * @augments Mesh - * @three_import import { GaussianSplatMesh } from 'three/addons/objects/GaussianSplatMesh.js'; + * @three_import import { GaussianSplat } from 'three/addons/objects/GaussianSplat.js'; */ -class GaussianSplatMesh extends Mesh { +class GaussianSplat extends Mesh { /** * Constructs a new Gaussian splat mesh. @@ -122,9 +122,9 @@ class GaussianSplatMesh extends Mesh { * @readonly * @default true */ - this.isGaussianSplatMesh = true; + this.isGaussianSplat = true; - this.type = 'GaussianSplatMesh'; + this.type = 'GaussianSplat'; /** * The source splat geometry. @@ -134,7 +134,7 @@ class GaussianSplatMesh extends Mesh { this.splatGeometry = splatGeometry; /** - * The bounding box of the splats. Can be computed via {@link GaussianSplatMesh#computeBoundingBox}. + * The bounding box of the splats. Can be computed via {@link GaussianSplat#computeBoundingBox}. * * @type {?Box3} * @default null @@ -142,7 +142,7 @@ class GaussianSplatMesh extends Mesh { this.boundingBox = null; /** - * The bounding sphere of the splats. Can be computed via {@link GaussianSplatMesh#computeBoundingSphere}. + * The bounding sphere of the splats. Can be computed via {@link GaussianSplat#computeBoundingSphere}. * * @type {?Sphere} * @default null @@ -259,7 +259,7 @@ class GaussianSplatMesh extends Mesh { } /** - * Computes the bounding box of the splats, updating {@link GaussianSplatMesh#boundingBox}. + * Computes the bounding box of the splats, updating {@link GaussianSplat#boundingBox}. * * Each splat is expanded by its own extent rather than treated as a point, so the bounds cover * what is drawn. @@ -295,7 +295,7 @@ class GaussianSplatMesh extends Mesh { } /** - * Computes the bounding sphere of the splats, updating {@link GaussianSplatMesh#boundingSphere}. + * Computes the bounding sphere of the splats, updating {@link GaussianSplat#boundingSphere}. * * Each splat is expanded by its own extent rather than treated as a point, so the bounds cover * what is drawn. @@ -856,4 +856,4 @@ function createMaterial( vertexNode, fragmentNode ) { } -export { GaussianSplatMesh }; +export { GaussianSplat }; diff --git a/examples/webgpu_gaussian_splat.html b/examples/webgpu_gaussian_splat.html index 8656e1e2674d6e..0d664656dd43fe 100644 --- a/examples/webgpu_gaussian_splat.html +++ b/examples/webgpu_gaussian_splat.html @@ -46,7 +46,7 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { SPLATLoader } from 'three/addons/loaders/SPLATLoader.js'; import { SPZLoader } from 'three/addons/loaders/SPZLoader.js'; - import { GaussianSplatMesh } from 'three/addons/objects/GaussianSplatMesh.js'; + import { GaussianSplat } from 'three/addons/objects/GaussianSplat.js'; import { Inspector } from 'three/addons/inspector/Inspector.js'; let camera, scene, renderer, controls, splats, splatRoot; @@ -148,7 +148,7 @@ disposeCurrentSplats(); - splats = new GaussianSplatMesh( splatData, { autoSort: false } ); + splats = new GaussianSplat( splatData, { autoSort: false } ); splatRoot = splats; if ( source.rotation !== undefined ) splatRoot.rotation.copy( source.rotation ); diff --git a/test/unit/addons/loaders/GLTFLoader.tests.js b/test/unit/addons/loaders/GLTFLoader.tests.js index d9b4ebea670033..013973a21c75ce 100644 --- a/test/unit/addons/loaders/GLTFLoader.tests.js +++ b/test/unit/addons/loaders/GLTFLoader.tests.js @@ -140,7 +140,7 @@ export default QUnit.module( 'Addons', () => { QUnit.module( 'GLTFLoader', () => { - QUnit.test( 'loads KHR_gaussian_splatting primitives as GaussianSplatMesh', async ( assert ) => { + QUnit.test( 'loads KHR_gaussian_splatting primitives as GaussianSplat', async ( assert ) => { const loader = new GLTFLoader(); loader.register( function ( parser ) { @@ -153,7 +153,7 @@ export default QUnit.module( 'Addons', () => { const mesh = gltf.scene.children[ 0 ]; const covariances = mesh.splatGeometry.getAttribute( 'covariance' ).array; - assert.ok( mesh.isGaussianSplatMesh, 'creates GaussianSplatMesh' ); + assert.ok( mesh.isGaussianSplat, 'creates GaussianSplat' ); assert.deepEqual( Array.from( mesh.splatGeometry.getAttribute( 'position' ).array ), [ 1, 2, 3 ], 'loads centers' ); closeTo( assert, covariances[ 0 ], 4, 'covariance xx' ); closeTo( assert, covariances[ 3 ], 9, 'covariance yy' );