@needle-tools/engine 3.0.1-alpha.4 → 3.1.0-alpha

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 (146) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/needle-engine.js +13110 -12429
  3. package/dist/needle-engine.min.js +378 -365
  4. package/dist/needle-engine.umd.cjs +366 -353
  5. package/lib/engine/api.d.ts +2 -1
  6. package/lib/engine/api.js +2 -1
  7. package/lib/engine/api.js.map +1 -1
  8. package/lib/engine/codegen/register_types.js +8 -0
  9. package/lib/engine/codegen/register_types.js.map +1 -1
  10. package/lib/engine/debug/debug_overlay.js +3 -0
  11. package/lib/engine/debug/debug_overlay.js.map +1 -1
  12. package/lib/engine/engine_addressables.d.ts +21 -1
  13. package/lib/engine/engine_addressables.js +83 -7
  14. package/lib/engine/engine_addressables.js.map +1 -1
  15. package/lib/engine/engine_context.d.ts +2 -0
  16. package/lib/engine/engine_context.js +3 -0
  17. package/lib/engine/engine_context.js.map +1 -1
  18. package/lib/engine/engine_element.d.ts +1 -1
  19. package/lib/engine/engine_element.js +2 -2
  20. package/lib/engine/engine_element.js.map +1 -1
  21. package/lib/engine/engine_element_loading.d.ts +7 -2
  22. package/lib/engine/engine_element_loading.js +67 -22
  23. package/lib/engine/engine_element_loading.js.map +1 -1
  24. package/lib/engine/engine_license.d.ts +1 -1
  25. package/lib/engine/engine_license.js +6 -19
  26. package/lib/engine/engine_license.js.map +1 -1
  27. package/lib/engine/engine_networking.d.ts +1 -0
  28. package/lib/engine/engine_networking.js +3 -0
  29. package/lib/engine/engine_networking.js.map +1 -1
  30. package/lib/engine/engine_serialization.d.ts +2 -2
  31. package/lib/engine/engine_serialization.js +2 -3
  32. package/lib/engine/engine_serialization.js.map +1 -1
  33. package/lib/engine/engine_serialization_builtin_serializer.d.ts +5 -0
  34. package/lib/engine/engine_serialization_builtin_serializer.js +16 -0
  35. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  36. package/lib/engine/engine_serialization_core.d.ts +1 -0
  37. package/lib/engine/engine_serialization_core.js +26 -20
  38. package/lib/engine/engine_serialization_core.js.map +1 -1
  39. package/lib/engine/engine_utils.d.ts +9 -0
  40. package/lib/engine/engine_utils.js +33 -13
  41. package/lib/engine/engine_utils.js.map +1 -1
  42. package/lib/engine/extensions/NEEDLE_animator_controller_model.d.ts +1 -0
  43. package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
  44. package/lib/engine/extensions/NEEDLE_progressive.js +2 -2
  45. package/lib/engine/extensions/NEEDLE_progressive.js.map +1 -1
  46. package/lib/engine-components/AnimatorController.js +22 -3
  47. package/lib/engine-components/AnimatorController.js.map +1 -1
  48. package/lib/engine-components/AudioSource.d.ts +2 -3
  49. package/lib/engine-components/AudioSource.js +28 -32
  50. package/lib/engine-components/AudioSource.js.map +1 -1
  51. package/lib/engine-components/CameraUtils.js.map +1 -1
  52. package/lib/engine-components/Component.js.map +1 -1
  53. package/lib/engine-components/ParticleSystem.d.ts +5 -2
  54. package/lib/engine-components/ParticleSystem.js +49 -10
  55. package/lib/engine-components/ParticleSystem.js.map +1 -1
  56. package/lib/engine-components/ParticleSystemModules.d.ts +2 -0
  57. package/lib/engine-components/ParticleSystemModules.js +23 -12
  58. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  59. package/lib/engine-components/ScreenCapture.d.ts +1 -0
  60. package/lib/engine-components/ScreenCapture.js +145 -46
  61. package/lib/engine-components/ScreenCapture.js.map +1 -1
  62. package/lib/engine-components/Skybox.js +2 -2
  63. package/lib/engine-components/Skybox.js.map +1 -1
  64. package/lib/engine-components/SyncedRoom.js +1 -2
  65. package/lib/engine-components/SyncedRoom.js.map +1 -1
  66. package/lib/engine-components/VideoPlayer.d.ts +4 -2
  67. package/lib/engine-components/VideoPlayer.js +35 -12
  68. package/lib/engine-components/VideoPlayer.js.map +1 -1
  69. package/lib/engine-components/WebXR.d.ts +4 -1
  70. package/lib/engine-components/WebXR.js +10 -2
  71. package/lib/engine-components/WebXR.js.map +1 -1
  72. package/lib/engine-components/WebXRController.js +2 -2
  73. package/lib/engine-components/WebXRController.js.map +1 -1
  74. package/lib/engine-components/WebXRImageTracking.d.ts +39 -0
  75. package/lib/engine-components/WebXRImageTracking.js +173 -0
  76. package/lib/engine-components/WebXRImageTracking.js.map +1 -0
  77. package/lib/engine-components/codegen/components.d.ts +4 -0
  78. package/lib/engine-components/codegen/components.js +4 -0
  79. package/lib/engine-components/codegen/components.js.map +1 -1
  80. package/lib/engine-components/postprocessing/Effects/DepthOfField.d.ts +2 -0
  81. package/lib/engine-components/postprocessing/Effects/DepthOfField.js +19 -1
  82. package/lib/engine-components/postprocessing/Effects/DepthOfField.js.map +1 -1
  83. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.d.ts +13 -0
  84. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js +63 -0
  85. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js.map +1 -0
  86. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +1 -0
  87. package/lib/engine-components/postprocessing/VolumeParameter.js +4 -0
  88. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  89. package/lib/engine-components/timeline/PlayableDirector.d.ts +3 -1
  90. package/lib/engine-components/timeline/PlayableDirector.js +40 -2
  91. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  92. package/lib/engine-components/timeline/TimelineTracks.d.ts +2 -2
  93. package/lib/engine-components/timeline/TimelineTracks.js +14 -16
  94. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  95. package/lib/engine-components/ui/Text.js +7 -8
  96. package/lib/engine-components/ui/Text.js.map +1 -1
  97. package/lib/include/three/ARButton.d.ts +1 -1
  98. package/lib/include/three/ARButton.js +2 -1
  99. package/lib/include/three/ARButton.js.map +1 -1
  100. package/lib/tsconfig.tsbuildinfo +1 -1
  101. package/package.json +3 -4
  102. package/plugins/vite/config.js +8 -0
  103. package/plugins/vite/copyfiles.js +12 -3
  104. package/plugins/vite/drop.js +1 -0
  105. package/plugins/vite/index.js +4 -0
  106. package/plugins/vite/license.js +24 -0
  107. package/plugins/vite/transform-codegen.js +45 -0
  108. package/src/engine/api.ts +2 -2
  109. package/src/engine/codegen/register_types.js +10 -2
  110. package/src/engine/debug/debug_overlay.ts +2 -0
  111. package/src/engine/engine_addressables.ts +102 -8
  112. package/src/engine/engine_context.ts +4 -1
  113. package/src/engine/engine_element.ts +2 -2
  114. package/src/engine/engine_element_loading.ts +68 -22
  115. package/src/engine/engine_license.ts +6 -17
  116. package/src/engine/engine_networking.ts +4 -0
  117. package/src/engine/engine_serialization.ts +5 -4
  118. package/src/engine/engine_serialization_builtin_serializer.ts +23 -3
  119. package/src/engine/engine_serialization_core.ts +27 -20
  120. package/src/engine/engine_utils.ts +35 -14
  121. package/src/engine/extensions/NEEDLE_animator_controller_model.ts +1 -0
  122. package/src/engine/extensions/NEEDLE_progressive.ts +2 -2
  123. package/src/engine-components/AnimatorController.ts +18 -3
  124. package/src/engine-components/AudioSource.ts +29 -38
  125. package/src/engine-components/CameraUtils.ts +2 -2
  126. package/src/engine-components/Component.ts +1 -1
  127. package/src/engine-components/ParticleSystem.ts +52 -10
  128. package/src/engine-components/ParticleSystemModules.ts +24 -12
  129. package/src/engine-components/ScreenCapture.ts +149 -49
  130. package/src/engine-components/Skybox.ts +2 -2
  131. package/src/engine-components/SyncedRoom.ts +1 -2
  132. package/src/engine-components/VideoPlayer.ts +33 -11
  133. package/src/engine-components/WebXR.ts +11 -2
  134. package/src/engine-components/WebXRController.ts +2 -2
  135. package/src/engine-components/WebXRImageTracking.ts +192 -0
  136. package/src/engine-components/codegen/components.ts +4 -0
  137. package/src/engine-components/postprocessing/Effects/DepthOfField.ts +21 -6
  138. package/src/engine-components/postprocessing/Effects/TiltShiftEffect.ts +56 -0
  139. package/src/engine-components/postprocessing/VolumeParameter.ts +5 -0
  140. package/src/engine-components/timeline/PlayableDirector.ts +38 -2
  141. package/src/engine-components/timeline/TimelineTracks.ts +15 -18
  142. package/src/engine-components/ui/Text.ts +7 -8
  143. package/src/include/three/ARButton.js +2 -2
  144. package/lib/engine/codegen/license.json +0 -1
  145. package/license-2447137e.js +0 -4
  146. package/src/engine/codegen/license.json +0 -1
@@ -47,6 +47,7 @@ export enum WebXREvent {
47
47
  XRStopped = "xrStopped",
48
48
  XRUpdate = "xrUpdate",
49
49
  RequestVRSession = "requestVRSession",
50
+ ModifyAROptions = "modify-ar-options",
50
51
  }
51
52
 
52
53
  export declare type CreateButtonOptions = {
@@ -91,6 +92,9 @@ export class WebXR extends Behaviour {
91
92
  this.events.removeEventListener(type, listener);
92
93
  return listener;
93
94
  }
95
+ private static dispatchEvent(type: string, event: any): void {
96
+ this.events.dispatchEvent({ type, detail: event });
97
+ }
94
98
 
95
99
  public static createVRButton(webXR: WebXR, opts?: CreateButtonOptions): HTMLButtonElement | HTMLAnchorElement {
96
100
  if (!WebXR.XRSupported) {
@@ -122,7 +126,7 @@ export class WebXR extends Behaviour {
122
126
  console.warn("No dom overlay root found, HTML overlays on top of screen-based AR will not work.");
123
127
  }
124
128
 
125
- const arButton = ARButton.createButton(webXR.context.renderer, options);
129
+ const arButton = ARButton.createButton(webXR.context.renderer, options, this.onModifyAROptions.bind(this));
126
130
  arButton.classList.add('webxr-ar-button');
127
131
  arButton.classList.add('webxr-button');
128
132
  WebXR.resetButtonStyles(arButton);
@@ -131,6 +135,10 @@ export class WebXR extends Behaviour {
131
135
  return arButton;
132
136
  }
133
137
 
138
+ private static onModifyAROptions(options){
139
+ WebXR.dispatchEvent(WebXREvent.ModifyAROptions, options);
140
+ }
141
+
134
142
  public static resetButtonStyles(button) {
135
143
  if (!button) return;
136
144
  button.style.position = "";
@@ -233,7 +241,8 @@ export class WebXR extends Behaviour {
233
241
  this.context.domElement.append(buttonsContainer);
234
242
 
235
243
  // AR support
236
- if (this.enableAR && this.createARButton && arSupported) {
244
+ // if (this.enableAR && this.createARButton && arSupported)
245
+ {
237
246
  arButton = WebXR.createARButton(this);
238
247
  this._arButton = arButton;
239
248
  buttonsContainer.appendChild(arButton);
@@ -8,7 +8,7 @@ import { InstancingUtil } from "../engine/engine_instancing";
8
8
  import { Mathf } from "../engine/engine_math";
9
9
  import { RaycastOptions } from "../engine/engine_physics";
10
10
  import { getWorldPosition, getWorldQuaternion, setWorldPosition, setWorldQuaternion } from "../engine/engine_three_utils";
11
- import { getParam, getPath } from "../engine/engine_utils";
11
+ import { getParam, resolveUrl } from "../engine/engine_utils";
12
12
  import { addDracoAndKTX2Loaders } from "../engine/engine_loaders";
13
13
 
14
14
  import { Avatar_POI } from "./avatar/Avatar_Brain_LookAt";
@@ -85,7 +85,7 @@ export class WebXRController extends Behaviour {
85
85
  const loader = new GLTFLoader();
86
86
  addDracoAndKTX2Loaders(loader, context);
87
87
  if (ctrl.webXR.handModelPath && ctrl.webXR.handModelPath !== "")
88
- loader.setPath(getPath(owner.sourceId, ctrl.webXR.handModelPath));
88
+ loader.setPath(resolveUrl(owner.sourceId, ctrl.webXR.handModelPath));
89
89
  else
90
90
  // from XRHandMeshModel.js
91
91
  loader.setPath('https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles/generic-hand/');
@@ -0,0 +1,192 @@
1
+ import { WebXR } from "./WebXR";
2
+ import { serializable } from "../engine/engine_serialization";
3
+ import { Behaviour } from "./Component";
4
+ import { Matrix4, Object3D, Quaternion, Vector, Vector3 } from "three";
5
+ import { CircularBuffer, getParam } from "../engine/engine_utils";
6
+
7
+ // https://github.com/immersive-web/marker-tracking/blob/main/explainer.md
8
+
9
+ const debug = getParam("debugimagetracking");
10
+
11
+ const _scaleTemp = new Vector3();
12
+
13
+ export class WebXRTrackedImage {
14
+
15
+
16
+ get url(): string { return this._trackedImage.image ?? ""; }
17
+ get widthInMeters() { return this._trackedImage.widthInMeters ?? undefined; }
18
+ get bitmap(): ImageBitmap { return this._bitmap; }
19
+ readonly measuredSize: number;
20
+ readonly state: "tracked" | "emulated";
21
+
22
+ // private _matrix: Matrix4 | null = null;
23
+ // private get matrix(): Matrix4 {
24
+ // if (!this._matrix) {
25
+ // // this._matrix = WebXRTrackedImage._matrixBuffer.get();
26
+ // // const matrix = this._pose.transform.matrix;
27
+ // // this._matrix.fromArray(matrix);
28
+ // }
29
+ // return this._matrix!;
30
+ // }
31
+
32
+ /** Copy the image position to a vector */
33
+ getPosition(vec: Vector3) {
34
+ this.ensureTransformData();
35
+ vec.copy(this._position);
36
+ return vec;
37
+ }
38
+
39
+ /** Copy the image rotation to a quaternion */
40
+ getQuaternion(quat: Quaternion) {
41
+ this.ensureTransformData();
42
+ quat.copy(this._rotation);
43
+ return quat;
44
+ }
45
+
46
+ applyToObject(object: Object3D) {
47
+ this.ensureTransformData();
48
+ object.position.copy(this._position);
49
+ object.quaternion.copy(this._rotation);
50
+ }
51
+
52
+ // private static _matrixBuffer: CircularBuffer<Matrix4> = new CircularBuffer(() => new Matrix4(), 20);
53
+ private static _positionBuffer: CircularBuffer<Vector3> = new CircularBuffer(() => new Vector3(), 20);
54
+ private static _rotationBuffer: CircularBuffer<Quaternion> = new CircularBuffer(() => new Quaternion(), 20);
55
+ private _position!: Vector3;
56
+ private _rotation!: Quaternion;
57
+ private ensureTransformData() {
58
+ if (!this._position) {
59
+ this._position = WebXRTrackedImage._positionBuffer.get();
60
+ this._rotation = WebXRTrackedImage._rotationBuffer.get();
61
+ const t = this._pose.transform;
62
+ this._position.set(-t.position.x, t.position.y, -t.position.z);
63
+ this._rotation.set(-t.orientation.x, t.orientation.y, -t.orientation.z, t.orientation.w);
64
+ }
65
+ }
66
+
67
+ private readonly _trackingComponent: WebXRImageTracking;;
68
+ private readonly _trackedImage: WebXRImageTrackingModel;
69
+ private readonly _bitmap: ImageBitmap;
70
+ private readonly _pose: any;
71
+
72
+ constructor(context: WebXRImageTracking, trackedImage: WebXRImageTrackingModel, bitmap: ImageBitmap, measuredSize: number, state: "tracked" | "emulated", pose: any) {
73
+ this._trackingComponent = context;;
74
+ this._trackedImage = trackedImage;
75
+ this._bitmap = bitmap;
76
+ this.measuredSize = measuredSize;
77
+ this.state = state;
78
+ this._pose = pose;
79
+ }
80
+
81
+ }
82
+
83
+ declare type WebXRImageTrackingEvent = (images: WebXRImageTrackingEvent[]) => void;
84
+
85
+ export class WebXRImageTrackingModel {
86
+
87
+ @serializable()
88
+ image?: string;
89
+
90
+ @serializable()
91
+ widthInMeters!: number;
92
+
93
+ }
94
+
95
+ export class WebXRImageTracking extends Behaviour {
96
+
97
+ @serializable(WebXRImageTrackingModel)
98
+ trackedImages!: WebXRImageTrackingModel[];
99
+
100
+
101
+
102
+
103
+ private readonly trackedImageIndexMap: Map<number, WebXRImageTrackingModel> = new Map();
104
+
105
+ private static _imageElements: Map<string, ImageBitmap | null> = new Map();
106
+
107
+ awake(): void {
108
+ for (const trackedImage of this.trackedImages) {
109
+ if (trackedImage.image) {
110
+ if (WebXRImageTracking._imageElements.has(trackedImage.image)) {
111
+ }
112
+ else {
113
+ const url = trackedImage.image;
114
+ WebXRImageTracking._imageElements.set(url, null);
115
+ const imageElement = document.createElement("img") as HTMLImageElement;
116
+ imageElement.src = url;
117
+ imageElement.addEventListener("load", async () => {
118
+ const img = await createImageBitmap(imageElement);
119
+ WebXRImageTracking._imageElements.set(url, img);
120
+ });
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ onEnable(): void {
127
+ WebXR.addEventListener("modify-ar-options", this.onModifyAROptions);
128
+ }
129
+
130
+ onDisable(): void {
131
+ WebXR.removeEventListener("modify-ar-options", this.onModifyAROptions);
132
+ }
133
+
134
+
135
+ private onModifyAROptions = (event: any) => {
136
+ const options = event.detail;
137
+ const features = options.optionalFeatures || [];
138
+ features.push("image-tracking");
139
+ options.optionalFeatures = features;
140
+
141
+ options.trackedImages = [];
142
+ for (const trackedImage of this.trackedImages) {
143
+ if (trackedImage.image?.length && trackedImage.widthInMeters > 0) {
144
+ const bitmap = WebXRImageTracking._imageElements.get(trackedImage.image);
145
+ if (bitmap) {
146
+ this.trackedImageIndexMap.set(options.trackedImages.length, trackedImage);
147
+ options.trackedImages.push({
148
+ image: bitmap,
149
+ widthInMeters: trackedImage.widthInMeters
150
+ });
151
+ }
152
+ }
153
+ }
154
+ }
155
+
156
+ onBeforeRender(frame: XRFrame | null): void {
157
+ //@ts-ignore
158
+ if (frame?.session && typeof frame.getImageTrackingResults === "function") {
159
+ //@ts-ignore
160
+ const results = frame.getImageTrackingResults();
161
+ if (results.length) {
162
+ const space = this.context.renderer.xr.getReferenceSpace();
163
+ if (space) {
164
+ const images: WebXRTrackedImage[] = [];
165
+ for (const result of results) {
166
+ const imageIndex = result.index;
167
+ const trackedImage = this.trackedImageIndexMap.get(imageIndex);
168
+ if (trackedImage) {
169
+ const pose = frame.getPose(result.imageSpace, space);
170
+ const state = result.trackingState;
171
+ const imageData = new WebXRTrackedImage(this, trackedImage, result.image, result.measuredSize, state, pose);
172
+ images.push(imageData);
173
+ }
174
+ else {
175
+ if (debug) {
176
+ console.warn("No tracked image for index", imageIndex);
177
+ }
178
+ }
179
+ }
180
+ if (images.length > 0) {
181
+ try {
182
+ this.dispatchEvent(new CustomEvent("image-tracking", { detail: images }));
183
+ }
184
+ catch (e) {
185
+ console.error(e);
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
@@ -145,6 +145,7 @@ export { TestRunner } from "../TestRunner";
145
145
  export { TestSimulateUserData } from "../TestRunner";
146
146
  export { Text } from "../ui/Text";
147
147
  export { TextureSheetAnimationModule } from "../ParticleSystemModules";
148
+ export { TiltShiftEffect } from "../postprocessing/Effects/TiltShiftEffect";
148
149
  export { ToneMapping } from "../postprocessing/Effects/Tonemapping";
149
150
  export { TrailModule } from "../ParticleSystemModules";
150
151
  export { TransformData } from "../export/usdz/extensions/Animation";
@@ -168,7 +169,10 @@ export { WebARSessionRoot } from "../WebARSessionRoot";
168
169
  export { WebXR } from "../WebXR";
169
170
  export { WebXRAvatar } from "../WebXRAvatar";
170
171
  export { WebXRController } from "../WebXRController";
172
+ export { WebXRImageTracking } from "../WebXRImageTracking";
173
+ export { WebXRImageTrackingModel } from "../WebXRImageTracking";
171
174
  export { WebXRSync } from "../WebXRSync";
175
+ export { WebXRTrackedImage } from "../WebXRImageTracking";
172
176
  export { XRFlag } from "../XRFlag";
173
177
  export { XRGrabModel } from "../WebXRGrabRendering";
174
178
  export { XRGrabRendering } from "../WebXRGrabRendering";
@@ -1,11 +1,10 @@
1
1
  import { DepthOfFieldEffect } from "postprocessing";
2
- import { PerspectiveCamera, Vector3 } from "three";
3
- import { getWorldPosition } from "../../../engine/engine_three_utils";
4
2
  import { serializable } from "../../../engine/engine_serialization";
5
3
  import { Mathf } from "../../../engine/engine_math";
6
4
  import { PostProcessingEffect } from "../PostProcessingEffect";
7
5
  import { VolumeParameter } from "../VolumeParameter";
8
6
  import { registerCustomEffectType } from "../VolumeProfile";
7
+ import { isMobileDevice } from "../../../engine/engine_utils";
9
8
 
10
9
  export enum DepthOfFieldMode {
11
10
  Off = 0,
@@ -20,7 +19,7 @@ export class DepthOfField extends PostProcessingEffect {
20
19
  }
21
20
 
22
21
  @serializable()
23
- mode! : DepthOfFieldMode;
22
+ mode!: DepthOfFieldMode;
24
23
 
25
24
  @serializable(VolumeParameter)
26
25
  focusDistance!: VolumeParameter;
@@ -34,13 +33,19 @@ export class DepthOfField extends PostProcessingEffect {
34
33
  @serializable(VolumeParameter)
35
34
  gaussianMaxRadius!: VolumeParameter;
36
35
 
36
+ @serializable(VolumeParameter)
37
+ resolutionScale?: VolumeParameter;
38
+
39
+ @serializable(VolumeParameter)
40
+ bokehScale?: VolumeParameter;
41
+
37
42
  init() {
38
43
  this.focalLength.valueProcessor = v => {
39
44
  const t = v / 300;
40
45
  const max = 2;// this.context.mainCameraComponent?.farClipPlane ?? 10;
41
46
  return Mathf.lerp(max, .01, t);
42
47
  };
43
-
48
+
44
49
  const maxBokehScale = 20;
45
50
  this.aperture.valueProcessor = v => {
46
51
  const t = 1 - v / 32;
@@ -49,7 +54,16 @@ export class DepthOfField extends PostProcessingEffect {
49
54
  }
50
55
 
51
56
  onCreateEffect() {
52
- if(this.mode === DepthOfFieldMode.Off) return undefined;
57
+ if (this.mode === DepthOfFieldMode.Off) return undefined;
58
+
59
+ const factor = 1 / window.devicePixelRatio;
60
+
61
+ if (this.resolutionScale === undefined) {
62
+ let defaultValue = 1;
63
+ if(isMobileDevice()) defaultValue = .6;
64
+ this.resolutionScale = new VolumeParameter(defaultValue * factor);
65
+ }
66
+
53
67
  // console.log(this.focusDistance.overrideState, this.focusDistance.value);
54
68
  // const depth = new DepthEffect({
55
69
  // inverted: true,
@@ -59,7 +73,7 @@ export class DepthOfField extends PostProcessingEffect {
59
73
  worldFocusRange: .2,
60
74
  focalLength: 1,
61
75
  bokehScale: 20,
62
- resolutionScale: 1,
76
+ resolutionScale: this.resolutionScale.value,
63
77
  });
64
78
 
65
79
  this.focusDistance.onValueChanged = v => {
@@ -68,6 +82,7 @@ export class DepthOfField extends PostProcessingEffect {
68
82
  this.focalLength.onValueChanged = v => dof.circleOfConfusionMaterial.worldFocusRange = v;
69
83
  this.aperture.onValueChanged = v => dof.bokehScale = v;
70
84
 
85
+ if (this.resolutionScale) this.resolutionScale.onValueChanged = v => dof.resolution.scale = v;
71
86
 
72
87
  return [dof];
73
88
  }
@@ -0,0 +1,56 @@
1
+ import { registerCustomEffectType } from "../VolumeProfile";
2
+ import { EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect";
3
+ import { KernelSize, TiltShiftEffect as TiltShift } from "postprocessing";
4
+ import { VolumeParameter } from "../VolumeParameter";
5
+ import { serializable } from "../../../engine/engine_serialization";
6
+
7
+
8
+ export class TiltShiftEffect extends PostProcessingEffect {
9
+ get typeName(): string {
10
+ return "TiltShiftEffect";
11
+ }
12
+
13
+ @serializable(VolumeParameter)
14
+ offset!: VolumeParameter;
15
+ @serializable(VolumeParameter)
16
+ rotation!: VolumeParameter;
17
+ @serializable(VolumeParameter)
18
+ focusArea!: VolumeParameter;
19
+ @serializable(VolumeParameter)
20
+ feather!: VolumeParameter
21
+ @serializable(VolumeParameter)
22
+ kernelSize!: VolumeParameter;
23
+ @serializable(VolumeParameter)
24
+ resolutionScale!: VolumeParameter;
25
+
26
+ init(): void {
27
+ this.offset.defaultValue = 0;
28
+ this.rotation.defaultValue = 0;
29
+ this.focusArea.defaultValue = 0.4;
30
+ this.feather.defaultValue = 0.3;
31
+ this.kernelSize.defaultValue = KernelSize.MEDIUM;
32
+ this.resolutionScale.defaultValue = 1 / window.devicePixelRatio;
33
+ }
34
+
35
+
36
+ onCreateEffect(): EffectProviderResult | undefined {
37
+
38
+ console.log(this);
39
+
40
+ const effect = new TiltShift({
41
+ kernelSize: KernelSize.VERY_LARGE,
42
+ });
43
+
44
+ this.offset.onValueChanged = v => effect.offset = v;
45
+ this.rotation.onValueChanged = v => effect.rotation = v;
46
+ this.focusArea.onValueChanged = v => effect.focusArea = v;
47
+ this.feather.onValueChanged = v => effect.feather = v;
48
+ this.kernelSize.onValueChanged = v => effect.blurPass.kernelSize = v;
49
+ this.resolutionScale.onValueChanged = v => effect.resolution.scale = v / window.devicePixelRatio;
50
+
51
+
52
+ return effect;
53
+ }
54
+
55
+ }
56
+ registerCustomEffectType("TiltShiftEffect", TiltShiftEffect);
@@ -5,6 +5,11 @@ export declare type VolumeParameterValueProcessor = (value: any) => any;
5
5
 
6
6
  export class VolumeParameter {
7
7
 
8
+ constructor(value?: any) {
9
+ this._value = value;
10
+ this._defaultValue = value;
11
+ }
12
+
8
13
  @serializable()
9
14
  get overrideState(): boolean {
10
15
  return this._active;
@@ -6,7 +6,7 @@ import { AudioSource } from '../AudioSource';
6
6
  import { SignalReceiver } from './SignalAsset';
7
7
  import * as Models from "./TimelineModels";
8
8
  import * as Tracks from "./TimelineTracks";
9
- import { deepClone, getParam } from '../../engine/engine_utils';
9
+ import { deepClone, delay, getParam } from '../../engine/engine_utils';
10
10
  import { GuidsMap } from '../../engine/engine_types';
11
11
  import { Object3D } from 'three';
12
12
  import { isLocalNetwork } from '../../engine/engine_networking_utils';
@@ -87,6 +87,8 @@ export class PlayableDirector extends Behaviour {
87
87
  get speed(): number { return this._speed; }
88
88
  set speed(value: number) { this._speed = value; }
89
89
 
90
+ /** When enabled the timeline will wait for audio tracks to load at the current time before starting to play */
91
+ waitForAudio: boolean = true;
90
92
 
91
93
  private _visibilityChangeEvt?: any;
92
94
  private _clonedPlayableAsset: boolean = false;
@@ -151,13 +153,28 @@ export class PlayableDirector extends Behaviour {
151
153
  this.setupAndCreateTrackHandlers();
152
154
  }
153
155
 
154
- play() {
156
+ async play() {
155
157
  if (!this.isValid()) return;
156
158
  const pauseChanged = this._isPaused == true;
157
159
  this._isPaused = false;
158
160
  if (pauseChanged) this.invokePauseChangedMethodsOnTracks();
159
161
  if (this._isPlaying) return;
160
162
  this._isPlaying = true;
163
+ if (this.waitForAudio) {
164
+ // Make sure audio tracks have loaded at the current time
165
+ const promises: Array<Promise<any>> = [];
166
+ for (const track of this._audioTracks) {
167
+ const promise = track.loadAudio(this._time, 1, 0);
168
+ if (promise)
169
+ promises.push(promise);
170
+ }
171
+ if (promises.length > 0) {
172
+ await Promise.all(promises);
173
+ if (!this._isPlaying) return;
174
+ }
175
+ while(this._audioTracks.length > 0 && this._isPlaying && !AudioSource.userInteractionRegistered && this.waitForAudio)
176
+ await delay(200);
177
+ }
161
178
  this._internalUpdateRoutine = this.startCoroutine(this.internalUpdate());
162
179
  }
163
180
 
@@ -363,6 +380,25 @@ export class PlayableDirector extends Behaviour {
363
380
  console.warn("Missing binding", binding, track.name, track.type, this.name, this.playableAsset.name);
364
381
  }
365
382
  }
383
+ if (track.type === Models.TrackType.Control) {
384
+ for (let i = 0; i < track.clips.length; i++) {
385
+ const clip = track.clips[i];
386
+ let binding = clip.asset.sourceObject;
387
+ if (typeof binding === "string") {
388
+ if (this._guidsMap && this._guidsMap[binding])
389
+ binding = this._guidsMap[binding];
390
+ const obj = GameObject.findByGuid(binding, root);
391
+ if (obj === null || typeof obj !== "object") {
392
+ console.warn("Failed to resolve sourceObject binding", binding, track.name, clip);
393
+ }
394
+ else {
395
+ if (debug)
396
+ console.log("Resolved binding", binding, "to", obj);
397
+ clip.asset.sourceObject = obj;
398
+ }
399
+ }
400
+ }
401
+ }
366
402
  }
367
403
  }
368
404
 
@@ -5,7 +5,7 @@ import { GameObject } from "../Component";
5
5
  import { Context } from "../../engine/engine_setup";
6
6
  import { SignalReceiver } from "./SignalAsset";
7
7
  import { AnimationClip, Quaternion, Vector3 } from "three";
8
- import { getParam, getPath } from "../../engine/engine_utils";
8
+ import { getParam, resolveUrl } from "../../engine/engine_utils";
9
9
  import { AudioSource } from "../AudioSource";
10
10
  import { Animator } from "../Animator"
11
11
 
@@ -517,7 +517,7 @@ export class AudioTrackHandler extends TrackHandler {
517
517
  private getAudioFilePath(path: string) {
518
518
  // TODO: this should be the timeline asset location probably which MIGHT be different
519
519
  const glbLocation = this.director.sourceId;
520
- return getPath(glbLocation, path);
520
+ return resolveUrl(glbLocation, path);
521
521
  }
522
522
 
523
523
  onAllowAudioChanged(allow: boolean) {
@@ -657,6 +657,9 @@ export class AudioTrackHandler extends TrackHandler {
657
657
  }
658
658
 
659
659
  private static _currentlyLoading: Map<string, Promise<AudioBuffer | null>> = new Map();
660
+ public static dispose() {
661
+ AudioTrackHandler._currentlyLoading.clear();
662
+ }
660
663
 
661
664
  private handleAudioLoading(model: Models.ClipModel, audio: THREE.Audio): Promise<AudioBuffer | null> | null {
662
665
  if (!this._audioLoader) {
@@ -665,8 +668,12 @@ export class AudioTrackHandler extends TrackHandler {
665
668
  // TODO: maybe we should cache the loaders / buffers here by path
666
669
  const path = this.getAudioFilePath(model.asset.clip);
667
670
 
668
- if(AudioTrackHandler._currentlyLoading.get(path)) {
669
- return AudioTrackHandler._currentlyLoading.get(path)!;
671
+ if (AudioTrackHandler._currentlyLoading.get(path)) {
672
+ const promise = AudioTrackHandler._currentlyLoading.get(path)!
673
+ promise.then((buffer) => {
674
+ if (buffer) audio.setBuffer(buffer);
675
+ });
676
+ return promise;
670
677
  }
671
678
 
672
679
  if (debug) console.warn("LOAD audio track", path, this.director.sourceId);
@@ -724,23 +731,13 @@ export class ControlTrackHandler extends TrackHandler {
724
731
  models: Array<Models.ClipModel> = [];
725
732
  timelines: Array<PlayableDirector | null> = [];
726
733
 
727
- private static resolved: { [key: string]: THREE.Object3D } = {};
728
-
729
- resolveSourceObjects(context: Context) {
734
+ resolveSourceObjects(_context: Context) {
730
735
  for (let i = this.models.length - 1; i >= 0; i--) {
731
736
  const model = this.models[i];
732
737
  const asset = model.asset as Models.ControlClipModel;
733
- if (typeof asset.sourceObject === "string") {
734
- const key = asset.sourceObject;
735
- if (ControlTrackHandler.resolved[key]) {
736
- asset.sourceObject = ControlTrackHandler.resolved[key];
737
- }
738
- else {
739
- asset.sourceObject = GameObject.findByGuid(key, context.scene) as THREE.Object3D
740
- ControlTrackHandler.resolved[key] = asset.sourceObject;
741
- }
742
- }
743
- if (!asset.sourceObject) {
738
+
739
+ if (!asset.sourceObject || typeof asset.sourceObject !== "object") {
740
+ console.log("no source object, removing model", i, asset);
744
741
  this.models.splice(i, 1);
745
742
  continue;
746
743
  }
@@ -7,7 +7,7 @@ import { FrameEvent } from '../../engine/engine_setup';
7
7
  import { updateRenderSettings } from './Utils';
8
8
  import { Canvas } from './Canvas';
9
9
  import { serializable } from '../../engine/engine_serialization_decorator';
10
- import { getParam, getPath } from '../../engine/engine_utils';
10
+ import { getParam, resolveUrl } from '../../engine/engine_utils';
11
11
 
12
12
  const debug = getParam("debugtext");
13
13
 
@@ -176,7 +176,6 @@ export class Text extends Graphic {
176
176
  fontSize: fontSize,
177
177
  fontKerning: "normal",
178
178
  };
179
- this.font = this.font?.toLocaleLowerCase();
180
179
  this.setFont(textOpts, this.fontStyle);
181
180
  return textOpts;
182
181
  }
@@ -482,24 +481,24 @@ export class Text extends Graphic {
482
481
 
483
482
  // if a font path has a known suffix we remove it
484
483
  if (fontName.endsWith("-regular")) {
485
- if (style === FontStyle.Normal) return getPath(this.sourceId, fontName);
484
+ if (style === FontStyle.Normal) return resolveUrl(this.sourceId, fontName);
486
485
  fontName = fontName.substring(0, fontName.length - "-regular".length);
487
486
  }
488
487
  else if (fontName.endsWith("-bold")) {
489
- if (style === FontStyle.Bold)return getPath(this.sourceId, fontName);
488
+ if (style === FontStyle.Bold)return resolveUrl(this.sourceId, fontName);
490
489
  fontName = fontName.substring(0, fontName.length - "-bold".length);
491
490
  }
492
491
  else if (fontName.endsWith("-italic")) {
493
- if (style === FontStyle.Italic)return getPath(this.sourceId, fontName);
492
+ if (style === FontStyle.Italic)return resolveUrl(this.sourceId, fontName);
494
493
  fontName = fontName.substring(0, fontName.length - "-italic".length);
495
494
  }
496
495
  else if (fontName.endsWith("-bolditalic")) {
497
- if (style === FontStyle.BoldAndItalic)return getPath(this.sourceId, fontName);
496
+ if (style === FontStyle.BoldAndItalic)return resolveUrl(this.sourceId, fontName);
498
497
  fontName = fontName.substring(0, fontName.length - "-bolditalic".length);
499
498
  }
500
499
  else
501
500
  // If a font does not have a specific style suffic we dont support getting the correct font style
502
- return getPath(this.sourceId, fontName);
501
+ return resolveUrl(this.sourceId, fontName);
503
502
 
504
503
  switch (style) {
505
504
  case FontStyle.Normal:
@@ -516,7 +515,7 @@ export class Text extends Graphic {
516
515
  break;
517
516
  }
518
517
 
519
- return getPath(this.sourceId, fontName);
518
+ return resolveUrl(this.sourceId, fontName);
520
519
  }
521
520
  }
522
521
 
@@ -1,6 +1,6 @@
1
1
  class ARButton {
2
2
 
3
- static createButton( renderer, options = {} ) {
3
+ static createButton( renderer, options = {}, beforeRequestSession ) {
4
4
 
5
5
  const button = document.createElement( 'button' );
6
6
  let ARButtonControlsDomOverlay = false;
@@ -126,7 +126,7 @@ class ARButton {
126
126
  button.onclick = function () {
127
127
 
128
128
  if ( currentSession === null ) {
129
-
129
+ beforeRequestSession?.call(this, options);
130
130
  navigator.xr.requestSession( 'immersive-ar', options ).then( onSessionStarted );
131
131
 
132
132
  } else {
@@ -1 +0,0 @@
1
- {}
@@ -1,4 +0,0 @@
1
- const e = {};
2
- export {
3
- e as default
4
- };
@@ -1 +0,0 @@
1
- {}