Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
20eb4eb
SceneSerializer: skip GaussianSplattingPartProxyMesh
kzhsw Mar 5, 2026
201b45b
babylonFileLoader: Load partProxies from GaussianSplattingMesh into A…
kzhsw Mar 5, 2026
9bd91eb
GaussianSplattingPartProxyMesh: add IBoundingInfoProvider
kzhsw Mar 5, 2026
eacdc64
GaussianSplattingMesh: add serialization helper function
kzhsw Mar 5, 2026
0e1201e
GaussianSplattingMesh: add _flipY
kzhsw Mar 5, 2026
f246ff5
GaussianSplattingPartProxyMesh: add serialize
kzhsw Mar 5, 2026
b64e255
GaussianSplattingMesh: add serialize
kzhsw Mar 5, 2026
7bab113
GaussianSplattingPartProxyMesh: add Parse
kzhsw Mar 5, 2026
62afc64
Mesh: add parse holders for GaussianSplattingMesh
kzhsw Mar 5, 2026
e21c18b
GaussianSplattingMesh: add Parse
kzhsw Mar 5, 2026
906c14c
GaussianSplattingPartProxyMesh: update Parse holder of Mesh
kzhsw Mar 5, 2026
3e9aaed
GaussianSplattingMesh: update Parse holder of Mesh
kzhsw Mar 5, 2026
d9d80a4
babylonFileLoader: simplify code
kzhsw Mar 5, 2026
f964c86
GaussianSplattingMesh: do not serialize cameraMesh
kzhsw Mar 5, 2026
da3e297
GaussianSplattingMaterial: do not serialize ShaderMaterials
kzhsw Mar 5, 2026
f32c45f
GaussianSplattingMesh: use Map.forEach
kzhsw Mar 6, 2026
42ad948
babylonFileLoader: use Map.forEach
kzhsw Mar 6, 2026
6b6e031
GaussianSplattingMesh: check for splatsData in Parse
kzhsw Mar 6, 2026
ec6cf90
Merge branch 'BabylonJS:master' into patch-1
kzhsw Mar 6, 2026
4146068
GaussianSplattingMesh: serialize disableDepthSort and viewUpdateThres…
kzhsw Mar 6, 2026
fb28da0
GaussianSplattingMesh: serialize partProxies as array
kzhsw Mar 6, 2026
875fba6
GaussianSplattingMesh: remove a call to setWorldMatrixForPart
kzhsw Mar 6, 2026
f40d518
Merge branch 'master' into patch-1
kzhsw Mar 27, 2026
4cc0a6a
GaussianSplatting: merge class split with serialization support
kzhsw Apr 3, 2026
428cdc8
GaussianSplattingCompoundMesh: add serialization
kzhsw Apr 3, 2026
d275b62
Merge branch 'master' into patch-1
kzhsw Apr 3, 2026
6daa84a
GaussianSplattingMeshBase: do not serialize material and cameraMesh
kzhsw Apr 3, 2026
4941538
GaussianSplattingMesh: add test for serialization
kzhsw Apr 3, 2026
e0d947c
fix: eslint formatting
kzhsw Apr 7, 2026
5684db1
Merge branch 'BabylonJS:master' into patch-1
kzhsw Apr 7, 2026
4cf1f97
Merge branch 'BabylonJS:master' into patch-1
kzhsw Apr 8, 2026
f4957e7
Merge branch 'BabylonJS:master' into patch-1
kzhsw Apr 9, 2026
f3e5c3d
Merge branch 'master' into patch-1
kzhsw Apr 10, 2026
6f01fb0
GaussianSplatting: fix serialization parse and proxy parent loading
kzhsw Apr 10, 2026
055c4aa
fix: prettier formatting
kzhsw Apr 10, 2026
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
26 changes: 26 additions & 0 deletions packages/dev/core/src/Loading/Plugins/babylonFileLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,21 @@ const LoadAssetContainer = (scene: Scene, data: string | object, rootUrl: string
instance._parentContainer = container;
}
}
// Load partProxies from GaussianSplattingMesh into AssetContainer
if (mesh.getClassName() === "GaussianSplattingMesh") {
const partProxies = (mesh as any)._partProxies as AbstractMesh[] | Map<number, AbstractMesh> | undefined;
const proxies = Array.isArray(partProxies) ? partProxies : partProxies ? Array.from(partProxies.values()) : [];
for (const partProxy of proxies) {
if (!partProxy) {
continue;
}
container.meshes.push(partProxy);
partProxy._parentContainer = container;
if (partProxy._waitingParsedUniqueId != null) {
TempIndexContainer[partProxy._waitingParsedUniqueId] = partProxy;
}
}
}
log += index === 0 ? "\n\tMeshes:" : "";
log += "\n\t\t" + mesh.toString(fullDetails);
}
Expand Down Expand Up @@ -1000,6 +1015,17 @@ RegisterSceneLoaderPlugin({
meshes.push(mesh);
parsedIdToNodeMap.set(mesh._waitingParsedUniqueId!, mesh);
mesh._waitingParsedUniqueId = null;
if (mesh.getClassName() === "GaussianSplattingMesh") {
const partProxies = (mesh as any)._partProxies as AbstractMesh[] | Map<number, AbstractMesh> | undefined;
const proxies = Array.isArray(partProxies) ? partProxies : partProxies ? Array.from(partProxies.values()) : [];
for (const partProxy of proxies) {
if (!partProxy || partProxy._waitingParsedUniqueId == null) {
continue;
}
parsedIdToNodeMap.set(partProxy._waitingParsedUniqueId, partProxy);
partProxy._waitingParsedUniqueId = null;
}
}
log += "\n\tMesh " + mesh.toString(fullDetails);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ export class GaussianSplattingMaterial extends PushMaterial {
needAlphaBlending: alphaBlendedDepth,
}
);
shaderMaterial.doNotSerialize = true;
shaderMaterial.backFaceCulling = false;
shaderMaterial.onBindObservable.add((mesh: AbstractMesh) => {
const gsMaterial = mesh.material as GaussianSplattingMaterial;
Expand All @@ -622,6 +623,7 @@ export class GaussianSplattingMaterial extends PushMaterial {
shaderLanguage: shaderLanguage,
}
);
shaderMaterial.doNotSerialize = true;
shaderMaterial.backFaceCulling = false;

const shadowDepthWrapper = new ShadowDepthWrapper(shaderMaterial, scene, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type Nullable } from "core/types";
import { type Scene } from "core/scene";
import { GaussianSplattingMesh } from "./gaussianSplattingMesh";
import { type GaussianSplattingPartProxyMesh } from "./gaussianSplattingPartProxyMesh";
import { Mesh } from "../mesh";

/**
* Class used to compose multiple Gaussian Splatting meshes into a single draw call,
Expand All @@ -26,7 +27,7 @@ export class GaussianSplattingCompoundMesh extends GaussianSplattingMesh {

/**
* Add another mesh to this compound mesh as a new part.
* The source mesh's splat data is read directly — no merged CPU buffer is constructed.
* The source mesh's splat data is read directly and copied into the compound's retained source buffers.
* @param other - The other mesh to add. Must be fully loaded before calling this method.
* @param disposeOther - Whether to dispose the other mesh after adding it.
* @returns a placeholder mesh that can be used to manipulate the part transform
Expand All @@ -37,7 +38,7 @@ export class GaussianSplattingCompoundMesh extends GaussianSplattingMesh {

/**
* Add multiple meshes to this compound mesh as new parts in a single operation.
* Splat data is written directly into texture arrays without constructing a merged CPU buffer.
* Splat data is written into texture arrays while the compound refreshes its retained merged source buffers.
* @param others - The meshes to add. Each must be fully loaded and must not be a compound.
* @param disposeOthers - Whether to dispose the other meshes after adding them.
* @returns an array of placeholder meshes that can be used to manipulate the part transforms
Expand All @@ -52,11 +53,38 @@ export class GaussianSplattingCompoundMesh extends GaussianSplattingMesh {

/**
* Remove a part from this compound mesh.
* The remaining parts are rebuilt directly from their stored source mesh references —
* no merged CPU splat buffer is read back.
* The remaining parts are rebuilt directly from the compound mesh's retained source buffers.
* @param index - The index of the part to remove
*/
public override removePart(index: number): void {
super.removePart(index);
}

/**
* Serialize current GaussianSplattingMesh
* @param serializationObject defines the object which will receive the serialization data
* @param encoding the encoding of binary data, defaults to base64 for json serialize,
* kept for future internal use like cloning where base64 encoding wastes cycles and memory
* @returns the serialized object
*/
public override serialize(serializationObject: any = {}, encoding: string = "base64"): any {
serializationObject = super.serialize(serializationObject, encoding);
// Note here, the getClassName() is not overridden,
// as a lot of code currently depend on `getClassName() === "GaussianSplattingMesh"` check,
// to not break those code, serialization uses `_isCompound` to mark the type
serializationObject._isCompound = true;
return serializationObject;
}

/**
* Parses a serialized GaussianSplattingCompoundMesh
* @param parsedMesh the serialized mesh
* @param scene the scene to create the GaussianSplattingCompoundMesh in
* @returns the created GaussianSplattingCompoundMesh
*/
public static override Parse(parsedMesh: any, scene: Scene): GaussianSplattingCompoundMesh {
return GaussianSplattingMesh._ParseInternal(parsedMesh, scene, GaussianSplattingCompoundMesh);
}
}

Mesh._GaussianSplattingCompoundMeshParser = GaussianSplattingCompoundMesh.Parse;
Loading