@needle-tools/engine 4.3.0-alpha → 4.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/dist/needle-engine.bundle.js +1467 -222
- package/dist/needle-engine.bundle.light.js +1467 -222
- package/dist/needle-engine.bundle.light.min.js +32 -32
- package/dist/needle-engine.bundle.light.umd.cjs +3 -3
- package/dist/needle-engine.bundle.min.js +3 -3
- package/dist/needle-engine.bundle.umd.cjs +3 -3
- package/dist/needle-engine.light.d.ts +9 -9
- package/lib/engine/engine_types.d.ts +162 -17
- package/lib/engine-components/Animator.d.ts +129 -21
- package/lib/engine-components/Animator.js +115 -21
- package/lib/engine-components/Animator.js.map +1 -1
- package/lib/engine-components/AnimatorController.d.ts +161 -32
- package/lib/engine-components/AnimatorController.js +176 -29
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioListener.d.ts +16 -5
- package/lib/engine-components/AudioListener.js +16 -5
- package/lib/engine-components/AudioListener.js.map +1 -1
- package/lib/engine-components/AudioSource.d.ts +120 -28
- package/lib/engine-components/AudioSource.js +120 -37
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/AvatarLoader.d.ts +61 -0
- package/lib/engine-components/AvatarLoader.js +61 -1
- package/lib/engine-components/AvatarLoader.js.map +1 -1
- package/lib/engine-components/AxesHelper.d.ts +19 -1
- package/lib/engine-components/AxesHelper.js +19 -1
- package/lib/engine-components/AxesHelper.js.map +1 -1
- package/lib/engine-components/BoxHelperComponent.d.ts +26 -0
- package/lib/engine-components/BoxHelperComponent.js +26 -0
- package/lib/engine-components/BoxHelperComponent.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +126 -37
- package/lib/engine-components/Camera.js +139 -37
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +20 -0
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +95 -21
- package/lib/engine-components/Collider.js +100 -23
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Component.d.ts +554 -106
- package/lib/engine-components/Component.js +352 -81
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/DragControls.d.ts +95 -21
- package/lib/engine-components/DragControls.js +126 -32
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/DropListener.d.ts +99 -16
- package/lib/engine-components/DropListener.js +119 -14
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/Light.d.ts +102 -5
- package/lib/engine-components/Light.js +102 -44
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/NeedleMenu.d.ts +28 -11
- package/lib/engine-components/NeedleMenu.js +28 -11
- package/lib/engine-components/NeedleMenu.js.map +1 -1
- package/lib/engine-components/Networking.d.ts +37 -5
- package/lib/engine-components/Networking.js +37 -5
- package/lib/engine-components/Networking.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.js +44 -0
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/SpatialTrigger.d.ts +66 -1
- package/lib/engine-components/SpatialTrigger.js +74 -2
- package/lib/engine-components/SpatialTrigger.js.map +1 -1
- package/lib/engine-components/SpectatorCamera.d.ts +66 -4
- package/lib/engine-components/SpectatorCamera.js +132 -6
- package/lib/engine-components/SpectatorCamera.js.map +1 -1
- package/lib/engine-components/SyncedTransform.d.ts +45 -6
- package/lib/engine-components/SyncedTransform.js +45 -6
- package/lib/engine-components/SyncedTransform.js.map +1 -1
- package/lib/engine-components/TransformGizmo.d.ts +49 -3
- package/lib/engine-components/TransformGizmo.js +49 -3
- package/lib/engine-components/TransformGizmo.js.map +1 -1
- package/lib/engine-components/webxr/WebXR.d.ts +131 -22
- package/lib/engine-components/webxr/WebXR.js +132 -23
- package/lib/engine-components/webxr/WebXR.js.map +1 -1
- package/lib/engine-components-experimental/networking/PlayerSync.d.ts +82 -9
- package/lib/engine-components-experimental/networking/PlayerSync.js +76 -11
- package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/engine_types.ts +179 -18
- package/src/engine-components/Animator.ts +142 -22
- package/src/engine-components/AnimatorController.ts +184 -34
- package/src/engine-components/AudioListener.ts +16 -5
- package/src/engine-components/AudioSource.ts +126 -37
- package/src/engine-components/AvatarLoader.ts +61 -2
- package/src/engine-components/AxesHelper.ts +21 -1
- package/src/engine-components/BoxHelperComponent.ts +26 -0
- package/src/engine-components/Camera.ts +147 -41
- package/src/engine-components/CameraUtils.ts +20 -0
- package/src/engine-components/Collider.ts +102 -27
- package/src/engine-components/Component.ts +605 -129
- package/src/engine-components/DragControls.ts +134 -38
- package/src/engine-components/DropListener.ts +143 -23
- package/src/engine-components/Light.ts +105 -44
- package/src/engine-components/NeedleMenu.ts +29 -11
- package/src/engine-components/Networking.ts +37 -6
- package/src/engine-components/SceneSwitcher.ts +48 -1
- package/src/engine-components/SpatialTrigger.ts +80 -3
- package/src/engine-components/SpectatorCamera.ts +136 -18
- package/src/engine-components/SyncedTransform.ts +50 -7
- package/src/engine-components/TransformGizmo.ts +49 -4
- package/src/engine-components/webxr/WebXR.ts +144 -27
- package/src/engine-components-experimental/networking/PlayerSync.ts +85 -13
|
@@ -13,84 +13,121 @@ import { Behaviour, GameObject } from "./Component.js";
|
|
|
13
13
|
const debug = getParam("debugaudio");
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Defines how audio volume attenuates over distance from the listener.
|
|
17
17
|
*/
|
|
18
18
|
export enum AudioRolloffMode {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Logarithmic rolloff provides a natural, real-world attenuation where volume decreases
|
|
21
|
+
* exponentially with distance.
|
|
22
|
+
*/
|
|
22
23
|
Logarithmic = 0,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Linear rolloff provides a straightforward volume reduction that decreases at a constant
|
|
27
|
+
* rate with distance.
|
|
28
|
+
*/
|
|
26
29
|
Linear = 1,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Custom rolloff allows for defining specialized distance-based attenuation curves.
|
|
33
|
+
* Note: Custom rolloff is not fully implemented in this version.
|
|
34
|
+
*/
|
|
30
35
|
Custom = 2,
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
|
|
34
|
-
/**
|
|
35
|
-
*
|
|
39
|
+
/**
|
|
40
|
+
* Plays audio clips in the scene, with support for spatial positioning.
|
|
41
|
+
*
|
|
42
|
+
* The AudioSource component can play audio files or media streams with
|
|
43
|
+
* options for spatial blending, volume control, looping, and more.
|
|
44
|
+
*
|
|
45
|
+
* When a page loses visibility (tab becomes inactive), audio will automatically
|
|
46
|
+
* pause unless {@link playInBackground} is set to true. On mobile devices, audio always
|
|
47
|
+
* pauses regardless of this setting. When the page becomes visible again,
|
|
48
|
+
* previously playing audio will resume.
|
|
49
|
+
*
|
|
50
|
+
* AudioSource also responds to application mute state changes. When the application
|
|
51
|
+
* is muted, the volume is set to 0. When unmuted, the volume
|
|
52
|
+
* returns to its previous value.
|
|
53
|
+
*
|
|
36
54
|
* @category Multimedia
|
|
37
55
|
* @group Components
|
|
38
56
|
*/
|
|
39
57
|
export class AudioSource extends Behaviour {
|
|
40
58
|
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
59
|
+
/**
|
|
60
|
+
* Checks if the user has interacted with the page to allow audio playback.
|
|
61
|
+
* Audio playback often requires a user gesture first due to browser autoplay policies.
|
|
62
|
+
* This is the same as calling {@link Application.userInteractionRegistered}.
|
|
63
|
+
*
|
|
64
|
+
* @returns Whether user interaction has been registered to allow audio playback
|
|
43
65
|
*/
|
|
44
66
|
public static get userInteractionRegistered(): boolean {
|
|
45
67
|
return Application.userInteractionRegistered;
|
|
46
68
|
}
|
|
47
69
|
|
|
48
|
-
/**
|
|
49
|
-
*
|
|
70
|
+
/**
|
|
71
|
+
* Registers a callback that will be executed once the user has interacted with the page,
|
|
72
|
+
* allowing audio playback to begin.
|
|
73
|
+
* This is the same as calling {@link Application.registerWaitForInteraction}.
|
|
74
|
+
*
|
|
75
|
+
* @param cb - The callback function to execute when user interaction is registered
|
|
50
76
|
*/
|
|
51
77
|
public static registerWaitForAllowAudio(cb: Function) {
|
|
52
78
|
Application.registerWaitForInteraction(cb);
|
|
53
79
|
}
|
|
54
80
|
|
|
55
81
|
/**
|
|
56
|
-
* The audio clip to play. Can be a string
|
|
82
|
+
* The audio clip to play. Can be a URL string pointing to an audio file or a {@link MediaStream} object.
|
|
57
83
|
*/
|
|
58
84
|
@serializable(URL)
|
|
59
85
|
clip: string | MediaStream = "";
|
|
60
86
|
|
|
61
87
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
88
|
+
* When true, the audio will automatically start playing when the component is enabled.
|
|
89
|
+
* When false, you must call play() manually to start audio playback.
|
|
64
90
|
* @default false
|
|
65
|
-
|
|
91
|
+
*/
|
|
66
92
|
@serializable()
|
|
67
93
|
playOnAwake: boolean = false;
|
|
68
94
|
|
|
69
95
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
96
|
+
* When true, the audio clip will be loaded during initialization rather than when play() is called.
|
|
97
|
+
* This can reduce playback delay but increases initial loading time.
|
|
72
98
|
* @default false
|
|
73
99
|
*/
|
|
74
100
|
@serializable()
|
|
75
101
|
preload: boolean = false;
|
|
76
102
|
|
|
77
103
|
/**
|
|
78
|
-
* When true,
|
|
104
|
+
* When true, audio will continue playing when the browser tab loses focus.
|
|
105
|
+
* When false, audio will pause when the tab is minimized or not active.
|
|
79
106
|
* @default true
|
|
80
107
|
*/
|
|
81
108
|
@serializable()
|
|
82
109
|
playInBackground: boolean = true;
|
|
83
110
|
|
|
84
111
|
/**
|
|
85
|
-
*
|
|
112
|
+
* Indicates whether the audio is currently playing.
|
|
113
|
+
*
|
|
114
|
+
* @returns True if the audio is playing, false otherwise
|
|
86
115
|
*/
|
|
87
116
|
get isPlaying(): boolean { return this.sound?.isPlaying ?? false; }
|
|
88
117
|
|
|
89
|
-
/**
|
|
118
|
+
/**
|
|
119
|
+
* The total duration of the current audio clip in seconds.
|
|
120
|
+
*
|
|
121
|
+
* @returns Duration in seconds or undefined if no clip is loaded
|
|
122
|
+
*/
|
|
90
123
|
get duration() {
|
|
91
124
|
return this.sound?.buffer?.duration;
|
|
92
125
|
}
|
|
93
|
-
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The current playback position as a normalized value between 0 and 1.
|
|
129
|
+
* Can be set to seek to a specific position in the audio.
|
|
130
|
+
*/
|
|
94
131
|
get time01() {
|
|
95
132
|
const duration = this.duration;
|
|
96
133
|
if (duration && this.sound) {
|
|
@@ -106,7 +143,8 @@ export class AudioSource extends Behaviour {
|
|
|
106
143
|
}
|
|
107
144
|
|
|
108
145
|
/**
|
|
109
|
-
* The current
|
|
146
|
+
* The current playback position in seconds.
|
|
147
|
+
* Can be set to seek to a specific time in the audio.
|
|
110
148
|
*/
|
|
111
149
|
get time(): number { return this.sound?.source ? (this.sound.source?.context.currentTime - this._lastContextTime + this.sound.offset) : 0; }
|
|
112
150
|
set time(val: number) {
|
|
@@ -121,8 +159,8 @@ export class AudioSource extends Behaviour {
|
|
|
121
159
|
}
|
|
122
160
|
|
|
123
161
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
162
|
+
* When true, the audio will repeat after reaching the end.
|
|
163
|
+
* When false, audio will play once and stop.
|
|
126
164
|
* @default false
|
|
127
165
|
*/
|
|
128
166
|
@serializable()
|
|
@@ -134,10 +172,12 @@ export class AudioSource extends Behaviour {
|
|
|
134
172
|
this._loop = val;
|
|
135
173
|
if (this.sound) this.sound.setLoop(val);
|
|
136
174
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
*
|
|
140
|
-
*
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Controls how the audio is positioned in space.
|
|
178
|
+
* Values range from 0 (2D, non-positional) to 1 (fully 3D positioned).
|
|
179
|
+
* Note: 2D playback is not fully supported in the current implementation.
|
|
180
|
+
*/
|
|
141
181
|
@serializable()
|
|
142
182
|
get spatialBlend(): number {
|
|
143
183
|
return this._spatialBlend;
|
|
@@ -147,6 +187,11 @@ export class AudioSource extends Behaviour {
|
|
|
147
187
|
this._spatialBlend = val;
|
|
148
188
|
this._needUpdateSpatialDistanceSettings = true;
|
|
149
189
|
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* The minimum distance from the audio source at which the volume starts to attenuate.
|
|
193
|
+
* Within this radius, the audio plays at full volume regardless of distance.
|
|
194
|
+
*/
|
|
150
195
|
@serializable()
|
|
151
196
|
get minDistance(): number {
|
|
152
197
|
return this._minDistance;
|
|
@@ -156,6 +201,11 @@ export class AudioSource extends Behaviour {
|
|
|
156
201
|
this._minDistance = val;
|
|
157
202
|
this._needUpdateSpatialDistanceSettings = true;
|
|
158
203
|
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The maximum distance from the audio source beyond which the volume no longer decreases.
|
|
207
|
+
* This defines the outer limit of the attenuation curve.
|
|
208
|
+
*/
|
|
159
209
|
@serializable()
|
|
160
210
|
get maxDistance(): number {
|
|
161
211
|
return this._maxDistance;
|
|
@@ -170,6 +220,11 @@ export class AudioSource extends Behaviour {
|
|
|
170
220
|
private _minDistance: number = 1;
|
|
171
221
|
private _maxDistance: number = 100;
|
|
172
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Controls the overall volume/loudness of the audio.
|
|
225
|
+
* Values range from 0 (silent) to 1 (full volume).
|
|
226
|
+
* @default 1
|
|
227
|
+
*/
|
|
173
228
|
@serializable()
|
|
174
229
|
get volume(): number { return this._volume; }
|
|
175
230
|
set volume(val: number) {
|
|
@@ -181,6 +236,12 @@ export class AudioSource extends Behaviour {
|
|
|
181
236
|
}
|
|
182
237
|
private _volume: number = 1;
|
|
183
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Controls the playback rate (speed) of the audio.
|
|
241
|
+
* Values greater than 1 increase speed, values less than 1 decrease it.
|
|
242
|
+
* This affects both speed and pitch of the audio.
|
|
243
|
+
* @default 1
|
|
244
|
+
*/
|
|
184
245
|
@serializable()
|
|
185
246
|
set pitch(val: number) {
|
|
186
247
|
if (this.sound) this.sound.setPlaybackRate(val);
|
|
@@ -189,6 +250,11 @@ export class AudioSource extends Behaviour {
|
|
|
189
250
|
return this.sound ? this.sound.getPlaybackRate() : 1;
|
|
190
251
|
}
|
|
191
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Determines how audio volume decreases with distance from the listener.
|
|
255
|
+
* @default AudioRolloffMode.Logarithmic
|
|
256
|
+
* @see {@link AudioRolloffMode}
|
|
257
|
+
*/
|
|
192
258
|
@serializable()
|
|
193
259
|
rollOffMode: AudioRolloffMode = 0;
|
|
194
260
|
|
|
@@ -204,6 +270,12 @@ export class AudioSource extends Behaviour {
|
|
|
204
270
|
private _lastClipStartedLoading: string | MediaStream | null = null;
|
|
205
271
|
private _audioElement: HTMLAudioElement | null = null;
|
|
206
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Returns the underlying {@link PositionalAudio} object, creating it if necessary.
|
|
275
|
+
* The audio source needs a user interaction to be initialized due to browser autoplay policies.
|
|
276
|
+
*
|
|
277
|
+
* @returns The three.js PositionalAudio object or null if unavailable
|
|
278
|
+
*/
|
|
207
279
|
public get Sound(): PositionalAudio | null {
|
|
208
280
|
if (!this.sound && AudioSource.userInteractionRegistered) {
|
|
209
281
|
let listener = GameObject.getComponent(this.context.mainCamera, AudioListener) ?? GameObject.findObjectOfType(AudioListener, this.context);
|
|
@@ -250,9 +322,19 @@ export class AudioSource extends Behaviour {
|
|
|
250
322
|
// }
|
|
251
323
|
// }
|
|
252
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Indicates whether the audio source is queued to play when possible.
|
|
327
|
+
* This may be true before user interaction has been registered.
|
|
328
|
+
*
|
|
329
|
+
* @returns Whether the audio source intends to play
|
|
330
|
+
*/
|
|
253
331
|
public get ShouldPlay(): boolean { return this.shouldPlay; }
|
|
254
332
|
|
|
255
|
-
/**
|
|
333
|
+
/**
|
|
334
|
+
* Returns the Web Audio API context associated with this audio source.
|
|
335
|
+
*
|
|
336
|
+
* @returns The {@link AudioContext} or null if not available
|
|
337
|
+
*/
|
|
256
338
|
public get audioContext() {
|
|
257
339
|
return this.sound?.context;
|
|
258
340
|
}
|
|
@@ -424,7 +506,12 @@ export class AudioSource extends Behaviour {
|
|
|
424
506
|
}
|
|
425
507
|
}
|
|
426
508
|
|
|
427
|
-
/**
|
|
509
|
+
/**
|
|
510
|
+
* Plays the audio clip or media stream.
|
|
511
|
+
* If no argument is provided, plays the currently assigned clip.
|
|
512
|
+
*
|
|
513
|
+
* @param clip - Optional audio clip or {@link MediaStream} to play
|
|
514
|
+
*/
|
|
428
515
|
play(clip: string | MediaStream | undefined = undefined) {
|
|
429
516
|
// use audio source's clip when no clip is passed in
|
|
430
517
|
if (!clip && this.clip)
|
|
@@ -483,7 +570,8 @@ export class AudioSource extends Behaviour {
|
|
|
483
570
|
}
|
|
484
571
|
|
|
485
572
|
/**
|
|
486
|
-
*
|
|
573
|
+
* Pauses audio playback while maintaining the current position.
|
|
574
|
+
* Use play() to resume from the paused position.
|
|
487
575
|
*/
|
|
488
576
|
pause() {
|
|
489
577
|
if (debug) console.log("Pause", this);
|
|
@@ -497,7 +585,8 @@ export class AudioSource extends Behaviour {
|
|
|
497
585
|
}
|
|
498
586
|
|
|
499
587
|
/**
|
|
500
|
-
*
|
|
588
|
+
* Stops audio playback completely and resets the playback position to the beginning.
|
|
589
|
+
* Unlike pause(), calling play() after stop() will start from the beginning.
|
|
501
590
|
*/
|
|
502
591
|
stop() {
|
|
503
592
|
if (debug) console.log("Pause", this);
|
|
@@ -10,17 +10,37 @@ import { GameObject } from "./Component.js";
|
|
|
10
10
|
|
|
11
11
|
const debug = utils.getParam("debugavatar");
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Represents an avatar model with head and hands references.
|
|
15
|
+
* Used for representing characters in 3D space.
|
|
16
|
+
*/
|
|
13
17
|
export class AvatarModel {
|
|
18
|
+
/** The root object of the avatar model */
|
|
14
19
|
root: Object3D;
|
|
20
|
+
/** The head object of the avatar model */
|
|
15
21
|
head: Object3D;
|
|
22
|
+
/** The left hand object of the avatar model, if available */
|
|
16
23
|
leftHand: Object3D | null;
|
|
24
|
+
/** The right hand object of the avatar model, if available */
|
|
17
25
|
rigthHand: Object3D | null;
|
|
18
26
|
|
|
19
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Checks if the avatar model has a valid configuration.
|
|
30
|
+
* An avatar is considered valid if it has a head.
|
|
31
|
+
* @returns Whether the avatar has a valid setup
|
|
32
|
+
*/
|
|
20
33
|
get isValid(): boolean {
|
|
21
34
|
return this.head !== null && this.head !== undefined;
|
|
22
35
|
}
|
|
23
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Creates a new avatar model.
|
|
39
|
+
* @param root The root object of the avatar
|
|
40
|
+
* @param head The head object of the avatar
|
|
41
|
+
* @param leftHand The left hand object of the avatar
|
|
42
|
+
* @param rigthHand The right hand object of the avatar
|
|
43
|
+
*/
|
|
24
44
|
constructor(root: Object3D, head: Object3D, leftHand: Object3D | null, rigthHand: Object3D | null) {
|
|
25
45
|
this.root = root;
|
|
26
46
|
this.head = head;
|
|
@@ -33,12 +53,25 @@ export class AvatarModel {
|
|
|
33
53
|
}
|
|
34
54
|
}
|
|
35
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Handles loading and instantiating avatar models from various sources.
|
|
58
|
+
* Provides functionality to find and extract important parts of an avatar (head, hands).
|
|
59
|
+
*
|
|
60
|
+
* Debug mode can be enabled with the URL parameter `?debugavatar`,
|
|
61
|
+
* which will log detailed information about avatar loading and configuration.
|
|
62
|
+
*/
|
|
36
63
|
export class AvatarLoader {
|
|
37
64
|
|
|
38
65
|
private readonly avatarRegistryUrl: string | null = null;
|
|
39
66
|
// private loader: GLTFLoader | null;
|
|
40
67
|
// private avatarModelCache: Map<string, AvatarModel | null> = new Map<string, AvatarModel | null>();
|
|
41
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Retrieves or creates a new avatar instance from an ID or existing Object3D.
|
|
71
|
+
* @param context The application context
|
|
72
|
+
* @param avatarId Either a string ID to load an avatar or an existing Object3D to use as avatar
|
|
73
|
+
* @returns Promise resolving to an AvatarModel if successful, or null if failed
|
|
74
|
+
*/
|
|
42
75
|
public async getOrCreateNewAvatarInstance(context: Context, avatarId: string | Object3D): Promise<AvatarModel | null> {
|
|
43
76
|
|
|
44
77
|
if (!avatarId) {
|
|
@@ -76,6 +109,12 @@ export class AvatarLoader {
|
|
|
76
109
|
}
|
|
77
110
|
|
|
78
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Loads an avatar model from a file or registry using the provided ID.
|
|
114
|
+
* @param context The engine context
|
|
115
|
+
* @param avatarId The ID of the avatar to load
|
|
116
|
+
* @returns Promise resolving to the loaded avatar's Object3D, or null if failed
|
|
117
|
+
*/
|
|
79
118
|
private async loadAvatar(context: Context, avatarId: string): Promise<Object3D | null> {
|
|
80
119
|
|
|
81
120
|
console.assert(avatarId !== undefined && avatarId !== null && typeof avatarId === "string", "Avatar id must not be null");
|
|
@@ -140,11 +179,20 @@ export class AvatarLoader {
|
|
|
140
179
|
});
|
|
141
180
|
}
|
|
142
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Caches an avatar model for reuse.
|
|
184
|
+
* @param _id The ID to associate with the model
|
|
185
|
+
* @param _model The avatar model to cache
|
|
186
|
+
*/
|
|
143
187
|
private cacheModel(_id: string, _model: AvatarModel) {
|
|
144
188
|
// this.avatarModelCache.set(id, model);
|
|
145
189
|
}
|
|
146
190
|
|
|
147
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Analyzes an Object3D to find avatar parts (head, hands) based on naming conventions.
|
|
193
|
+
* @param obj The Object3D to search for avatar parts
|
|
194
|
+
* @returns A structured AvatarModel with references to found parts
|
|
195
|
+
*/
|
|
148
196
|
private findAvatar(obj: Object3D): AvatarModel {
|
|
149
197
|
|
|
150
198
|
const root: Object3D = obj;
|
|
@@ -175,7 +223,12 @@ export class AvatarLoader {
|
|
|
175
223
|
return model;
|
|
176
224
|
}
|
|
177
225
|
|
|
178
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Recursively searches for an avatar part by name within an Object3D hierarchy.
|
|
228
|
+
* @param obj The Object3D to search within
|
|
229
|
+
* @param searchString Array of strings that should all be present in the object name
|
|
230
|
+
* @returns The found Object3D part or null if not found
|
|
231
|
+
*/
|
|
179
232
|
private findAvatarPart(obj: Object3D, searchString: string[]): Object3D | null {
|
|
180
233
|
|
|
181
234
|
const name = obj.name.toLowerCase();
|
|
@@ -196,6 +249,12 @@ export class AvatarLoader {
|
|
|
196
249
|
return null;
|
|
197
250
|
}
|
|
198
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Handles HTTP response errors from avatar loading operations.
|
|
254
|
+
* @param response The fetch API response to check
|
|
255
|
+
* @returns The response if it was ok
|
|
256
|
+
* @throws Error with status text if response was not ok
|
|
257
|
+
*/
|
|
199
258
|
private handleCustomAvatarErrors(response) {
|
|
200
259
|
if (!response.ok) {
|
|
201
260
|
throw Error(response.statusText);
|
|
@@ -5,20 +5,37 @@ import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
|
5
5
|
import { Behaviour } from "./Component.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Component that visualizes the axes of an object in the scene.
|
|
9
|
+
* Renders colored lines representing the X (red), Y (green) and Z (blue) axes.
|
|
9
10
|
* @category Helpers
|
|
10
11
|
* @group Components
|
|
11
12
|
*/
|
|
12
13
|
export class AxesHelper extends Behaviour {
|
|
14
|
+
/**
|
|
15
|
+
* The length of each axis line in scene units.
|
|
16
|
+
*/
|
|
13
17
|
@serializable()
|
|
14
18
|
public length: number = 1;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Whether the axes should be occluded by objects in the scene.
|
|
22
|
+
* When set to false, axes will always appear on top regardless of their depth.
|
|
23
|
+
*/
|
|
15
24
|
@serializable()
|
|
16
25
|
public depthTest: boolean = true;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* When true, this helper will only be visible if the debug flag `?gizmos` is enabled.
|
|
29
|
+
*/
|
|
17
30
|
@serializable()
|
|
18
31
|
public isGizmo: boolean = false;
|
|
19
32
|
|
|
20
33
|
private _axes: _AxesHelper | null = null;
|
|
21
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Creates and adds the axes visualization to the scene when the component is enabled.
|
|
37
|
+
* If marked as a gizmo, it will only be shown when gizmos are enabled in the global parameters.
|
|
38
|
+
*/
|
|
22
39
|
onEnable(): void {
|
|
23
40
|
if (this.isGizmo && !params.showGizmos) return;
|
|
24
41
|
if (!this._axes)
|
|
@@ -33,6 +50,9 @@ export class AxesHelper extends Behaviour {
|
|
|
33
50
|
}
|
|
34
51
|
}
|
|
35
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Removes the axes visualization from the scene when the component is disabled.
|
|
55
|
+
*/
|
|
36
56
|
onDisable(): void {
|
|
37
57
|
if (!this._axes) return;
|
|
38
58
|
this.gameObject.remove(this._axes);
|
|
@@ -9,11 +9,17 @@ const gizmos = getParam("gizmos");
|
|
|
9
9
|
const debug = getParam("debugboxhelper");
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
+
* A component that creates a bounding box around an object and provides intersection testing functionality.
|
|
13
|
+
*
|
|
14
|
+
* Debug mode can be enabled with the URL parameter `?debugboxhelper`, which will visualize intersection tests.
|
|
15
|
+
* Helper visualization can be enabled with the URL parameter `?gizmos`.
|
|
16
|
+
*
|
|
12
17
|
* @category Helpers
|
|
13
18
|
* @group Components
|
|
14
19
|
*/
|
|
15
20
|
export class BoxHelperComponent extends Behaviour {
|
|
16
21
|
|
|
22
|
+
/** The bounding box for this component */
|
|
17
23
|
private box: Box3 | null = null;
|
|
18
24
|
private static testBox: Box3 = new Box3();
|
|
19
25
|
private _lastMatrixUpdateFrame: number = -1;
|
|
@@ -21,6 +27,11 @@ export class BoxHelperComponent extends Behaviour {
|
|
|
21
27
|
private static _size: Vector3 = new Vector3(.01, .01, .01);
|
|
22
28
|
private static _emptyObjectSize: Vector3 = new Vector3(.01, .01, .01);
|
|
23
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Tests if an object intersects with this helper's bounding box
|
|
32
|
+
* @param obj The object to test for intersection
|
|
33
|
+
* @returns True if objects intersect, false if not, undefined if the provided object is invalid
|
|
34
|
+
*/
|
|
24
35
|
public isInBox(obj: Object3D): boolean | undefined {
|
|
25
36
|
if (!obj) return undefined;
|
|
26
37
|
|
|
@@ -44,11 +55,21 @@ export class BoxHelperComponent extends Behaviour {
|
|
|
44
55
|
return intersects;
|
|
45
56
|
}
|
|
46
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Tests if this helper's bounding box intersects with another box
|
|
60
|
+
* @param box The {@link Box3} to test for intersection
|
|
61
|
+
* @returns True if boxes intersect, false otherwise
|
|
62
|
+
*/
|
|
47
63
|
public intersects(box: Box3): boolean {
|
|
48
64
|
if (!box) return false;
|
|
49
65
|
return this.updateBox(false).intersectsBox(box);
|
|
50
66
|
}
|
|
51
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Updates the helper's bounding box based on the gameObject's position and scale
|
|
70
|
+
* @param force Whether to force an update regardless of frame count
|
|
71
|
+
* @returns The updated {@link Box3}
|
|
72
|
+
*/
|
|
52
73
|
public updateBox(force: boolean = false): Box3 {
|
|
53
74
|
if (!this.box) {
|
|
54
75
|
this.box = new Box3();
|
|
@@ -74,6 +95,11 @@ export class BoxHelperComponent extends Behaviour {
|
|
|
74
95
|
this.box = null;
|
|
75
96
|
}
|
|
76
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Creates and displays a visual wireframe representation of this box helper
|
|
100
|
+
* @param col Optional color for the wireframe. If not provided, uses default color
|
|
101
|
+
* @param force If true, shows the helper even if gizmos are disabled
|
|
102
|
+
*/
|
|
77
103
|
public showHelper(col: ColorRepresentation | null = null, force: boolean = false) {
|
|
78
104
|
if (!gizmos && !force) return;
|
|
79
105
|
if (this._helper) {
|