@babylonjs/core 8.0.2 → 8.0.3

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.
Files changed (44) hide show
  1. package/AudioV2/abstractAudio/subNodes/audioAnalyzerSubNode.d.ts +0 -2
  2. package/AudioV2/abstractAudio/subNodes/audioAnalyzerSubNode.js +0 -4
  3. package/AudioV2/abstractAudio/subNodes/audioAnalyzerSubNode.js.map +1 -1
  4. package/AudioV2/abstractAudio/subNodes/spatialAudioSubNode.d.ts +0 -2
  5. package/AudioV2/abstractAudio/subNodes/spatialAudioSubNode.js +0 -4
  6. package/AudioV2/abstractAudio/subNodes/spatialAudioSubNode.js.map +1 -1
  7. package/AudioV2/abstractAudio/subNodes/stereoAudioSubNode.d.ts +0 -2
  8. package/AudioV2/abstractAudio/subNodes/stereoAudioSubNode.js +0 -4
  9. package/AudioV2/abstractAudio/subNodes/stereoAudioSubNode.js.map +1 -1
  10. package/AudioV2/abstractAudio/subProperties/audioAnalyzer.d.ts +4 -0
  11. package/AudioV2/abstractAudio/subProperties/audioAnalyzer.js +14 -6
  12. package/AudioV2/abstractAudio/subProperties/audioAnalyzer.js.map +1 -1
  13. package/AudioV2/abstractAudio/subProperties/spatialAudio.d.ts +8 -0
  14. package/AudioV2/abstractAudio/subProperties/spatialAudio.js +25 -9
  15. package/AudioV2/abstractAudio/subProperties/spatialAudio.js.map +1 -1
  16. package/AudioV2/abstractAudio/subProperties/stereoAudio.d.ts +1 -0
  17. package/AudioV2/abstractAudio/subProperties/stereoAudio.js +5 -3
  18. package/AudioV2/abstractAudio/subProperties/stereoAudio.js.map +1 -1
  19. package/Cameras/arcRotateCamera.d.ts +13 -3
  20. package/Cameras/arcRotateCamera.js +121 -46
  21. package/Cameras/arcRotateCamera.js.map +1 -1
  22. package/Engines/ICanvas.d.ts +4 -0
  23. package/Engines/ICanvas.js.map +1 -1
  24. package/Engines/abstractEngine.js +2 -2
  25. package/Engines/abstractEngine.js.map +1 -1
  26. package/Materials/Node/Blocks/colorConverterBlock.d.ts +1 -0
  27. package/Materials/Node/Blocks/colorConverterBlock.js +9 -0
  28. package/Materials/Node/Blocks/colorConverterBlock.js.map +1 -1
  29. package/Materials/Node/Blocks/colorMergerBlock.d.ts +1 -0
  30. package/Materials/Node/Blocks/colorMergerBlock.js +6 -0
  31. package/Materials/Node/Blocks/colorMergerBlock.js.map +1 -1
  32. package/Materials/Textures/renderTargetTexture.d.ts +2 -2
  33. package/Materials/Textures/renderTargetTexture.js.map +1 -1
  34. package/Materials/uniformBuffer.js +3 -0
  35. package/Materials/uniformBuffer.js.map +1 -1
  36. package/Rendering/objectRenderer.d.ts +4 -3
  37. package/Rendering/objectRenderer.js +10 -5
  38. package/Rendering/objectRenderer.js.map +1 -1
  39. package/ShadersWGSL/ShadersInclude/pbrBlockReflection.js +1 -1
  40. package/ShadersWGSL/ShadersInclude/pbrBlockReflection.js.map +1 -1
  41. package/index.d.ts +1 -0
  42. package/index.js +1 -0
  43. package/index.js.map +1 -1
  44. package/package.json +1 -1
@@ -42,6 +42,10 @@ export function ComputeAlpha(offset) {
42
42
  export function ComputeBeta(verticalOffset, radius) {
43
43
  return Math.acos(verticalOffset / radius);
44
44
  }
45
+ // Returns the value if not NaN, otherwise returns the fallback value.
46
+ function checkNaN(value, fallback) {
47
+ return isNaN(value) ? fallback : value;
48
+ }
45
49
  /**
46
50
  * This represents an orbital type of camera.
47
51
  *
@@ -334,6 +338,12 @@ export class ArcRotateCamera extends TargetCamera {
334
338
  mousewheel.wheelDeltaPercentage = value;
335
339
  }
336
340
  }
341
+ /**
342
+ * If true, indicates the camera is currently interpolating to a new pose.
343
+ */
344
+ get isInterpolating() {
345
+ return this._isInterpolating;
346
+ }
337
347
  /**
338
348
  * Gets the bouncing behavior of the camera if it has been enabled.
339
349
  * @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#bouncing-behavior
@@ -539,8 +549,8 @@ export class ArcRotateCamera extends TargetCamera {
539
549
  * Defines if camera will eliminate transform on y axis.
540
550
  */
541
551
  this.mapPanning = false;
542
- // restoring state progressively
543
- this._progressiveRestore = false;
552
+ // This is redundant with all _goal* properties being NaN, but we track it anyway because we check for active interpolation in the hot path.
553
+ this._isInterpolating = false;
544
554
  /**
545
555
  * Observable triggered when the transform node target has been changed on the camera.
546
556
  */
@@ -560,6 +570,11 @@ export class ArcRotateCamera extends TargetCamera {
560
570
  this._collisionVelocity = Vector3.Zero();
561
571
  this._newPosition = Vector3.Zero();
562
572
  this._computationVector = Vector3.Zero();
573
+ this._goalAlpha = NaN;
574
+ this._goalBeta = NaN;
575
+ this._goalRadius = NaN;
576
+ this._goalTarget = new Vector3(NaN, NaN, NaN);
577
+ this._goalTargetScreenOffset = new Vector2(NaN, NaN);
563
578
  this._onCollisionPositionChange = (collisionId, newPosition, collidedMesh = null) => {
564
579
  if (!collidedMesh) {
565
580
  this._previousPosition.copyFrom(this._position);
@@ -647,11 +662,11 @@ export class ArcRotateCamera extends TargetCamera {
647
662
  * @returns the camera itself
648
663
  */
649
664
  storeState() {
650
- this._storedAlpha = this._goalAlpha = this.alpha;
651
- this._storedBeta = this._goalBeta = this.beta;
652
- this._storedRadius = this._goalRadius = this.radius;
653
- this._storedTarget = this._goalTarget = this._getTargetPosition().clone();
654
- this._storedTargetScreenOffset = this._goalTargetScreenOffset = this.targetScreenOffset.clone();
665
+ this._storedAlpha = this.alpha;
666
+ this._storedBeta = this.beta;
667
+ this._storedRadius = this.radius;
668
+ this._storedTarget = this._getTargetPosition().clone();
669
+ this._storedTargetScreenOffset = this.targetScreenOffset.clone();
655
670
  return super.storeState();
656
671
  }
657
672
  /**
@@ -678,6 +693,16 @@ export class ArcRotateCamera extends TargetCamera {
678
693
  this.inertialPanningY = 0;
679
694
  return true;
680
695
  }
696
+ /**
697
+ * Stops any in-progress interpolation.
698
+ */
699
+ stopInterpolation() {
700
+ this._goalAlpha = NaN;
701
+ this._goalBeta = NaN;
702
+ this._goalRadius = NaN;
703
+ this._goalTarget.set(NaN, NaN, NaN);
704
+ this._goalTargetScreenOffset.set(NaN, NaN);
705
+ }
681
706
  /**
682
707
  * Interpolates the camera to a goal state.
683
708
  * @param alpha Defines the goal alpha.
@@ -686,9 +711,10 @@ export class ArcRotateCamera extends TargetCamera {
686
711
  * @param target Defines the goal target.
687
712
  * @param targetScreenOffset Defines the goal target screen offset.
688
713
  * @param interpolationFactor A value between 0 and 1 that determines the speed of the interpolation.
714
+ * @remarks Passing undefined for any of the parameters will use the current value (effectively stopping any in-progress interpolation for that parameter).
715
+ * Passing NaN will not start or stop any interpolation for that parameter (effectively allowing multiple interpolations of different parameters to overlap).
689
716
  */
690
717
  interpolateTo(alpha = this.alpha, beta = this.beta, radius = this.radius, target = this.target, targetScreenOffset = this.targetScreenOffset, interpolationFactor) {
691
- this._progressiveRestore = true;
692
718
  this.inertialAlphaOffset = 0;
693
719
  this.inertialBetaOffset = 0;
694
720
  this.inertialRadiusOffset = 0;
@@ -703,15 +729,17 @@ export class ArcRotateCamera extends TargetCamera {
703
729
  else {
704
730
  this._currentInterpolationFactor = 0.1;
705
731
  }
706
- alpha = Clamp(alpha, this.lowerAlphaLimit ?? -Infinity, this.upperAlphaLimit ?? Infinity);
707
- beta = Clamp(beta, this.lowerBetaLimit ?? -Infinity, this.upperBetaLimit ?? Infinity);
708
- radius = Clamp(radius, this.lowerRadiusLimit ?? -Infinity, this.upperRadiusLimit ?? Infinity);
709
- target.y = Clamp(target.y, this.lowerTargetYLimit ?? -Infinity, Infinity);
710
- this._goalAlpha = alpha;
711
- this._goalBeta = beta;
712
- this._goalRadius = radius;
713
- this._goalTarget = target;
714
- this._goalTargetScreenOffset = targetScreenOffset;
732
+ // If NaN is passed in for a goal value, keep the current goal value.
733
+ this._goalAlpha = checkNaN(alpha, this._goalAlpha);
734
+ this._goalBeta = checkNaN(beta, this._goalBeta);
735
+ this._goalRadius = checkNaN(radius, this._goalRadius);
736
+ this._goalTarget.set(checkNaN(target.x, this._goalTarget.x), checkNaN(target.y, this._goalTarget.y), checkNaN(target.z, this._goalTarget.z));
737
+ this._goalTargetScreenOffset.set(checkNaN(targetScreenOffset.x, this._goalTargetScreenOffset.x), checkNaN(targetScreenOffset.y, this._goalTargetScreenOffset.y));
738
+ this._goalAlpha = Clamp(this._goalAlpha, this.lowerAlphaLimit ?? -Infinity, this.upperAlphaLimit ?? Infinity);
739
+ this._goalBeta = Clamp(this._goalBeta, this.lowerBetaLimit ?? -Infinity, this.upperBetaLimit ?? Infinity);
740
+ this._goalRadius = Clamp(this._goalRadius, this.lowerRadiusLimit ?? -Infinity, this.upperRadiusLimit ?? Infinity);
741
+ this._goalTarget.y = Clamp(this._goalTarget.y, this.lowerTargetYLimit ?? -Infinity, Infinity);
742
+ this._isInterpolating = true;
715
743
  }
716
744
  // Synchronized
717
745
  /** @internal */
@@ -772,37 +800,10 @@ export class ArcRotateCamera extends TargetCamera {
772
800
  return;
773
801
  }
774
802
  this.inputs.checkInputs();
775
- // progressive restore
776
- if (this._progressiveRestore) {
777
- const dt = this._scene.getEngine().getDeltaTime() / 1000;
778
- const t = 1 - Math.pow(2, -dt / this._currentInterpolationFactor);
779
- // can't use tmp vector here because of assignment
780
- this.setTarget(Vector3.Lerp(this.getTarget(), this._goalTarget, t));
781
- // Using quaternion for smoother interpolation (and no Euler angles modulo)
782
- Quaternion.RotationAlphaBetaGammaToRef(this._goalAlpha, this._goalBeta, 0, TmpVectors.Quaternion[0]);
783
- Quaternion.RotationAlphaBetaGammaToRef(this.alpha, this.beta, 0, TmpVectors.Quaternion[1]);
784
- Quaternion.SlerpToRef(TmpVectors.Quaternion[1], TmpVectors.Quaternion[0], t, TmpVectors.Quaternion[2]);
785
- TmpVectors.Quaternion[2].normalize();
786
- TmpVectors.Quaternion[2].toAlphaBetaGammaToRef(TmpVectors.Vector3[0]);
787
- this.alpha = TmpVectors.Vector3[0].x;
788
- this.beta = TmpVectors.Vector3[0].y;
789
- this.radius += (this._goalRadius - this.radius) * t;
790
- Vector2.LerpToRef(this.targetScreenOffset, this._goalTargetScreenOffset, t, this.targetScreenOffset);
791
- // stop restoring when within close range or when user starts interacting
792
- if ((Vector3.DistanceSquared(this.getTarget(), this._goalTarget) < Epsilon &&
793
- TmpVectors.Quaternion[2].isApprox(TmpVectors.Quaternion[0]) &&
794
- Math.pow(this._goalRadius - this.radius, 2) < Epsilon &&
795
- Vector2.Distance(this.targetScreenOffset, this._goalTargetScreenOffset) < Epsilon) ||
796
- this.inertialAlphaOffset !== 0 ||
797
- this.inertialBetaOffset !== 0 ||
798
- this.inertialRadiusOffset !== 0 ||
799
- this.inertialPanningX !== 0 ||
800
- this.inertialPanningY !== 0) {
801
- this._progressiveRestore = false;
802
- }
803
- }
803
+ let hasUserInteractions = false;
804
804
  // Inertia
805
805
  if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset !== 0) {
806
+ hasUserInteractions = true;
806
807
  const directionModifier = this.invertRotation ? -1 : 1;
807
808
  const handednessMultiplier = this._calculateHandednessMultiplier();
808
809
  let inertialAlphaOffset = this.inertialAlphaOffset * handednessMultiplier;
@@ -827,6 +828,7 @@ export class ArcRotateCamera extends TargetCamera {
827
828
  }
828
829
  // Panning inertia
829
830
  if (this.inertialPanningX !== 0 || this.inertialPanningY !== 0) {
831
+ hasUserInteractions = true;
830
832
  const localDirection = new Vector3(this.inertialPanningX, this.inertialPanningY, this.inertialPanningY);
831
833
  this._viewMatrix.invertToRef(this._cameraTransformMatrix);
832
834
  localDirection.multiplyInPlace(this.panningAxis);
@@ -868,6 +870,79 @@ export class ArcRotateCamera extends TargetCamera {
868
870
  this.inertialPanningY = 0;
869
871
  }
870
872
  }
873
+ if (hasUserInteractions) {
874
+ this.stopInterpolation();
875
+ }
876
+ else if (this._isInterpolating) {
877
+ let isInterpolating = false;
878
+ const dt = this._scene.getEngine().getDeltaTime() / 1000;
879
+ const t = 1 - Math.pow(2, -dt / this._currentInterpolationFactor);
880
+ // NOTE: If the goal is NaN, it means we are not interpolating to a new value, so we can use the current value. Hence the calls to checkNaN.
881
+ // Get the goal radius immediately as we'll need it for determining interpolation termination for the target.
882
+ const goalRadius = checkNaN(this._goalRadius, this.radius);
883
+ // Interpolate the target if we haven't reached the goal yet.
884
+ if (!isNaN(this._goalTarget.x) || !isNaN(this._goalTarget.y) || !isNaN(this._goalTarget.z)) {
885
+ const goalTarget = TmpVectors.Vector3[0].set(checkNaN(this._goalTarget.x, this._target.x), checkNaN(this._goalTarget.y, this._target.y), checkNaN(this._goalTarget.z, this._target.z));
886
+ this.setTarget(Vector3.Lerp(this.target, goalTarget, t), undefined, undefined, true);
887
+ // Terminate the target interpolation if we the target is close relative to the radius.
888
+ // This is when visually (regardless of scale) the target appears close to its final goal position.
889
+ if ((Vector3.Distance(this.target, goalTarget) * 10) / goalRadius < Epsilon) {
890
+ this._goalTarget.set(NaN, NaN, NaN);
891
+ this.setTarget(goalTarget.clone(), undefined, undefined, true);
892
+ }
893
+ else {
894
+ isInterpolating = true;
895
+ }
896
+ }
897
+ // Interpolate the rotation if we haven't reached the goal yet.
898
+ if (!isNaN(this._goalAlpha) || !isNaN(this._goalBeta)) {
899
+ // Using quaternion for smoother interpolation (and no Euler angles modulo)
900
+ const goalRotation = Quaternion.RotationAlphaBetaGammaToRef(checkNaN(this._goalAlpha, this.alpha), checkNaN(this._goalBeta, this.beta), 0, TmpVectors.Quaternion[0]);
901
+ const currentRotation = Quaternion.RotationAlphaBetaGammaToRef(this.alpha, this.beta, 0, TmpVectors.Quaternion[1]);
902
+ const newRotation = Quaternion.SlerpToRef(currentRotation, goalRotation, t, TmpVectors.Quaternion[2]);
903
+ newRotation.normalize();
904
+ const newAlphaBetaGamma = newRotation.toAlphaBetaGammaToRef(TmpVectors.Vector3[0]);
905
+ this.alpha = newAlphaBetaGamma.x;
906
+ this.beta = newAlphaBetaGamma.y;
907
+ // Terminate the rotation interpolation when the rotation appears visually close to the final goal rotation.
908
+ if (newRotation.isApprox(goalRotation, Epsilon / 5)) {
909
+ this._goalAlpha = NaN;
910
+ this._goalBeta = NaN;
911
+ const goalAlphaBetaGamma = goalRotation.toAlphaBetaGammaToRef(TmpVectors.Vector3[0]);
912
+ this.alpha = goalAlphaBetaGamma.x;
913
+ this.beta = goalAlphaBetaGamma.y;
914
+ }
915
+ else {
916
+ isInterpolating = true;
917
+ }
918
+ }
919
+ // Interpolate the radius if we haven't reached the goal yet.
920
+ if (!isNaN(this._goalRadius)) {
921
+ this.radius += (goalRadius - this.radius) * t;
922
+ // Terminate the radius interpolation when we are 99.9% of the way to the goal radius, at which point it is visually indistinguishable from the goal.
923
+ if (Math.abs(goalRadius / this.radius - 1) < Epsilon) {
924
+ this._goalRadius = NaN;
925
+ this.radius = goalRadius;
926
+ }
927
+ else {
928
+ isInterpolating = true;
929
+ }
930
+ }
931
+ // Interpolate the target screen offset if we haven't reached the goal yet.
932
+ if (!isNaN(this._goalTargetScreenOffset.x) || !isNaN(this._goalTargetScreenOffset.y)) {
933
+ const goalTargetScreenOffset = TmpVectors.Vector2[0].set(checkNaN(this._goalTargetScreenOffset.x, this.targetScreenOffset.x), checkNaN(this._goalTargetScreenOffset.y, this.targetScreenOffset.y));
934
+ Vector2.LerpToRef(this.targetScreenOffset, goalTargetScreenOffset, t, this.targetScreenOffset);
935
+ // Terminate the target screen offset interpolation when the target screen offset appears visually close to the final goal target screen offset.
936
+ if (Vector2.Distance(this.targetScreenOffset, goalTargetScreenOffset) < Epsilon) {
937
+ this._goalTargetScreenOffset.set(NaN, NaN);
938
+ this.targetScreenOffset.copyFrom(goalTargetScreenOffset);
939
+ }
940
+ else {
941
+ isInterpolating = true;
942
+ }
943
+ }
944
+ this._isInterpolating = isInterpolating;
945
+ }
871
946
  // Limits
872
947
  this._checkLimits();
873
948
  super._checkInputs();