@babylonjs/core 9.9.1 → 9.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AudioV2/abstractAudio/audioEngineV2.d.ts +34 -1
- package/AudioV2/abstractAudio/audioEngineV2.js +54 -0
- package/AudioV2/abstractAudio/audioEngineV2.js.map +1 -1
- package/AudioV2/abstractAudio/components/spatialAudioAttacherComponent.d.ts +12 -0
- package/AudioV2/abstractAudio/components/spatialAudioAttacherComponent.js +18 -0
- package/AudioV2/abstractAudio/components/spatialAudioAttacherComponent.js.map +1 -1
- package/AudioV2/abstractAudio/index.d.ts +1 -0
- package/AudioV2/abstractAudio/index.js +1 -0
- package/AudioV2/abstractAudio/index.js.map +1 -1
- package/AudioV2/abstractAudio/pure.d.ts +1 -0
- package/AudioV2/abstractAudio/pure.js +1 -0
- package/AudioV2/abstractAudio/pure.js.map +1 -1
- package/AudioV2/abstractAudio/subNodes/spatialAudioSubNode.d.ts +7 -1
- package/AudioV2/abstractAudio/subNodes/spatialAudioSubNode.js +12 -0
- package/AudioV2/abstractAudio/subNodes/spatialAudioSubNode.js.map +1 -1
- package/AudioV2/abstractAudio/subProperties/abstractSpatialAudio.d.ts +14 -0
- package/AudioV2/abstractAudio/subProperties/abstractSpatialAudio.js.map +1 -1
- package/AudioV2/abstractAudio/subProperties/abstractSpatialAudioListener.d.ts +4 -0
- package/AudioV2/abstractAudio/subProperties/abstractSpatialAudioListener.js.map +1 -1
- package/AudioV2/abstractAudio/subProperties/spatialAudio.d.ts +6 -0
- package/AudioV2/abstractAudio/subProperties/spatialAudio.js +12 -0
- package/AudioV2/abstractAudio/subProperties/spatialAudio.js.map +1 -1
- package/AudioV2/abstractAudio/subProperties/spatialAudioListener.d.ts +2 -0
- package/AudioV2/abstractAudio/subProperties/spatialAudioListener.js +4 -0
- package/AudioV2/abstractAudio/subProperties/spatialAudioListener.js.map +1 -1
- package/AudioV2/webAudio/webAudioEngine.js +2 -1
- package/AudioV2/webAudio/webAudioEngine.js.map +1 -1
- package/Engines/abstractEngine.pure.js +2 -2
- package/Engines/abstractEngine.pure.js.map +1 -1
- package/FrameGraph/Node/Blocks/Layers/selectionOutlineLayerBlock.pure.d.ts +3 -0
- package/FrameGraph/Node/Blocks/Layers/selectionOutlineLayerBlock.pure.js +16 -1
- package/FrameGraph/Node/Blocks/Layers/selectionOutlineLayerBlock.pure.js.map +1 -1
- package/FrameGraph/Tasks/Layers/selectionOutlineTask.d.ts +2 -1
- package/FrameGraph/Tasks/Layers/selectionOutlineTask.js +5 -2
- package/FrameGraph/Tasks/Layers/selectionOutlineTask.js.map +1 -1
- package/Gizmos/index.d.ts +1 -0
- package/Gizmos/index.js +1 -0
- package/Gizmos/index.js.map +1 -1
- package/Gizmos/pure.d.ts +1 -0
- package/Gizmos/pure.js +1 -0
- package/Gizmos/pure.js.map +1 -1
- package/Gizmos/spatialAudioGizmo.d.ts +55 -0
- package/Gizmos/spatialAudioGizmo.js +151 -0
- package/Gizmos/spatialAudioGizmo.js.map +1 -0
- package/Layers/selectionOutlineLayer.pure.d.ts +9 -2
- package/Layers/selectionOutlineLayer.pure.js +29 -6
- package/Layers/selectionOutlineLayer.pure.js.map +1 -1
- package/Layers/thinEffectLayer.d.ts +1 -0
- package/Layers/thinEffectLayer.js +7 -4
- package/Layers/thinEffectLayer.js.map +1 -1
- package/Layers/thinSelectionOutlineLayer.d.ts +17 -3
- package/Layers/thinSelectionOutlineLayer.js +82 -17
- package/Layers/thinSelectionOutlineLayer.js.map +1 -1
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.d.ts +5 -0
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js +54 -1
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js.map +1 -1
- package/Materials/PBR/openpbrMaterial.pure.d.ts +13 -0
- package/Materials/PBR/openpbrMaterial.pure.js +17 -0
- package/Materials/PBR/openpbrMaterial.pure.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingCompoundMesh.pure.d.ts +2 -1
- package/Meshes/GaussianSplatting/gaussianSplattingCompoundMesh.pure.js +3 -2
- package/Meshes/GaussianSplatting/gaussianSplattingCompoundMesh.pure.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.d.ts +32 -2
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js +180 -22
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.d.ts +54 -10
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js +130 -13
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js.map +1 -1
- package/Meshes/abstractMesh.pure.d.ts +5 -1
- package/Meshes/abstractMesh.pure.js +92 -2
- package/Meshes/abstractMesh.pure.js.map +1 -1
- package/Meshes/thinInstanceMesh.pure.js +143 -2
- package/Meshes/thinInstanceMesh.pure.js.map +1 -1
- package/Meshes/thinInstanceMesh.types.d.ts +2 -1
- package/Meshes/thinInstanceMesh.types.js.map +1 -1
- package/Misc/tools.pure.js +1 -1
- package/Misc/tools.pure.js.map +1 -1
- package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js +12 -1
- package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js.map +1 -1
- package/Rendering/geometryBufferRenderer.pure.js +8 -0
- package/Rendering/geometryBufferRenderer.pure.js.map +1 -1
- package/Rendering/objectRenderer.js +4 -2
- package/Rendering/objectRenderer.js.map +1 -1
- package/Shaders/ShadersInclude/gaussianSplatting.js +54 -5
- package/Shaders/ShadersInclude/gaussianSplatting.js.map +1 -1
- package/Shaders/ShadersInclude/pbrBlockFinalLitComponents.js +1 -1
- package/Shaders/ShadersInclude/pbrBlockFinalLitComponents.js.map +1 -1
- package/Shaders/gaussianSplatting.vertex.js +14 -3
- package/Shaders/gaussianSplatting.vertex.js.map +1 -1
- package/Shaders/gaussianSplattingVoxel.vertex.js +1 -0
- package/Shaders/gaussianSplattingVoxel.vertex.js.map +1 -1
- package/Shaders/selectionOutline.fragment.js +16 -4
- package/Shaders/selectionOutline.fragment.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/gaussianSplatting.js +56 -5
- package/ShadersWGSL/ShadersInclude/gaussianSplatting.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.js +2 -3
- package/ShadersWGSL/ShadersInclude/openpbrBaseLayerData.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrBlockFinalLitComponents.js +1 -1
- package/ShadersWGSL/ShadersInclude/pbrBlockFinalLitComponents.js.map +1 -1
- package/ShadersWGSL/gaussianSplatting.vertex.js +14 -3
- package/ShadersWGSL/gaussianSplatting.vertex.js.map +1 -1
- package/ShadersWGSL/gaussianSplattingVoxel.vertex.js +1 -0
- package/ShadersWGSL/gaussianSplattingVoxel.vertex.js.map +1 -1
- package/ShadersWGSL/selectionOutline.fragment.js +14 -2
- package/ShadersWGSL/selectionOutline.fragment.js.map +1 -1
- package/XR/features/WebXRBodyTracking.pure.d.ts +16 -0
- package/XR/features/WebXRBodyTracking.pure.js +167 -30
- package/XR/features/WebXRBodyTracking.pure.js.map +1 -1
- package/package.json +1 -1
|
@@ -19,8 +19,9 @@ export declare class GaussianSplattingCompoundMesh extends GaussianSplattingMesh
|
|
|
19
19
|
* @param url optional URL to load a Gaussian Splatting file from
|
|
20
20
|
* @param scene the hosting scene
|
|
21
21
|
* @param keepInRam whether to keep the raw splat data in RAM after uploading to GPU
|
|
22
|
+
* @param needsRotationScaleTextures generate rotation and scale matrix textures required for voxel-based IBL shadows
|
|
22
23
|
*/
|
|
23
|
-
constructor(name: string, url?: Nullable<string>, scene?: Nullable<Scene>, keepInRam?: boolean);
|
|
24
|
+
constructor(name: string, url?: Nullable<string>, scene?: Nullable<Scene>, keepInRam?: boolean, needsRotationScaleTextures?: boolean);
|
|
24
25
|
/**
|
|
25
26
|
* Add another mesh to this compound mesh as a new part.
|
|
26
27
|
* The source mesh's splat data is read directly and copied into the compound's retained source buffers.
|
|
@@ -17,9 +17,10 @@ export class GaussianSplattingCompoundMesh extends GaussianSplattingMesh {
|
|
|
17
17
|
* @param url optional URL to load a Gaussian Splatting file from
|
|
18
18
|
* @param scene the hosting scene
|
|
19
19
|
* @param keepInRam whether to keep the raw splat data in RAM after uploading to GPU
|
|
20
|
+
* @param needsRotationScaleTextures generate rotation and scale matrix textures required for voxel-based IBL shadows
|
|
20
21
|
*/
|
|
21
|
-
constructor(name, url = null, scene = null, keepInRam = false) {
|
|
22
|
-
super(name, url, scene, keepInRam);
|
|
22
|
+
constructor(name, url = null, scene = null, keepInRam = false, needsRotationScaleTextures = false) {
|
|
23
|
+
super(name, url, scene, keepInRam, needsRotationScaleTextures);
|
|
23
24
|
}
|
|
24
25
|
/**
|
|
25
26
|
* Add another mesh to this compound mesh as a new part.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gaussianSplattingCompoundMesh.pure.js","sourceRoot":"","sources":["../../../../../dev/core/src/Meshes/GaussianSplatting/gaussianSplattingCompoundMesh.pure.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAI7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,OAAO,6BAA8B,SAAQ,qBAAqB;IACpE
|
|
1
|
+
{"version":3,"file":"gaussianSplattingCompoundMesh.pure.js","sourceRoot":"","sources":["../../../../../dev/core/src/Meshes/GaussianSplatting/gaussianSplattingCompoundMesh.pure.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAI7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,OAAO,6BAA8B,SAAQ,qBAAqB;IACpE;;;;;;;OAOG;IACH,YAAY,IAAY,EAAE,MAAwB,IAAI,EAAE,QAAyB,IAAI,EAAE,YAAqB,KAAK,EAAE,6BAAsC,KAAK;QAC1J,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,0BAA0B,CAAC,CAAC;IACnE,CAAC;IAED;;;;;;OAMG;IACa,OAAO,CAAC,KAA4B,EAAE,eAAwB,IAAI;QAC9E,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;OAMG;IACI,QAAQ,CAAC,MAA+B,EAAE,gBAAyB,IAAI;QAC1E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,EAAE,CAAC;QACd,CAAC;QACD,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACtE,OAAO,WAAW,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACa,UAAU,CAAC,KAAa;QACpC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;;OAMG;IACa,SAAS,CAAC,sBAA2B,EAAE,EAAE,WAAmB,QAAQ;QAChF,mBAAmB,GAAG,KAAK,CAAC,SAAS,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;QACrE,mDAAmD;QACnD,2FAA2F;QAC3F,6EAA6E;QAC7E,mBAAmB,CAAC,WAAW,GAAG,IAAI,CAAC;QACvC,OAAO,mBAAmB,CAAC;IAC/B,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAU,KAAK,CAAC,UAAe,EAAE,KAAY;QACtD,OAAO,qBAAqB,CAAC,cAAc,CAAC,UAAU,EAAE,KAAK,EAAE,6BAA6B,CAAC,CAAC;IAClG,CAAC;CACJ;AAED,IAAI,WAAW,GAAG,KAAK,CAAC;AACxB;;;GAGG;AACH,MAAM,UAAU,qCAAqC;IACjD,IAAI,WAAW,EAAE,CAAC;QACd,OAAO;IACX,CAAC;IACD,WAAW,GAAG,IAAI,CAAC;IAEnB,IAAI,CAAC,oCAAoC,GAAG,6BAA6B,CAAC,KAAK,CAAC;AACpF,CAAC","sourcesContent":["/** This file must only contain pure code and pure imports */\r\n\r\nimport { type Nullable } from \"core/types\";\r\nimport { type Scene } from \"core/scene.pure\";\r\nimport { GaussianSplattingMesh } from \"./gaussianSplattingMesh.pure\";\r\nimport { type GaussianSplattingPartProxyMesh } from \"./gaussianSplattingPartProxyMesh.pure\";\r\nimport { Mesh } from \"../mesh.pure\";\r\n\r\n/**\r\n * Class used to compose multiple Gaussian Splatting meshes into a single draw call,\r\n * with per-part world-matrix and visibility control via addPart/addParts/removePart.\r\n *\r\n * This is the recommended class for multi-part Gaussian Splatting use cases.\r\n *\r\n * Next major version: the compound mesh API (addPart/addParts/removePart) will\r\n * move exclusively to this class and will be removed from GaussianSplattingMesh.\r\n */\r\nexport class GaussianSplattingCompoundMesh extends GaussianSplattingMesh {\r\n /**\r\n * Creates a new GaussianSplattingCompoundMesh\r\n * @param name the name of the mesh\r\n * @param url optional URL to load a Gaussian Splatting file from\r\n * @param scene the hosting scene\r\n * @param keepInRam whether to keep the raw splat data in RAM after uploading to GPU\r\n * @param needsRotationScaleTextures generate rotation and scale matrix textures required for voxel-based IBL shadows\r\n */\r\n constructor(name: string, url: Nullable<string> = null, scene: Nullable<Scene> = null, keepInRam: boolean = false, needsRotationScaleTextures: boolean = false) {\r\n super(name, url, scene, keepInRam, needsRotationScaleTextures);\r\n }\r\n\r\n /**\r\n * Add another mesh to this compound mesh as a new part.\r\n * The source mesh's splat data is read directly and copied into the compound's retained source buffers.\r\n * @param other - The other mesh to add. Must be fully loaded before calling this method.\r\n * @param disposeOther - Whether to dispose the other mesh after adding it.\r\n * @returns a placeholder mesh that can be used to manipulate the part transform\r\n */\r\n public override addPart(other: GaussianSplattingMesh, disposeOther: boolean = true): GaussianSplattingPartProxyMesh {\r\n return super.addPart(other, disposeOther);\r\n }\r\n\r\n /**\r\n * Add multiple meshes to this compound mesh as new parts in a single operation.\r\n * Splat data is written into texture arrays while the compound refreshes its retained merged source buffers.\r\n * @param others - The meshes to add. Each must be fully loaded and must not be a compound.\r\n * @param disposeOthers - Whether to dispose the other meshes after adding them.\r\n * @returns an array of placeholder meshes that can be used to manipulate the part transforms\r\n */\r\n public addParts(others: GaussianSplattingMesh[], disposeOthers: boolean = true): GaussianSplattingPartProxyMesh[] {\r\n if (others.length === 0) {\r\n return [];\r\n }\r\n const { proxyMeshes } = this._addPartsInternal(others, disposeOthers);\r\n return proxyMeshes;\r\n }\r\n\r\n /**\r\n * Remove a part from this compound mesh.\r\n * The remaining parts are rebuilt directly from the compound mesh's retained source buffers.\r\n * @param index - The index of the part to remove\r\n */\r\n public override removePart(index: number): void {\r\n super.removePart(index);\r\n }\r\n\r\n /**\r\n * Serialize current GaussianSplattingMesh\r\n * @param serializationObject defines the object which will receive the serialization data\r\n * @param encoding the encoding of binary data, defaults to base64 for json serialize,\r\n * kept for future internal use like cloning where base64 encoding wastes cycles and memory\r\n * @returns the serialized object\r\n */\r\n public override serialize(serializationObject: any = {}, encoding: string = \"base64\"): any {\r\n serializationObject = super.serialize(serializationObject, encoding);\r\n // Note here, the getClassName() is not overridden,\r\n // as a lot of code currently depend on `getClassName() === \"GaussianSplattingMesh\"` check,\r\n // to not break those code, serialization uses `_isCompound` to mark the type\r\n serializationObject._isCompound = true;\r\n return serializationObject;\r\n }\r\n\r\n /**\r\n * Parses a serialized GaussianSplattingCompoundMesh\r\n * @param parsedMesh the serialized mesh\r\n * @param scene the scene to create the GaussianSplattingCompoundMesh in\r\n * @returns the created GaussianSplattingCompoundMesh\r\n */\r\n public static override Parse(parsedMesh: any, scene: Scene): GaussianSplattingCompoundMesh {\r\n return GaussianSplattingMesh._ParseInternal(parsedMesh, scene, GaussianSplattingCompoundMesh);\r\n }\r\n}\r\n\r\nlet _Registered = false;\r\n/**\r\n * Register side effects for gaussianSplattingCompoundMesh.\r\n * Safe to call multiple times; only the first call has an effect.\r\n */\r\nexport function RegisterGaussianSplattingCompoundMesh(): void {\r\n if (_Registered) {\r\n return;\r\n }\r\n _Registered = true;\r\n\r\n Mesh._GaussianSplattingCompoundMeshParser = GaussianSplattingCompoundMesh.Parse;\r\n}\r\n"]}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/** This file must only contain pure code and pure imports */
|
|
2
2
|
import { type Nullable } from "../../types.js";
|
|
3
3
|
import { type Scene } from "../../scene.pure.js";
|
|
4
|
-
import {
|
|
4
|
+
import { Matrix, Vector3 } from "../../Maths/math.vector.pure.js";
|
|
5
|
+
import { type Vector2 } from "../../Maths/math.vector.js";
|
|
5
6
|
import { type Effect } from "../../Materials/effect.pure.js";
|
|
6
7
|
import { GaussianSplattingMeshBase } from "./gaussianSplattingMeshBase.pure.js";
|
|
7
8
|
import { GaussianSplattingPartProxyMesh } from "./gaussianSplattingPartProxyMesh.pure.js";
|
|
8
|
-
import {
|
|
9
|
+
import { BoundingInfo } from "../../Culling/boundingInfo.js";
|
|
9
10
|
import { type BaseTexture } from "../../Materials/Textures/baseTexture.pure.js";
|
|
11
|
+
import { type AbstractMesh } from "../abstractMesh.pure.js";
|
|
10
12
|
interface IGaussianSplattingPartSource {
|
|
11
13
|
name: string;
|
|
12
14
|
_vertexCount: number;
|
|
@@ -29,6 +31,9 @@ export declare class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
29
31
|
* Proxy meshes indexed by part index. Maintained in sync with _partMatrices.
|
|
30
32
|
*/
|
|
31
33
|
private _partProxies;
|
|
34
|
+
/** Part 0 local-space AABB when owned directly (not proxied). Set on first addPart, cleared on dispose/reset. */
|
|
35
|
+
private _part0LocalMin;
|
|
36
|
+
private _part0LocalMax;
|
|
32
37
|
/**
|
|
33
38
|
* World matrices for each part, indexed by part index.
|
|
34
39
|
*/
|
|
@@ -70,6 +75,31 @@ export declare class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
70
75
|
* @returns true when ready
|
|
71
76
|
*/
|
|
72
77
|
isReady(completeCheck?: boolean): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Recomputes compound local-space bounds from part 0's stored AABB (if unproxied) plus all
|
|
80
|
+
* proxy world AABBs inverse-transformed to compound-local space. All 8 corners of each proxy
|
|
81
|
+
* AABB are transformed so the result is correct under non-identity compound rotation/scale.
|
|
82
|
+
*/
|
|
83
|
+
private _updateBoundingInfoFromProxies;
|
|
84
|
+
/**
|
|
85
|
+
* Override for compound meshes: recomputes bounds from proxy world extents instead of
|
|
86
|
+
* local bounds × world matrix, which is wrong for proxied parts with independent transforms.
|
|
87
|
+
* @returns this mesh
|
|
88
|
+
*/
|
|
89
|
+
_updateBoundingInfo(): AbstractMesh;
|
|
90
|
+
/**
|
|
91
|
+
* Replaces the base hierarchy bounds computation for compound meshes: computes world bounds
|
|
92
|
+
* from scratch by iterating part 0's local AABB and all proxy meshes, rather than delegating
|
|
93
|
+
* to the base _children traversal which never reaches proxies (they are not parented to the
|
|
94
|
+
* compound). Visibility per-part is respected; invisible parts are excluded.
|
|
95
|
+
* @param includeDescendants when true, includes descendants (default: true)
|
|
96
|
+
* @param predicate optional filter predicate
|
|
97
|
+
* @returns world-space min/max of the hierarchy bounding box
|
|
98
|
+
*/
|
|
99
|
+
getHierarchyBoundingVectors(includeDescendants?: boolean, predicate?: Nullable<(abstractMesh: AbstractMesh) => boolean>): {
|
|
100
|
+
min: Vector3;
|
|
101
|
+
max: Vector3;
|
|
102
|
+
};
|
|
73
103
|
/**
|
|
74
104
|
* Disposes proxy meshes and clears part data in addition to the base class GPU resources.
|
|
75
105
|
* @param doNotRecurse Set to true to not recurse into each children
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/** This file must only contain pure code and pure imports */
|
|
2
|
-
import { Quaternion, Vector3 } from "../../Maths/math.vector.pure.js";
|
|
2
|
+
import { Matrix, Quaternion, Vector3 } from "../../Maths/math.vector.pure.js";
|
|
3
3
|
import { GetGaussianSplattingMaxPartCount } from "../../Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js";
|
|
4
|
-
import { GaussianSplattingMeshBase } from "./gaussianSplattingMeshBase.pure.js";
|
|
4
|
+
import { GaussianSplattingMeshBase, AllocateShBuffers } from "./gaussianSplattingMeshBase.pure.js";
|
|
5
5
|
import { RawTexture } from "../../Materials/Textures/rawTexture.js";
|
|
6
6
|
|
|
7
7
|
import { DecodeBase64ToBinary, EncodeArrayBufferToBase64 } from "../../Misc/stringTools.js";
|
|
8
8
|
import { Mesh } from "../mesh.pure.js";
|
|
9
9
|
import { GaussianSplattingPartProxyMesh } from "./gaussianSplattingPartProxyMesh.pure.js";
|
|
10
|
+
import { BoundingInfo } from "../../Culling/boundingInfo.js";
|
|
10
11
|
const _GaussianSplattingBytesPerSplat = 32;
|
|
11
12
|
const _GaussianSplattingBytesPerShTexel = 16;
|
|
12
13
|
/**
|
|
@@ -78,6 +79,9 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
78
79
|
* Proxy meshes indexed by part index. Maintained in sync with _partMatrices.
|
|
79
80
|
*/
|
|
80
81
|
this._partProxies = [];
|
|
82
|
+
/** Part 0 local-space AABB when owned directly (not proxied). Set on first addPart, cleared on dispose/reset. */
|
|
83
|
+
this._part0LocalMin = null;
|
|
84
|
+
this._part0LocalMax = null;
|
|
81
85
|
/**
|
|
82
86
|
* World matrices for each part, indexed by part index.
|
|
83
87
|
*/
|
|
@@ -123,6 +127,101 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
123
127
|
}
|
|
124
128
|
return super.isReady(completeCheck);
|
|
125
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Recomputes compound local-space bounds from part 0's stored AABB (if unproxied) plus all
|
|
132
|
+
* proxy world AABBs inverse-transformed to compound-local space. All 8 corners of each proxy
|
|
133
|
+
* AABB are transformed so the result is correct under non-identity compound rotation/scale.
|
|
134
|
+
*/
|
|
135
|
+
_updateBoundingInfoFromProxies() {
|
|
136
|
+
const compoundWorld = this.getWorldMatrix();
|
|
137
|
+
const invCompoundWorld = Matrix.Invert(compoundWorld);
|
|
138
|
+
const localMin = this._part0LocalMin ? this._part0LocalMin.clone() : new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
139
|
+
const localMax = this._part0LocalMax ? this._part0LocalMax.clone() : new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
|
|
140
|
+
const corner = new Vector3();
|
|
141
|
+
for (const proxy of this._partProxies) {
|
|
142
|
+
if (!proxy) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
// Proxies have no geometry — getHierarchyBoundingVectors returns sentinels. Use boundingBox directly.
|
|
146
|
+
proxy.computeWorldMatrix(false);
|
|
147
|
+
const bb = proxy.getBoundingInfo().boundingBox;
|
|
148
|
+
const wMin = bb.minimumWorld;
|
|
149
|
+
const wMax = bb.maximumWorld;
|
|
150
|
+
for (let b = 0; b < 8; b++) {
|
|
151
|
+
corner.set(b & 1 ? wMax.x : wMin.x, b & 2 ? wMax.y : wMin.y, b & 4 ? wMax.z : wMin.z);
|
|
152
|
+
Vector3.TransformCoordinatesToRef(corner, invCompoundWorld, corner);
|
|
153
|
+
localMin.minimizeInPlace(corner);
|
|
154
|
+
localMax.maximizeInPlace(corner);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (localMin.x <= localMax.x) {
|
|
158
|
+
// Direct access avoids getBoundingInfo() → _updateBoundingInfo() recursion.
|
|
159
|
+
if (this._boundingInfo) {
|
|
160
|
+
this._boundingInfo.reConstruct(localMin, localMax, compoundWorld);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this._boundingInfo = new BoundingInfo(localMin, localMax, compoundWorld);
|
|
164
|
+
}
|
|
165
|
+
this._cachedBoundingMin = localMin.clone();
|
|
166
|
+
this._cachedBoundingMax = localMax.clone();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Override for compound meshes: recomputes bounds from proxy world extents instead of
|
|
171
|
+
* local bounds × world matrix, which is wrong for proxied parts with independent transforms.
|
|
172
|
+
* @returns this mesh
|
|
173
|
+
*/
|
|
174
|
+
_updateBoundingInfo() {
|
|
175
|
+
if (this.isCompound) {
|
|
176
|
+
this._updateBoundingInfoFromProxies();
|
|
177
|
+
this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
|
|
178
|
+
return this;
|
|
179
|
+
}
|
|
180
|
+
return super._updateBoundingInfo();
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Replaces the base hierarchy bounds computation for compound meshes: computes world bounds
|
|
184
|
+
* from scratch by iterating part 0's local AABB and all proxy meshes, rather than delegating
|
|
185
|
+
* to the base _children traversal which never reaches proxies (they are not parented to the
|
|
186
|
+
* compound). Visibility per-part is respected; invisible parts are excluded.
|
|
187
|
+
* @param includeDescendants when true, includes descendants (default: true)
|
|
188
|
+
* @param predicate optional filter predicate
|
|
189
|
+
* @returns world-space min/max of the hierarchy bounding box
|
|
190
|
+
*/
|
|
191
|
+
getHierarchyBoundingVectors(includeDescendants = true, predicate = null) {
|
|
192
|
+
if (!this.isCompound) {
|
|
193
|
+
return super.getHierarchyBoundingVectors(includeDescendants, predicate);
|
|
194
|
+
}
|
|
195
|
+
// For compound meshes, compute visible-only world bounds from scratch so that
|
|
196
|
+
// invisible parts don't inflate the result (e.g. for voxelization scene bounds).
|
|
197
|
+
const min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
198
|
+
const max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
|
|
199
|
+
// Unproxied part 0: the compound mesh owns this geometry directly (no proxy node).
|
|
200
|
+
// Transform its local AABB to world space if visible.
|
|
201
|
+
if (this._part0LocalMin && (this._partVisibility[0] ?? 1.0) > 0) {
|
|
202
|
+
const wm = this.getWorldMatrix();
|
|
203
|
+
const lMin = this._part0LocalMin;
|
|
204
|
+
const lMax = this._part0LocalMax;
|
|
205
|
+
const corner = new Vector3();
|
|
206
|
+
for (let b = 0; b < 8; b++) {
|
|
207
|
+
corner.set(b & 1 ? lMax.x : lMin.x, b & 2 ? lMax.y : lMin.y, b & 4 ? lMax.z : lMin.z);
|
|
208
|
+
Vector3.TransformCoordinatesToRef(corner, wm, corner);
|
|
209
|
+
min.minimizeInPlace(corner);
|
|
210
|
+
max.maximizeInPlace(corner);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
for (let i = 0; i < this._partProxies.length; i++) {
|
|
214
|
+
const proxy = this._partProxies[i];
|
|
215
|
+
if (!proxy || (this._partVisibility[i] ?? 1.0) === 0) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
proxy.computeWorldMatrix(false);
|
|
219
|
+
const bb = proxy.getBoundingInfo().boundingBox;
|
|
220
|
+
min.minimizeInPlace(bb.minimumWorld);
|
|
221
|
+
max.maximizeInPlace(bb.maximumWorld);
|
|
222
|
+
}
|
|
223
|
+
return { min, max };
|
|
224
|
+
}
|
|
126
225
|
/**
|
|
127
226
|
* Disposes proxy meshes and clears part data in addition to the base class GPU resources.
|
|
128
227
|
* @param doNotRecurse Set to true to not recurse into each children
|
|
@@ -136,6 +235,8 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
136
235
|
this._partMatrices = [];
|
|
137
236
|
this._partVisibility = [];
|
|
138
237
|
this._partIndicesTexture = null;
|
|
238
|
+
this._part0LocalMin = null;
|
|
239
|
+
this._part0LocalMax = null;
|
|
139
240
|
super.dispose(doNotRecurse);
|
|
140
241
|
}
|
|
141
242
|
// ---------------------------------------------------------------------------
|
|
@@ -385,7 +486,7 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
385
486
|
_vertexCount: proxy._vertexCount,
|
|
386
487
|
_splatsData: splatBytes.subarray(splatByteOffset, splatByteOffset + splatByteLength),
|
|
387
488
|
_shData: this._shData?.map((texture) => texture.subarray(shByteOffset, shByteOffset + shByteLength)) ?? null,
|
|
388
|
-
_shDegree: this._shData
|
|
489
|
+
_shDegree: this._shData ? this._shDegree : 0,
|
|
389
490
|
isCompound: false,
|
|
390
491
|
getWorldMatrix: () => proxy.getWorldMatrix(),
|
|
391
492
|
getBoundingInfo: () => proxy.getBoundingInfo(),
|
|
@@ -417,10 +518,11 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
417
518
|
this._shData = null;
|
|
418
519
|
return;
|
|
419
520
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
521
|
+
// Each SH texture holds one texel per splat; each texel is _GaussianSplattingBytesPerShTexel
|
|
522
|
+
// bytes with one byte per scalar, so it carries that many scalars. Degree d has
|
|
523
|
+
// ((d+1)^2 - 1) higher-order coefficients × 3 RGB = total scalars per splat; divide by texel capacity.
|
|
524
|
+
const shTextureCount = Math.ceil((((shDegree + 1) * (shDegree + 1) - 1) * 3) / _GaussianSplattingBytesPerShTexel);
|
|
525
|
+
const mergedShData = AllocateShBuffers(shTextureCount, totalCount * _GaussianSplattingBytesPerShTexel);
|
|
424
526
|
let shByteOffset = 0;
|
|
425
527
|
if (this._shData && existingVertexCount > 0) {
|
|
426
528
|
const existingShByteLength = existingVertexCount * _GaussianSplattingBytesPerShTexel;
|
|
@@ -476,16 +578,23 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
476
578
|
const covA = new Uint16Array(textureLength * 4);
|
|
477
579
|
const covB = new Uint16Array(covBSItemSize * textureLength);
|
|
478
580
|
const colorArray = new Uint8Array(textureLength * 4);
|
|
479
|
-
// Determine merged SH degree
|
|
480
|
-
|
|
581
|
+
// Determine merged SH degree.
|
|
582
|
+
// hasSH is true when the merged result will carry SH:
|
|
583
|
+
// - Existing compound already has SH (_shDegree>0): preserve it even if new parts
|
|
584
|
+
// have no SH — their texel region is pre-filled with 128 (neutral) by AllocateShBuffers.
|
|
585
|
+
// - At least one new part carries SH: enable SH for the whole compound; existing
|
|
586
|
+
// parts that had no SH also get neutral fill.
|
|
587
|
+
// Deliberately excludes the case where the existing compound has no SH and no new part
|
|
588
|
+
// has SH either (shDegreeNew stays 0, no SH textures allocated).
|
|
589
|
+
const hasSH = this._shDegree > 0 || others.some((o) => o._shData !== null);
|
|
481
590
|
const shDegreeNew = hasSH ? Math.max(this._shDegree, ...others.map((o) => o._shDegree)) : 0;
|
|
482
591
|
let sh = undefined;
|
|
483
592
|
if (hasSH && shDegreeNew > 0) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
593
|
+
// Each SH texture holds one texel per splat; each texel is _GaussianSplattingBytesPerShTexel
|
|
594
|
+
// bytes with one byte per scalar, so it carries that many scalars. Degree d has
|
|
595
|
+
// ((d+1)^2 - 1) higher-order coefficients × 3 RGB = total scalars per splat; divide by texel capacity.
|
|
596
|
+
const shTextureCount = Math.ceil((((shDegreeNew + 1) * (shDegreeNew + 1) - 1) * 3) / _GaussianSplattingBytesPerShTexel);
|
|
597
|
+
sh = AllocateShBuffers(shTextureCount, textureLength * _GaussianSplattingBytesPerShTexel);
|
|
489
598
|
}
|
|
490
599
|
// --- Incremental path: can we reuse the already-committed GPU region? ---
|
|
491
600
|
const incremental = this._canReuseCachedData(splatCountA, totalCount);
|
|
@@ -559,10 +668,9 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
559
668
|
this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false);
|
|
560
669
|
}
|
|
561
670
|
if (sh && this._shData) {
|
|
562
|
-
const bytesPerTexel = 16;
|
|
563
671
|
for (let texIdx = 0; texIdx < sh.length; texIdx++) {
|
|
564
672
|
if (texIdx < this._shData.length) {
|
|
565
|
-
sh[texIdx].set(this._shData[texIdx].subarray(0, part0Count *
|
|
673
|
+
sh[texIdx].set(this._shData[texIdx].subarray(0, part0Count * _GaussianSplattingBytesPerShTexel), 0);
|
|
566
674
|
}
|
|
567
675
|
}
|
|
568
676
|
}
|
|
@@ -597,10 +705,9 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
597
705
|
this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false);
|
|
598
706
|
}
|
|
599
707
|
if (sh && this._shData) {
|
|
600
|
-
const bytesPerTexel = 16;
|
|
601
708
|
for (let texIdx = 0; texIdx < sh.length; texIdx++) {
|
|
602
709
|
if (texIdx < this._shData.length) {
|
|
603
|
-
sh[texIdx].set(this._shData[texIdx].subarray(0, splatCountA *
|
|
710
|
+
sh[texIdx].set(this._shData[texIdx].subarray(0, splatCountA * _GaussianSplattingBytesPerShTexel), 0);
|
|
604
711
|
}
|
|
605
712
|
}
|
|
606
713
|
}
|
|
@@ -612,6 +719,7 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
612
719
|
// so _updateSubTextures does not upload stale zeros over those already-committed texels.
|
|
613
720
|
// The base-class _updateData always re-processes from firstNewTexel for the same reason;
|
|
614
721
|
// the compound path must do the same.
|
|
722
|
+
// Boundary-row SH is restored after _retainMergedPartData (see below), where _shData is ready.
|
|
615
723
|
if (incremental) {
|
|
616
724
|
const firstNewTexel = firstNewLine * textureSize.x;
|
|
617
725
|
if (firstNewTexel < splatCountA) {
|
|
@@ -704,6 +812,39 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
704
812
|
try {
|
|
705
813
|
// --- Upload to GPU ---
|
|
706
814
|
if (incremental) {
|
|
815
|
+
// Create missing SH GPU textures: either the compound just gained SH for the first
|
|
816
|
+
// time (_shTextures===null) or the degree increased (sh.length > _shTextures.length).
|
|
817
|
+
// Use _shData when available (contains correct merged values for all rows);
|
|
818
|
+
// fall back to sh[idx] (pre-filled with 128) when _shData is absent (keepInRam=false).
|
|
819
|
+
// _updateSubTextures will re-upload from firstNewLine, which is redundant but harmless.
|
|
820
|
+
if (sh && (!this._shTextures || sh.length > this._shTextures.length)) {
|
|
821
|
+
if (!this._shTextures) {
|
|
822
|
+
this._shTextures = [];
|
|
823
|
+
}
|
|
824
|
+
while (this._shTextures.length < sh.length) {
|
|
825
|
+
const idx = this._shTextures.length;
|
|
826
|
+
const shTexture = new RawTexture(null, textureSize.x, textureSize.y, 11, this._scene, false, false, 1, 7);
|
|
827
|
+
shTexture.wrapU = 0;
|
|
828
|
+
shTexture.wrapV = 0;
|
|
829
|
+
this._shTextures.push(shTexture);
|
|
830
|
+
const src = this._shData && idx < this._shData.length ? this._shData[idx] : sh[idx];
|
|
831
|
+
this._updateShTextureData(shTexture, src, textureSize.x, 0, textureSize.y);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
// Restore boundary-row SH: sh is freshly filled with 128, and _updateSubTextures
|
|
835
|
+
// starts at firstNewLine — existing splats on that row need their values from _shData.
|
|
836
|
+
if (sh && this._shData) {
|
|
837
|
+
const firstNewTexel = firstNewLine * textureSize.x;
|
|
838
|
+
if (firstNewTexel < splatCountA) {
|
|
839
|
+
const byteStart = firstNewTexel * _GaussianSplattingBytesPerShTexel;
|
|
840
|
+
const byteEnd = splatCountA * _GaussianSplattingBytesPerShTexel;
|
|
841
|
+
for (let texIdx = 0; texIdx < sh.length; texIdx++) {
|
|
842
|
+
if (texIdx < this._shData.length) {
|
|
843
|
+
sh[texIdx].set(this._shData[texIdx].subarray(byteStart, byteEnd), byteStart);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
707
848
|
// Update the part-indices texture (handles both create and update-in-place).
|
|
708
849
|
// _ensurePartIndicesTexture is a no-op when the texture already exists, so on the
|
|
709
850
|
// second+ addPart the partIndices would be stale without this call.
|
|
@@ -713,11 +854,23 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
713
854
|
else {
|
|
714
855
|
this._updateTextures(covA, covB, colorArray, sh);
|
|
715
856
|
}
|
|
716
|
-
this.getBoundingInfo().reConstruct(minimum, maximum, this.getWorldMatrix());
|
|
717
857
|
this.setEnabled(true);
|
|
718
|
-
this._cachedBoundingMin = minimum.clone();
|
|
719
|
-
this._cachedBoundingMax = maximum.clone();
|
|
720
858
|
this._notifyWorkerNewData();
|
|
859
|
+
// Bounding info is updated via _updateBoundingInfoFromProxies (called below, after proxy
|
|
860
|
+
// world matrices are known), which needs part 0's local-space AABB as an input:
|
|
861
|
+
// • For unproxied part 0 (legacy layout A: compound loaded its own splat data before
|
|
862
|
+
// any addPart call, so no _partProxies[0]), capture the local-space AABB from the
|
|
863
|
+
// compound mesh's existing _boundingInfo — set when the mesh loaded its own data via
|
|
864
|
+
// URL/updateData — so _updateBoundingInfoFromProxies can include part 0's geometry.
|
|
865
|
+
// • For proxied part 0, skip — its bounds are already on the proxy's getBoundingInfo()
|
|
866
|
+
// and _updateBoundingInfoFromProxies picks it up there.
|
|
867
|
+
// Guard splatCountA > 0 avoids reading a stale bounding box on a fresh empty mesh.
|
|
868
|
+
// Guard !this._part0LocalMin ensures we only store once; subsequent addPart calls must
|
|
869
|
+
// not overwrite it, because by then _boundingInfo reflects the full merged dataset.
|
|
870
|
+
if (!this._partProxies[0] && splatCountA > 0 && !this._part0LocalMin) {
|
|
871
|
+
this._part0LocalMin = this.getBoundingInfo().minimum.clone();
|
|
872
|
+
this._part0LocalMax = this.getBoundingInfo().maximum.clone();
|
|
873
|
+
}
|
|
721
874
|
// --- Create proxy meshes ---
|
|
722
875
|
const proxyMeshes = [];
|
|
723
876
|
for (let i = 0; i < others.length; i++) {
|
|
@@ -736,6 +889,8 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
736
889
|
this._partProxies[newPartIndex] = proxyMesh;
|
|
737
890
|
proxyMeshes.push(proxyMesh);
|
|
738
891
|
}
|
|
892
|
+
// Update compound bounds now that all proxy world matrices are known.
|
|
893
|
+
this._updateBoundingInfoFromProxies();
|
|
739
894
|
// Restore the rebuild gate and post the now-complete partMatrices in one message, then trigger a single sort pass.
|
|
740
895
|
// This ensures the worker sees a consistent partMatrices array that matches the partIndices for every splat.
|
|
741
896
|
if (needsWorkerGate) {
|
|
@@ -850,6 +1005,8 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
850
1005
|
this._partVisibility = [];
|
|
851
1006
|
this._cachedBoundingMin = null;
|
|
852
1007
|
this._cachedBoundingMax = null;
|
|
1008
|
+
this._part0LocalMin = null;
|
|
1009
|
+
this._part0LocalMax = null;
|
|
853
1010
|
this._splatsData = null;
|
|
854
1011
|
this._shData = null;
|
|
855
1012
|
this._shDegree = 0;
|
|
@@ -933,6 +1090,7 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
933
1090
|
}
|
|
934
1091
|
if (this._shData) {
|
|
935
1092
|
serializationObject.shData = encoding === "base64" ? this._shData.map(EncodeArrayBufferToBase64) : this._shData;
|
|
1093
|
+
serializationObject.shDegree = this._shDegree;
|
|
936
1094
|
}
|
|
937
1095
|
if (this._partIndices) {
|
|
938
1096
|
const compressedIndices = CompressPartIndices(this._partIndices.subarray(0, this._vertexCount));
|
|
@@ -984,7 +1142,7 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
984
1142
|
}
|
|
985
1143
|
if (splatsData) {
|
|
986
1144
|
const flipY = parsedMesh._flipY ?? false;
|
|
987
|
-
mesh.updateData(splatsData, parsedShData, { flipY }, parsedPartIndices);
|
|
1145
|
+
mesh.updateData(splatsData, parsedShData, { flipY }, parsedPartIndices, parsedMesh.shDegree);
|
|
988
1146
|
}
|
|
989
1147
|
if (parsedMesh.partProxies) {
|
|
990
1148
|
for (const serializedPart of parsedMesh.partProxies) {
|