@konitif/viewer-3d 0.285.6 → 0.285.8

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 (42) hide show
  1. package/README.md +15 -0
  2. package/dist/renderer/CameraController.d.ts +3 -0
  3. package/dist/renderer/CameraController.d.ts.map +1 -1
  4. package/dist/renderer/CameraController.js +36 -24
  5. package/dist/renderer/CameraController.js.map +1 -1
  6. package/dist/renderer/CardinalGridLayer.d.ts +22 -0
  7. package/dist/renderer/CardinalGridLayer.d.ts.map +1 -0
  8. package/dist/renderer/CardinalGridLayer.js +127 -0
  9. package/dist/renderer/CardinalGridLayer.js.map +1 -0
  10. package/dist/renderer/OrthographicGroundReflection.d.ts +5 -0
  11. package/dist/renderer/OrthographicGroundReflection.d.ts.map +1 -0
  12. package/dist/renderer/OrthographicGroundReflection.js +58 -0
  13. package/dist/renderer/OrthographicGroundReflection.js.map +1 -0
  14. package/dist/renderer/PerformanceObservation.d.ts +8 -0
  15. package/dist/renderer/PerformanceObservation.d.ts.map +1 -0
  16. package/dist/renderer/PerformanceObservation.js +21 -0
  17. package/dist/renderer/PerformanceObservation.js.map +1 -0
  18. package/dist/renderer/SceneAstronomy.d.ts +34 -0
  19. package/dist/renderer/SceneAstronomy.d.ts.map +1 -0
  20. package/dist/renderer/SceneAstronomy.js +96 -0
  21. package/dist/renderer/SceneAstronomy.js.map +1 -0
  22. package/dist/renderer/SceneDayCycle.d.ts +21 -0
  23. package/dist/renderer/SceneDayCycle.d.ts.map +1 -0
  24. package/dist/renderer/SceneDayCycle.js +27 -0
  25. package/dist/renderer/SceneDayCycle.js.map +1 -0
  26. package/dist/renderer/SceneEnvironmentLayer.d.ts +26 -0
  27. package/dist/renderer/SceneEnvironmentLayer.d.ts.map +1 -0
  28. package/dist/renderer/SceneEnvironmentLayer.js +89 -0
  29. package/dist/renderer/SceneEnvironmentLayer.js.map +1 -0
  30. package/dist/renderer/Viewer3DRenderer.d.ts +30 -1
  31. package/dist/renderer/Viewer3DRenderer.d.ts.map +1 -1
  32. package/dist/renderer/Viewer3DRenderer.js +74 -11
  33. package/dist/renderer/Viewer3DRenderer.js.map +1 -1
  34. package/dist/renderer/VisualGroundLayer.d.ts.map +1 -1
  35. package/dist/renderer/VisualGroundLayer.js +37 -5
  36. package/dist/renderer/VisualGroundLayer.js.map +1 -1
  37. package/dist/renderer/index.d.ts +2 -0
  38. package/dist/renderer/index.d.ts.map +1 -1
  39. package/dist/renderer/index.js +2 -0
  40. package/dist/renderer/index.js.map +1 -1
  41. package/package.json +1 -1
  42. package/reference/catalog.json +10 -0
@@ -1,3 +1,6 @@
1
+ import { ViewerCardinalGridLayer } from './CardinalGridLayer.js';
2
+ import { ViewerSceneEnvironmentLayer } from './SceneEnvironmentLayer.js';
3
+ import { measureViewerOperation } from './PerformanceObservation.js';
1
4
  import { createViewerPhysicsFrameQuaternion, resolveViewerSceneYaw, projectViewerImpulseByFrame, projectViewerPointByFrame } from './physics/ViewerPhysicsFrame.js';
2
5
  import { resolveViewerJointMapping, selectDirectViewerJointMappings } from './physics/ViewerJointResolution.js';
3
6
  import { createPhysicsJointTargetValue, createVisualJointValueFromPhysics, createVisualJointValueFromSource } from './physics/ViewerPhysicsJointMapping.js';
@@ -257,6 +260,9 @@ export class Viewer3D {
257
260
  gridHelper = null;
258
261
  visualGroundLayer = null;
259
262
  keyLight = null;
263
+ cardinalGrid = null;
264
+ sceneDayCycle = null;
265
+ sceneFog = null;
260
266
  trajectoryGroup = null;
261
267
  contactPointGroup = null;
262
268
  physicsDebugGroup = null;
@@ -700,6 +706,12 @@ export class Viewer3D {
700
706
  }
701
707
  this.scheduleLoop();
702
708
  }
709
+ /** Signal a projection-only change made to caller-owned scene contributions.
710
+ * Uses the viewer's existing coalesced frame loop; does not advance simulation or transport.
711
+ */
712
+ requestPresentationFrame() {
713
+ this.requestRender();
714
+ }
703
715
  setStatsVisible(showStats) {
704
716
  if (this.options.showStats === showStats) {
705
717
  return;
@@ -729,6 +741,31 @@ export class Viewer3D {
729
741
  this.globalRafProbeFrame = 0;
730
742
  }
731
743
  }
744
+ /** Set a static local solar time; the caller owns persistence and playback. */
745
+ setSceneTimeHours(timeHours) {
746
+ this.sceneDayCycle ??= new ViewerSceneEnvironmentLayer(this.scene, this.renderer, this.keyLight, () => this.requestRender(), this.options.transparent);
747
+ this.sceneDayCycle.setFog(this.sceneFog);
748
+ this.sceneDayCycle.setTime(timeHours);
749
+ }
750
+ /** A null density delegates to the environment. Manual density survives day/night and theme changes. */
751
+ setSceneFog(settings) {
752
+ this.sceneFog = settings ? { enabled: settings.enabled, density: typeof settings.density === 'number' && Number.isFinite(settings.density) ? Math.max(0, Math.min(.5, settings.density)) : null } : null;
753
+ if (this.sceneDayCycle)
754
+ this.sceneDayCycle.setFog(this.sceneFog);
755
+ else
756
+ this.updateVisualGroundEnvironment();
757
+ this.requestRender();
758
+ }
759
+ setCardinalGridVisible(visible) {
760
+ if (visible)
761
+ this.cardinalGrid ??= new ViewerCardinalGridLayer(this.scene, () => this.controls.target, this.renderer.domElement.parentElement ?? undefined);
762
+ else {
763
+ this.cardinalGrid?.dispose();
764
+ this.cardinalGrid = null;
765
+ }
766
+ this.requestRender();
767
+ }
768
+ clearSceneTimeHours() { this.sceneDayCycle?.dispose(); this.sceneDayCycle = null; this.applyTheme(); }
732
769
  setGridVisible(showGrid) {
733
770
  if (this.options.showGrid === showGrid) {
734
771
  return;
@@ -1453,6 +1490,11 @@ export class Viewer3D {
1453
1490
  getPerformanceSummary() {
1454
1491
  return this.performanceMonitor.getSummary();
1455
1492
  }
1493
+ performanceObserver = null;
1494
+ /** Borrowed, optional sink. Does not allocate a loop, timer or browser observer. */
1495
+ setPerformanceObserver(observer) {
1496
+ this.performanceObserver = observer;
1497
+ }
1456
1498
  setTemporalProjectionMode(mode) {
1457
1499
  if (this.temporalProjection.getMode() === mode) {
1458
1500
  return;
@@ -3144,6 +3186,11 @@ export class Viewer3D {
3144
3186
  this.requestRender();
3145
3187
  }
3146
3188
  destroy(options = {}) {
3189
+ this.cardinalGrid?.dispose();
3190
+ this.cardinalGrid = null;
3191
+ this.sceneDayCycle?.dispose();
3192
+ this.sceneDayCycle = null;
3193
+ this.performanceObserver = null;
3147
3194
  if (this.destroyed) {
3148
3195
  return;
3149
3196
  }
@@ -3309,14 +3356,14 @@ export class Viewer3D {
3309
3356
  }
3310
3357
  this.updateVisualGroundShadowCasters();
3311
3358
  this.updateVisualGroundFocusTiltPasses();
3312
- const fogEnabled = this.options.showVisualGround && (config?.components.fogFade ?? true);
3359
+ const fogEnabled = this.sceneFog?.enabled ?? (this.options.showVisualGround && (config?.components.fogFade ?? true));
3313
3360
  if (!fogEnabled || this.options.transparent) {
3314
3361
  this.scene.fog = null;
3315
3362
  return;
3316
3363
  }
3317
3364
  const themeBackgroundColor = this.resolveThemeColor('--color-background-canvas', '#111722');
3318
3365
  const fogColor = this.resolveVisualGroundSkyColor(themeBackgroundColor);
3319
- const fogDensity = config?.fogDensity ?? DEFAULT_VIEWER_VISUAL_GROUND_CONFIG.fogDensity;
3366
+ const fogDensity = this.sceneFog?.density ?? config?.fogDensity ?? DEFAULT_VIEWER_VISUAL_GROUND_CONFIG.fogDensity;
3320
3367
  if (this.scene.fog instanceof FogExp2) {
3321
3368
  // Preserve the same fog authority while Viewer settings react. Replacing
3322
3369
  // the object on every layer update invalidated material state and could
@@ -3438,6 +3485,7 @@ export class Viewer3D {
3438
3485
  if (this.scene.fog instanceof FogExp2) {
3439
3486
  this.scene.fog.color.copy(backgroundColor);
3440
3487
  }
3488
+ this.sceneDayCycle?.apply();
3441
3489
  if (!this.gridHelper) {
3442
3490
  this.requestRender();
3443
3491
  return;
@@ -3668,7 +3716,10 @@ export class Viewer3D {
3668
3716
  this.perspectiveCamera.near = planes.near;
3669
3717
  this.perspectiveCamera.far = planes.far;
3670
3718
  this.perspectiveCamera.updateProjectionMatrix();
3671
- this.orthographicCamera.near = planes.near;
3719
+ // Orthographic projection has no perspective eye plane. Include geometry
3720
+ // on both sides of the camera plane, especially the foreground floor
3721
+ // at grazing angles; otherwise it is sliced by a positive near plane.
3722
+ this.orthographicCamera.near = -planes.far;
3672
3723
  this.orthographicCamera.far = planes.far;
3673
3724
  this.orthographicCamera.updateProjectionMatrix();
3674
3725
  }
@@ -3936,6 +3987,9 @@ export class Viewer3D {
3936
3987
  if (!this.animationLoop.beginFrame()) {
3937
3988
  return;
3938
3989
  }
3990
+ measureViewerOperation(this.performanceObserver, 'viewer.loop.cpu', () => this.runFrame());
3991
+ };
3992
+ runFrame() {
3939
3993
  const loopStartedAt = performance.now();
3940
3994
  const rafNow = loopStartedAt;
3941
3995
  this.temporalScheduler.frame(rafNow / 1000);
@@ -4012,7 +4066,7 @@ export class Viewer3D {
4012
4066
  const controlsStartedAt = performance.now();
4013
4067
  const shouldUpdateControls = this.controls.enabled && (this.controlsActive || this.controlsSettlingFrames > 0);
4014
4068
  if (shouldUpdateControls) {
4015
- this.controls.update();
4069
+ measureViewerOperation(this.performanceObserver, 'viewer.controls.cpu', () => this.controls.update());
4016
4070
  }
4017
4071
  if (shouldUpdateControls) {
4018
4072
  this.markFrameSignal('controls');
@@ -4097,8 +4151,12 @@ export class Viewer3D {
4097
4151
  if (shouldContinueLoop && this.animationLoop.isIdle()) {
4098
4152
  this.scheduleLoop();
4099
4153
  }
4100
- };
4154
+ }
4101
4155
  render() {
4156
+ measureViewerOperation(this.performanceObserver, 'viewer.draw.cpu', () => this.renderScene());
4157
+ }
4158
+ renderScene() {
4159
+ this.cardinalGrid?.update(this.camera);
4102
4160
  this.projectComparisonSimulation();
4103
4161
  if (this.observedRobotGhostMirrorsSimulatedRobot) {
4104
4162
  this.syncObservedRobotGhostFromSimulatedRobot();
@@ -4814,6 +4872,11 @@ export class Viewer3D {
4814
4872
  : undefined
4815
4873
  };
4816
4874
  }
4875
+ /** Invalidate the on-demand projection after caller-owned scene changes. */
4876
+ notifySceneChanged() {
4877
+ if (!this.destroyed)
4878
+ this.requestRender();
4879
+ }
4817
4880
  requestRender() {
4818
4881
  this.animationLoop.requestRender();
4819
4882
  }
@@ -11063,8 +11126,8 @@ export class Viewer3D {
11063
11126
  this.updateViewerDebugLayers({ poseHandles: true });
11064
11127
  }
11065
11128
  setCameraPose(position, target = this.options.cameraTarget, up) {
11066
- if (this.options.cameraControlMode === 'orbit') {
11067
- const worldUpPose = resolveWorldUpCameraPose(new Vector3(position.x, position.y, position.z), new Vector3(target.x, target.y, target.z), up ? new Vector3(up.x, up.y, up.z) : this.camera.up);
11129
+ if (this.options.cameraControlMode === 'orbit' && !up) {
11130
+ const worldUpPose = resolveWorldUpCameraPose(new Vector3(position.x, position.y, position.z), new Vector3(target.x, target.y, target.z), this.camera.up);
11068
11131
  this.cameraController.setCameraPose(this.serializeCameraVector(worldUpPose.position), target, this.serializeCameraVector(worldUpPose.up));
11069
11132
  return;
11070
11133
  }
@@ -11108,13 +11171,13 @@ export class Viewer3D {
11108
11171
  z: Number(vector.z.toFixed(4))
11109
11172
  };
11110
11173
  }
11111
- transitionCameraPose(position, target = this.options.cameraTarget, durationMs = 420, up) {
11112
- if (this.options.cameraControlMode === 'orbit') {
11174
+ transitionCameraPose(position, target = this.options.cameraTarget, durationMs = 420, up, transition = {}) {
11175
+ if (this.options.cameraControlMode === 'orbit' && !transition.orbit) {
11113
11176
  const worldUpPose = resolveWorldUpCameraPose(new Vector3(position.x, position.y, position.z), new Vector3(target.x, target.y, target.z), up ? new Vector3(up.x, up.y, up.z) : this.camera.up);
11114
- this.cameraController.transitionCameraPose(this.serializeCameraVector(worldUpPose.position), target, durationMs, this.serializeCameraVector(worldUpPose.up));
11177
+ this.cameraController.transitionCameraPose(this.serializeCameraVector(worldUpPose.position), target, durationMs, this.serializeCameraVector(worldUpPose.up), transition);
11115
11178
  return;
11116
11179
  }
11117
- this.cameraController.transitionCameraPose(position, target, durationMs, up);
11180
+ this.cameraController.transitionCameraPose(position, target, durationMs, up, transition);
11118
11181
  }
11119
11182
  resetCameraView(durationMs = 520) {
11120
11183
  this.transitionCameraPose(VIEWER3D_DEFAULT_CAMERA_POSITION, VIEWER3D_DEFAULT_CAMERA_TARGET, durationMs, {