@babylonjs/core 9.3.1 → 9.3.2
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/Engines/abstractEngine.js +2 -2
- package/Engines/abstractEngine.js.map +1 -1
- package/Lights/Clustered/clusteredLightContainer.d.ts +1 -0
- package/Lights/Clustered/clusteredLightContainer.js +19 -0
- package/Lights/Clustered/clusteredLightContainer.js.map +1 -1
- package/Lights/light.d.ts +6 -0
- package/Lights/light.js +8 -0
- package/Lights/light.js.map +1 -1
- package/Lights/spotLight.d.ts +2 -0
- package/Lights/spotLight.js +10 -0
- package/Lights/spotLight.js.map +1 -1
- package/Materials/Background/backgroundMaterial.js +4 -1
- package/Materials/Background/backgroundMaterial.js.map +1 -1
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.js +6 -2
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.js.map +1 -1
- package/Materials/Node/Blocks/Dual/lightBlock.d.ts +8 -0
- package/Materials/Node/Blocks/Dual/lightBlock.js +16 -0
- package/Materials/Node/Blocks/Dual/lightBlock.js.map +1 -1
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.js +3 -0
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.js.map +1 -1
- package/Materials/Node/nodeMaterial.js +4 -1
- package/Materials/Node/nodeMaterial.js.map +1 -1
- package/Materials/PBR/openpbrMaterial.js +4 -1
- package/Materials/PBR/openpbrMaterial.js.map +1 -1
- package/Materials/PBR/pbrBaseMaterial.js +4 -1
- package/Materials/PBR/pbrBaseMaterial.js.map +1 -1
- package/Materials/materialHelper.functions.d.ts +12 -0
- package/Materials/materialHelper.functions.js +24 -0
- package/Materials/materialHelper.functions.js.map +1 -1
- package/Materials/standardMaterial.js +4 -1
- package/Materials/standardMaterial.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.d.ts +13 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js +26 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.d.ts +3 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.js +113 -10
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.js.map +1 -1
- package/Misc/tools.js +1 -1
- package/Misc/tools.js.map +1 -1
- package/Rendering/depthRenderer.d.ts +8 -0
- package/Rendering/depthRenderer.js +48 -13
- package/Rendering/depthRenderer.js.map +1 -1
- package/Rendering/depthRendererSceneComponent.d.ts +1 -0
- package/Rendering/depthRendererSceneComponent.js +26 -0
- package/Rendering/depthRendererSceneComponent.js.map +1 -1
- package/XR/features/WebXRBodyTracking.d.ts +952 -0
- package/XR/features/WebXRBodyTracking.js +2221 -0
- package/XR/features/WebXRBodyTracking.js.map +1 -0
- package/XR/features/index.d.ts +1 -0
- package/XR/features/index.js +1 -0
- package/XR/features/index.js.map +1 -1
- package/XR/webXRFeaturesManager.d.ts +7 -0
- package/XR/webXRFeaturesManager.js +4 -0
- package/XR/webXRFeaturesManager.js.map +1 -1
- package/package.json +1 -1
- package/sceneComponent.d.ts +1 -0
- package/sceneComponent.js +1 -0
- package/sceneComponent.js.map +1 -1
|
@@ -393,6 +393,8 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
393
393
|
this._modelViewProjectionMatrix = Matrix.Identity();
|
|
394
394
|
this._canPostToWorker = true;
|
|
395
395
|
this._readyToDisplay = false;
|
|
396
|
+
this._sortRequestId = 0;
|
|
397
|
+
this._hasRenderedOnce = false;
|
|
396
398
|
this._covariancesATexture = null;
|
|
397
399
|
this._covariancesBTexture = null;
|
|
398
400
|
this._centersTexture = null;
|
|
@@ -496,6 +498,66 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
496
498
|
this._postToWorker(true);
|
|
497
499
|
return false;
|
|
498
500
|
}
|
|
501
|
+
// Before the first successful render, apply strict sort-state checks to ensure
|
|
502
|
+
// the first rendered frame uses correct splat ordering. Once the mesh has been
|
|
503
|
+
// rendered at least once, skip these checks — the render loop will continuously
|
|
504
|
+
// re-sort as the camera/world changes via _postToWorker() in render().
|
|
505
|
+
if (!this._hasRenderedOnce && !this._disableDepthSort) {
|
|
506
|
+
const cameras = this._scene.activeCameras?.length ? this._scene.activeCameras : [this._scene.activeCamera];
|
|
507
|
+
const worldMatrix = this.computeWorldMatrix(true);
|
|
508
|
+
let anyDirty = false;
|
|
509
|
+
for (const camera of cameras) {
|
|
510
|
+
if (!camera) {
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
const cameraViewInfo = this._cameraViewInfos.get(camera.uniqueId);
|
|
514
|
+
if (!cameraViewInfo || !cameraViewInfo.splatIndexBufferSet) {
|
|
515
|
+
anyDirty = true;
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
// Wait for the most recently requested sort to be applied so that the splat indices
|
|
519
|
+
// match the latest world/camera state.
|
|
520
|
+
if (cameraViewInfo.sortAppliedId !== cameraViewInfo.sortRequestId) {
|
|
521
|
+
anyDirty = true;
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
// Also detect drift: if the world or camera state has changed since the last post,
|
|
525
|
+
// mark dirty so the next render does not silently queue a new sort that completes
|
|
526
|
+
// after isReady has reported true.
|
|
527
|
+
if (this._isSortStateDirty(cameraViewInfo, worldMatrix, camera)) {
|
|
528
|
+
anyDirty = true;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (anyDirty) {
|
|
532
|
+
// Try to post any pending sort so subsequent polling iterations make progress.
|
|
533
|
+
this._postToWorker(true);
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// Attach the splat geometry to the GS top mesh so that the shadow generator (which renders
|
|
538
|
+
// shadow casters via the top mesh's subMeshes, NOT through this mesh's render() override)
|
|
539
|
+
// has valid geometry on the very first shadow pass. Without this, the first shadow render
|
|
540
|
+
// happens before render() is called and the GS produces no shadow caster output.
|
|
541
|
+
if (!this._geometry && this._cameraViewInfos.size) {
|
|
542
|
+
this._geometry = this._cameraViewInfos.values().next().value.mesh.geometry;
|
|
543
|
+
}
|
|
544
|
+
// If the material declares a shadow depth wrapper, make sure its effect is compiled for
|
|
545
|
+
// each subMesh against the scene's shadow generators. Otherwise the first shadow pass
|
|
546
|
+
// would be skipped (ShadowGenerator.isReady would return false) and we'd miss the shadow
|
|
547
|
+
// on a renderCount=1 capture.
|
|
548
|
+
if (this.material && this.material.shadowDepthWrapper) {
|
|
549
|
+
for (const light of this._scene.lights) {
|
|
550
|
+
const shadowGenerator = light.getShadowGenerator();
|
|
551
|
+
if (!shadowGenerator) {
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
for (const subMesh of this.subMeshes) {
|
|
555
|
+
if (!shadowGenerator.isReady(subMesh, true, false)) {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
499
561
|
return true;
|
|
500
562
|
}
|
|
501
563
|
_getCameraDirection(camera) {
|
|
@@ -503,7 +565,7 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
503
565
|
const cameraProjectionMatrix = camera.getProjectionMatrix();
|
|
504
566
|
const cameraViewProjectionMatrix = TmpVectors.Matrix[0];
|
|
505
567
|
cameraViewMatrix.multiplyToRef(cameraProjectionMatrix, cameraViewProjectionMatrix);
|
|
506
|
-
const modelMatrix = this.
|
|
568
|
+
const modelMatrix = this.computeWorldMatrix(true);
|
|
507
569
|
const modelViewMatrix = TmpVectors.Matrix[1];
|
|
508
570
|
modelMatrix.multiplyToRef(cameraViewMatrix, modelViewMatrix);
|
|
509
571
|
modelMatrix.multiplyToRef(cameraViewProjectionMatrix, this._modelViewProjectionMatrix);
|
|
@@ -513,6 +575,25 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
513
575
|
localDirection.normalize();
|
|
514
576
|
return localDirection;
|
|
515
577
|
}
|
|
578
|
+
_isSortStateDirty(cameraViewInfo, worldMatrix, camera) {
|
|
579
|
+
const world = worldMatrix.m;
|
|
580
|
+
const previousWorld = cameraViewInfo.sortWorldMatrix.m;
|
|
581
|
+
for (let i = 0; i < previousWorld.length; i++) {
|
|
582
|
+
if (!Scalar.WithinEpsilon(previousWorld[i], world[i], this.viewUpdateThreshold)) {
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
const cameraViewMatrix = camera.getViewMatrix();
|
|
587
|
+
if (!Scalar.WithinEpsilon(cameraViewInfo.sortCameraForward.x, cameraViewMatrix.m[2], this.viewUpdateThreshold) ||
|
|
588
|
+
!Scalar.WithinEpsilon(cameraViewInfo.sortCameraForward.y, cameraViewMatrix.m[6], this.viewUpdateThreshold) ||
|
|
589
|
+
!Scalar.WithinEpsilon(cameraViewInfo.sortCameraForward.z, cameraViewMatrix.m[10], this.viewUpdateThreshold)) {
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
const cameraPosition = camera.globalPosition;
|
|
593
|
+
return (!Scalar.WithinEpsilon(cameraViewInfo.sortCameraPosition.x, cameraPosition.x, this.viewUpdateThreshold) ||
|
|
594
|
+
!Scalar.WithinEpsilon(cameraViewInfo.sortCameraPosition.y, cameraPosition.y, this.viewUpdateThreshold) ||
|
|
595
|
+
!Scalar.WithinEpsilon(cameraViewInfo.sortCameraPosition.z, cameraPosition.z, this.viewUpdateThreshold));
|
|
596
|
+
}
|
|
516
597
|
/** @internal */
|
|
517
598
|
_postToWorker(forced = false) {
|
|
518
599
|
const scene = this._scene;
|
|
@@ -559,6 +640,11 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
559
640
|
const newViewInfos = {
|
|
560
641
|
camera: camera,
|
|
561
642
|
cameraDirection: new Vector3(0, 0, 0),
|
|
643
|
+
sortWorldMatrix: Matrix.Identity(),
|
|
644
|
+
sortCameraForward: new Vector3(0, 0, 0),
|
|
645
|
+
sortCameraPosition: new Vector3(0, 0, 0),
|
|
646
|
+
sortRequestId: 0,
|
|
647
|
+
sortAppliedId: 0,
|
|
562
648
|
mesh: cameraMesh,
|
|
563
649
|
frameIdLastUpdate: frameId,
|
|
564
650
|
splatIndexBufferSet: false,
|
|
@@ -567,28 +653,39 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
567
653
|
this._cameraViewInfos.set(cameraId, newViewInfos);
|
|
568
654
|
}
|
|
569
655
|
});
|
|
570
|
-
// sort view infos
|
|
571
|
-
|
|
656
|
+
// sort view infos: cameras without an initial splat-index buffer come first so they don't get starved
|
|
657
|
+
// by a `forced` re-sort of an already-initialized camera (which would consume `_canPostToWorker`).
|
|
658
|
+
// Among initialized cameras, the least recently updated comes first.
|
|
659
|
+
activeViewInfos.sort((a, b) => {
|
|
660
|
+
if (a.splatIndexBufferSet !== b.splatIndexBufferSet) {
|
|
661
|
+
return a.splatIndexBufferSet ? 1 : -1;
|
|
662
|
+
}
|
|
663
|
+
return a.frameIdLastUpdate - b.frameIdLastUpdate;
|
|
664
|
+
});
|
|
572
665
|
const hasSortFunction = this._worker || Native?.sortSplats || this._disableDepthSort;
|
|
573
666
|
if ((forced || outdated) && hasSortFunction && (this._scene.activeCameras?.length || this._scene.activeCamera) && this._canPostToWorker) {
|
|
667
|
+
const worldMatrix = this.computeWorldMatrix(true);
|
|
574
668
|
// view infos sorted by least recent updated frame id
|
|
575
669
|
activeViewInfos.forEach((cameraViewInfos) => {
|
|
576
670
|
const camera = cameraViewInfos.camera;
|
|
577
671
|
const cameraDirection = this._getCameraDirection(camera);
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
if ((forced || Math.abs(dot - 1) >= this.viewUpdateThreshold) && this._canPostToWorker) {
|
|
672
|
+
if ((forced || this._isSortStateDirty(cameraViewInfos, worldMatrix, camera)) && this._canPostToWorker) {
|
|
673
|
+
const cameraViewMatrix = camera.getViewMatrix();
|
|
581
674
|
cameraViewInfos.cameraDirection.copyFrom(cameraDirection);
|
|
675
|
+
cameraViewInfos.sortWorldMatrix.copyFrom(worldMatrix);
|
|
676
|
+
cameraViewInfos.sortCameraForward.set(cameraViewMatrix.m[2], cameraViewMatrix.m[6], cameraViewMatrix.m[10]);
|
|
677
|
+
cameraViewInfos.sortCameraPosition.copyFrom(camera.globalPosition);
|
|
678
|
+
cameraViewInfos.sortRequestId = ++this._sortRequestId;
|
|
582
679
|
cameraViewInfos.frameIdLastUpdate = frameId;
|
|
583
680
|
this._canPostToWorker = false;
|
|
584
681
|
if (this._worker) {
|
|
585
|
-
const cameraViewMatrix = camera.getViewMatrix();
|
|
586
682
|
this._worker.postMessage({
|
|
587
|
-
worldMatrix:
|
|
683
|
+
worldMatrix: worldMatrix.m,
|
|
588
684
|
cameraForward: [cameraViewMatrix.m[2], cameraViewMatrix.m[6], cameraViewMatrix.m[10]],
|
|
589
685
|
cameraPosition: [camera.globalPosition.x, camera.globalPosition.y, camera.globalPosition.z],
|
|
590
686
|
depthMix: this._depthMix,
|
|
591
687
|
cameraId: camera.uniqueId,
|
|
688
|
+
sortRequestId: cameraViewInfos.sortRequestId,
|
|
592
689
|
}, [this._depthMix.buffer]);
|
|
593
690
|
}
|
|
594
691
|
else if (Native?.sortSplats) {
|
|
@@ -600,6 +697,7 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
600
697
|
cameraViewInfos.mesh.thinInstanceSetBuffer("splatIndex", this._splatIndex, 16, false);
|
|
601
698
|
cameraViewInfos.splatIndexBufferSet = true;
|
|
602
699
|
}
|
|
700
|
+
cameraViewInfos.sortAppliedId = cameraViewInfos.sortRequestId;
|
|
603
701
|
this._canPostToWorker = true;
|
|
604
702
|
this._readyToDisplay = true;
|
|
605
703
|
}
|
|
@@ -650,6 +748,7 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
650
748
|
mesh.setMaterialForRenderPass(renderPassId, renderPassMaterial);
|
|
651
749
|
}
|
|
652
750
|
const ret = mesh.render(subMesh, enableAlphaMode, effectiveMeshReplacement);
|
|
751
|
+
this._hasRenderedOnce = true;
|
|
653
752
|
// Clean up the temporary override to avoid affecting other render passes
|
|
654
753
|
if (renderPassMaterial) {
|
|
655
754
|
mesh.setMaterialForRenderPass(renderPassId, undefined);
|
|
@@ -1459,6 +1558,7 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
1459
1558
|
newGS._modelViewProjectionMatrix = Matrix.Identity();
|
|
1460
1559
|
newGS._splatPositions = this._splatPositions;
|
|
1461
1560
|
newGS._readyToDisplay = false;
|
|
1561
|
+
newGS._hasRenderedOnce = false;
|
|
1462
1562
|
newGS._disableDepthSort = this._disableDepthSort;
|
|
1463
1563
|
newGS._instantiateWorker();
|
|
1464
1564
|
const binfo = this.getBoundingInfo();
|
|
@@ -1976,6 +2076,7 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
1976
2076
|
}
|
|
1977
2077
|
this._depthMix = e.data.depthMix;
|
|
1978
2078
|
const cameraId = e.data.cameraId;
|
|
2079
|
+
const sortRequestId = e.data.sortRequestId;
|
|
1979
2080
|
const indexMix = new Uint32Array(e.data.depthMix.buffer);
|
|
1980
2081
|
if (this._splatIndex) {
|
|
1981
2082
|
for (let j = 0; j < vertexCountPadded; j++) {
|
|
@@ -1997,6 +2098,7 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
1997
2098
|
cameraViewInfos.mesh.thinInstanceSetBuffer("splatIndex", this._splatIndex, 16, false);
|
|
1998
2099
|
cameraViewInfos.splatIndexBufferSet = true;
|
|
1999
2100
|
}
|
|
2101
|
+
cameraViewInfos.sortAppliedId = sortRequestId;
|
|
2000
2102
|
}
|
|
2001
2103
|
this._canPostToWorker = true;
|
|
2002
2104
|
this._readyToDisplay = true;
|
|
@@ -2184,13 +2286,14 @@ GaussianSplattingMeshBase._CreateWorker = function (self) {
|
|
|
2184
2286
|
// update on view changed
|
|
2185
2287
|
else {
|
|
2186
2288
|
const cameraId = e.data.cameraId;
|
|
2289
|
+
const sortRequestId = e.data.sortRequestId;
|
|
2187
2290
|
const globalWorldMatrix = e.data.worldMatrix;
|
|
2188
2291
|
const cameraForward = e.data.cameraForward;
|
|
2189
2292
|
const cameraPosition = e.data.cameraPosition;
|
|
2190
2293
|
depthMix = e.data.depthMix;
|
|
2191
2294
|
if (!positions || !cameraForward) {
|
|
2192
2295
|
// Sort request arrived before positions were initialized — return the buffer unchanged so the main thread can unlock _canPostToWorker.
|
|
2193
|
-
self.postMessage({ depthMix, cameraId }, [depthMix.buffer]);
|
|
2296
|
+
self.postMessage({ depthMix, cameraId, sortRequestId }, [depthMix.buffer]);
|
|
2194
2297
|
return;
|
|
2195
2298
|
}
|
|
2196
2299
|
const vertexCountPadded = (positions.length / 4 + 15) & ~0xf;
|
|
@@ -2243,7 +2346,7 @@ GaussianSplattingMeshBase._CreateWorker = function (self) {
|
|
|
2243
2346
|
// eslint-disable-next-line no-console
|
|
2244
2347
|
console.error("Gaussian splat sort worker encountered an error (will retry next frame):", sortError);
|
|
2245
2348
|
}
|
|
2246
|
-
self.postMessage({ depthMix, cameraId }, [depthMix.buffer]);
|
|
2349
|
+
self.postMessage({ depthMix, cameraId, sortRequestId }, [depthMix.buffer]);
|
|
2247
2350
|
}
|
|
2248
2351
|
};
|
|
2249
2352
|
};
|