@needle-tools/engine 3.0.1-alpha.5 → 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 (100) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/needle-engine.js +24245 -24524
  3. package/dist/needle-engine.min.js +367 -354
  4. package/dist/needle-engine.umd.cjs +366 -353
  5. package/lib/engine/api.d.ts +1 -1
  6. package/lib/engine/api.js +1 -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/engine_addressables.d.ts +21 -1
  11. package/lib/engine/engine_addressables.js +83 -7
  12. package/lib/engine/engine_addressables.js.map +1 -1
  13. package/lib/engine/engine_serialization.d.ts +2 -2
  14. package/lib/engine/engine_serialization.js +2 -3
  15. package/lib/engine/engine_serialization.js.map +1 -1
  16. package/lib/engine/engine_serialization_builtin_serializer.d.ts +5 -0
  17. package/lib/engine/engine_serialization_builtin_serializer.js +16 -0
  18. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  19. package/lib/engine/engine_serialization_core.d.ts +1 -0
  20. package/lib/engine/engine_serialization_core.js +26 -20
  21. package/lib/engine/engine_serialization_core.js.map +1 -1
  22. package/lib/engine/engine_utils.d.ts +9 -0
  23. package/lib/engine/engine_utils.js +33 -13
  24. package/lib/engine/engine_utils.js.map +1 -1
  25. package/lib/engine/extensions/NEEDLE_animator_controller_model.d.ts +1 -0
  26. package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
  27. package/lib/engine/extensions/NEEDLE_progressive.js +2 -2
  28. package/lib/engine/extensions/NEEDLE_progressive.js.map +1 -1
  29. package/lib/engine-components/AnimatorController.js +22 -3
  30. package/lib/engine-components/AnimatorController.js.map +1 -1
  31. package/lib/engine-components/AudioSource.js +3 -2
  32. package/lib/engine-components/AudioSource.js.map +1 -1
  33. package/lib/engine-components/Component.js.map +1 -1
  34. package/lib/engine-components/ParticleSystem.d.ts +5 -2
  35. package/lib/engine-components/ParticleSystem.js +34 -4
  36. package/lib/engine-components/ParticleSystem.js.map +1 -1
  37. package/lib/engine-components/ParticleSystemModules.d.ts +1 -0
  38. package/lib/engine-components/ParticleSystemModules.js +1 -1
  39. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  40. package/lib/engine-components/Skybox.js +2 -2
  41. package/lib/engine-components/Skybox.js.map +1 -1
  42. package/lib/engine-components/VideoPlayer.d.ts +1 -2
  43. package/lib/engine-components/VideoPlayer.js +6 -7
  44. package/lib/engine-components/VideoPlayer.js.map +1 -1
  45. package/lib/engine-components/WebXR.d.ts +4 -1
  46. package/lib/engine-components/WebXR.js +10 -2
  47. package/lib/engine-components/WebXR.js.map +1 -1
  48. package/lib/engine-components/WebXRController.js +2 -2
  49. package/lib/engine-components/WebXRController.js.map +1 -1
  50. package/lib/engine-components/WebXRImageTracking.d.ts +39 -0
  51. package/lib/engine-components/WebXRImageTracking.js +173 -0
  52. package/lib/engine-components/WebXRImageTracking.js.map +1 -0
  53. package/lib/engine-components/codegen/components.d.ts +4 -0
  54. package/lib/engine-components/codegen/components.js +4 -0
  55. package/lib/engine-components/codegen/components.js.map +1 -1
  56. package/lib/engine-components/postprocessing/Effects/DepthOfField.d.ts +1 -0
  57. package/lib/engine-components/postprocessing/Effects/DepthOfField.js +4 -0
  58. package/lib/engine-components/postprocessing/Effects/DepthOfField.js.map +1 -1
  59. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.d.ts +13 -0
  60. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js +63 -0
  61. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js.map +1 -0
  62. package/lib/engine-components/timeline/TimelineTracks.js +2 -2
  63. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  64. package/lib/engine-components/ui/Text.js +7 -7
  65. package/lib/engine-components/ui/Text.js.map +1 -1
  66. package/lib/include/three/ARButton.d.ts +1 -1
  67. package/lib/include/three/ARButton.js +2 -1
  68. package/lib/include/three/ARButton.js.map +1 -1
  69. package/lib/tsconfig.tsbuildinfo +1 -1
  70. package/package.json +1 -1
  71. package/plugins/vite/config.js +8 -0
  72. package/plugins/vite/copyfiles.js +12 -3
  73. package/plugins/vite/drop.js +1 -0
  74. package/plugins/vite/index.js +2 -0
  75. package/plugins/vite/transform-codegen.js +45 -0
  76. package/src/engine/api.ts +1 -1
  77. package/src/engine/codegen/register_types.js +8 -0
  78. package/src/engine/engine_addressables.ts +102 -8
  79. package/src/engine/engine_serialization.ts +5 -4
  80. package/src/engine/engine_serialization_builtin_serializer.ts +23 -3
  81. package/src/engine/engine_serialization_core.ts +27 -20
  82. package/src/engine/engine_utils.ts +35 -14
  83. package/src/engine/extensions/NEEDLE_animator_controller_model.ts +1 -0
  84. package/src/engine/extensions/NEEDLE_progressive.ts +2 -2
  85. package/src/engine-components/AnimatorController.ts +18 -3
  86. package/src/engine-components/AudioSource.ts +2 -2
  87. package/src/engine-components/Component.ts +1 -1
  88. package/src/engine-components/ParticleSystem.ts +34 -4
  89. package/src/engine-components/ParticleSystemModules.ts +1 -1
  90. package/src/engine-components/Skybox.ts +2 -2
  91. package/src/engine-components/VideoPlayer.ts +6 -6
  92. package/src/engine-components/WebXR.ts +11 -2
  93. package/src/engine-components/WebXRController.ts +2 -2
  94. package/src/engine-components/WebXRImageTracking.ts +192 -0
  95. package/src/engine-components/codegen/components.ts +4 -0
  96. package/src/engine-components/postprocessing/Effects/DepthOfField.ts +3 -0
  97. package/src/engine-components/postprocessing/Effects/TiltShiftEffect.ts +56 -0
  98. package/src/engine-components/timeline/TimelineTracks.ts +2 -2
  99. package/src/engine-components/ui/Text.ts +7 -7
  100. package/src/include/three/ARButton.js +2 -2
@@ -193,6 +193,7 @@ class ParticleSystemEmissionOverTime extends BaseValueGenerator {
193
193
  }
194
194
 
195
195
  genValue(): number {
196
+ if (!this.system.isPlaying) return 0;
196
197
  if (!this.system.emission.enabled) return 0;
197
198
  if (this.system.currentParticles >= this.system.maxParticles) return 0;
198
199
  // emission over time
@@ -220,6 +221,7 @@ class ParticleSystemEmissionOverTime extends BaseValueGenerator {
220
221
  class ParticleSystemEmissionOverDistance extends BaseValueGenerator {
221
222
 
222
223
  genValue(): number {
224
+ if (!this.system.isPlaying) return 0;
223
225
  // this seems not be called yet
224
226
  return 0;
225
227
  // if (this.system.currentParticles >= this.system.maxParticles) return 0;
@@ -547,7 +549,7 @@ class ParticleSystemInterface implements ParticleSystemParameters {
547
549
  }
548
550
  switch (this.system.renderer.renderMode) {
549
551
  case ParticleSystemRenderMode.Billboard: return RenderMode.BillBoard;
550
- // case ParticleSystemRenderMode.Stretch: return RenderMode.Stretch;
552
+ case ParticleSystemRenderMode.Stretch: return RenderMode.StretchedBillBoard;
551
553
  case ParticleSystemRenderMode.HorizontalBillboard: return RenderMode.LocalSpace;
552
554
  case ParticleSystemRenderMode.VerticalBillboard: return RenderMode.LocalSpace;
553
555
  case ParticleSystemRenderMode.Mesh: return RenderMode.LocalSpace;
@@ -597,8 +599,8 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
597
599
  }
598
600
  }, true)
599
601
  }
602
+
600
603
  this._isPlaying = true;
601
- this._time = 0;
602
604
 
603
605
  // https://github.com/Alchemist0823/three.quarks/pull/35
604
606
  if (this._particleSystem) {
@@ -608,12 +610,40 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
608
610
  this.emission?.reset();
609
611
  }
610
612
 
611
- pause() {
613
+ pause(includeChildren = true) {
614
+ if (includeChildren) {
615
+ GameObject.foreachComponent(this.gameObject, comp => {
616
+ if (comp instanceof ParticleSystem && comp !== this) {
617
+ comp.pause(false);
618
+ }
619
+ }, true)
620
+ }
612
621
  this._isPlaying = false;
613
622
  }
614
- stop() {
623
+
624
+ /** clear=true removes all emitted particles */
625
+ stop(includeChildren = true, clear: boolean = false) {
626
+ if (includeChildren) {
627
+ GameObject.foreachComponent(this.gameObject, comp => {
628
+ if (comp instanceof ParticleSystem && comp !== this) {
629
+ comp.stop(false, clear);
630
+ }
631
+ }, true)
632
+ }
615
633
  this._isPlaying = false;
616
634
  this._time = 0;
635
+ if (clear) this.reset();
636
+ }
637
+
638
+ /** remove emitted particles and reset time */
639
+ reset() {
640
+ this._time = 0;
641
+ if (this._particleSystem) {
642
+ this._particleSystem.particleNum = 0;
643
+ this._particleSystem["emissionState"].time = 0;
644
+ this._particleSystem["emitEnded"] = false;
645
+ this.emission?.reset();
646
+ }
617
647
  }
618
648
 
619
649
  private _state?: ParticlesEmissionState;
@@ -35,7 +35,7 @@ export interface IParticleSystem {
35
35
 
36
36
  export enum ParticleSystemRenderMode {
37
37
  Billboard = 0,
38
- // Stretch = 1,
38
+ Stretch = 1,
39
39
  HorizontalBillboard = 2,
40
40
  VerticalBillboard = 3,
41
41
  Mesh = 4,
@@ -5,7 +5,7 @@ import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader";
5
5
  import { EquirectangularRefractionMapping, sRGBEncoding, Texture, TextureLoader } from "three"
6
6
  import { syncField } from "../engine/engine_networking_auto";
7
7
  import { Camera } from "./Camera";
8
- import { getParam, getPath } from "../engine/engine_utils";
8
+ import { getParam, resolveUrl } from "../engine/engine_utils";
9
9
 
10
10
  const debug = getParam("debugskybox");
11
11
 
@@ -56,7 +56,7 @@ export class RemoteSkybox extends Behaviour {
56
56
  if(debug) console.log("Remote skybox url?: " + url);
57
57
 
58
58
  if (!url.startsWith("http") && !url.startsWith("www.") && !url.startsWith("data:")) {
59
- url = getPath(this.sourceId, url);
59
+ url = resolveUrl(this.sourceId, url);
60
60
  if(debug) console.log("Remote skybox resolved to " + url);
61
61
  }
62
62
 
@@ -3,7 +3,7 @@ import * as THREE from "three";
3
3
  import { serializable } from "../engine/engine_serialization_decorator";
4
4
  import { LinearFilter, Material, Mesh, Object3D, RawShaderMaterial, ShaderMaterial, Texture, TextureLoader, Vector2, Vector4, VideoTexture } from "three";
5
5
  import { awaitInput } from "../engine/engine_input_utils";
6
- import { getParam } from "../engine/engine_utils";
6
+ import { getParam, resolveUrl } from "../engine/engine_utils";
7
7
  import { Renderer } from "./Renderer";
8
8
  import { getWorldScale } from "../engine/engine_three_utils";
9
9
  import { ObjectUtils, PrimitiveType } from "../engine/engine_create_objects";
@@ -49,11 +49,12 @@ export class VideoPlayer extends Behaviour {
49
49
  renderer: THREE.Object3D | null = null;
50
50
  @serializable()
51
51
  playOnAwake: boolean = true;
52
- @serializable()
53
- playOnEnable?: boolean;
54
52
 
55
53
  @serializable()
56
54
  aspectMode: AspectMode = AspectMode.None;
55
+
56
+ @serializable(URL)
57
+ private clip?: string | MediaStream | null = null;
57
58
 
58
59
  @serializable()
59
60
  private renderMode?: VideoRenderMode;
@@ -153,7 +154,6 @@ export class VideoPlayer extends Behaviour {
153
154
  private audioOutputMode: VideoAudioOutputMode = VideoAudioOutputMode.AudioSource;
154
155
 
155
156
  private source!: VideoSource;
156
- private clip?: string | MediaStream | null = null;
157
157
  private url?: string | null = null;
158
158
 
159
159
  private _videoElement: HTMLVideoElement | null = null;
@@ -209,7 +209,7 @@ export class VideoPlayer extends Behaviour {
209
209
  }
210
210
 
211
211
  onEnable(): void {
212
- if (this.playOnEnable === true) {
212
+ if (this.playOnAwake === true) {
213
213
  this.handleBeginPlaying(true);
214
214
  }
215
215
  if (this.screenspace) {
@@ -422,7 +422,7 @@ export class VideoPlayer extends Behaviour {
422
422
  let muted = !this._receivedInput && this.audioOutputMode !== VideoAudioOutputMode.None;
423
423
  if(!muted && this._muted) muted = true;
424
424
  this._videoElement.muted = muted;
425
- if (this.playOnAwake || this.playOnEnable)
425
+ if (this.playOnAwake)
426
426
  this._videoElement.autoplay = true;
427
427
  }
428
428
 
@@ -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";
@@ -36,6 +36,9 @@ export class DepthOfField extends PostProcessingEffect {
36
36
  @serializable(VolumeParameter)
37
37
  resolutionScale?: VolumeParameter;
38
38
 
39
+ @serializable(VolumeParameter)
40
+ bokehScale?: VolumeParameter;
41
+
39
42
  init() {
40
43
  this.focalLength.valueProcessor = v => {
41
44
  const t = v / 300;
@@ -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,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) {
@@ -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
 
@@ -481,24 +481,24 @@ export class Text extends Graphic {
481
481
 
482
482
  // if a font path has a known suffix we remove it
483
483
  if (fontName.endsWith("-regular")) {
484
- if (style === FontStyle.Normal) return getPath(this.sourceId, fontName);
484
+ if (style === FontStyle.Normal) return resolveUrl(this.sourceId, fontName);
485
485
  fontName = fontName.substring(0, fontName.length - "-regular".length);
486
486
  }
487
487
  else if (fontName.endsWith("-bold")) {
488
- if (style === FontStyle.Bold)return getPath(this.sourceId, fontName);
488
+ if (style === FontStyle.Bold)return resolveUrl(this.sourceId, fontName);
489
489
  fontName = fontName.substring(0, fontName.length - "-bold".length);
490
490
  }
491
491
  else if (fontName.endsWith("-italic")) {
492
- if (style === FontStyle.Italic)return getPath(this.sourceId, fontName);
492
+ if (style === FontStyle.Italic)return resolveUrl(this.sourceId, fontName);
493
493
  fontName = fontName.substring(0, fontName.length - "-italic".length);
494
494
  }
495
495
  else if (fontName.endsWith("-bolditalic")) {
496
- if (style === FontStyle.BoldAndItalic)return getPath(this.sourceId, fontName);
496
+ if (style === FontStyle.BoldAndItalic)return resolveUrl(this.sourceId, fontName);
497
497
  fontName = fontName.substring(0, fontName.length - "-bolditalic".length);
498
498
  }
499
499
  else
500
500
  // If a font does not have a specific style suffic we dont support getting the correct font style
501
- return getPath(this.sourceId, fontName);
501
+ return resolveUrl(this.sourceId, fontName);
502
502
 
503
503
  switch (style) {
504
504
  case FontStyle.Normal:
@@ -515,7 +515,7 @@ export class Text extends Graphic {
515
515
  break;
516
516
  }
517
517
 
518
- return getPath(this.sourceId, fontName);
518
+ return resolveUrl(this.sourceId, fontName);
519
519
  }
520
520
  }
521
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 {