@needle-tools/engine 2.51.0-pre → 2.53.0-pre
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 +18 -0
- package/dist/needle-engine.d.ts +243 -56
- package/dist/needle-engine.js +380 -381
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +41 -42
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/engine_components.js +2 -2
- package/lib/engine/engine_components.js.map +1 -1
- package/lib/engine/engine_networking_instantiate.d.ts +1 -1
- package/lib/engine/engine_networking_instantiate.js +3 -0
- package/lib/engine/engine_networking_instantiate.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.d.ts +6 -0
- package/lib/engine/engine_serialization_builtin_serializer.js +31 -6
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/engine_serialization_core.d.ts +1 -0
- package/lib/engine/engine_serialization_core.js +6 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_setup.js +2 -2
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_texture.d.ts +3 -0
- package/lib/engine/engine_texture.js +4 -0
- package/lib/engine/engine_texture.js.map +1 -0
- package/lib/engine/engine_utils.d.ts +2 -0
- package/lib/engine/engine_utils.js +9 -0
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/{NEEDLE_deferred_texture.d.ts → NEEDLE_progressive.d.ts} +2 -2
- package/lib/engine/extensions/{NEEDLE_deferred_texture.js → NEEDLE_progressive.js} +10 -9
- package/lib/engine/extensions/NEEDLE_progressive.js.map +1 -0
- package/lib/engine/extensions/extensions.js +2 -2
- package/lib/engine/extensions/extensions.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +8 -2
- package/lib/engine-components/Camera.js +56 -4
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/EventTrigger.d.ts +10 -1
- package/lib/engine-components/EventTrigger.js +47 -0
- package/lib/engine-components/EventTrigger.js.map +1 -1
- package/lib/engine-components/Light.js +6 -2
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +6 -2
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/ParticleSystemModules.js +0 -1
- package/lib/engine-components/ParticleSystemModules.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +1 -0
- package/lib/engine-components/Renderer.js +13 -6
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/ShadowCatcher.js +5 -6
- package/lib/engine-components/ShadowCatcher.js.map +1 -1
- package/lib/engine-components/Skybox.d.ts +1 -0
- package/lib/engine-components/Skybox.js +5 -0
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/SpriteRenderer.d.ts +19 -3
- package/lib/engine-components/SpriteRenderer.js +154 -41
- package/lib/engine-components/SpriteRenderer.js.map +1 -1
- package/lib/engine-components/Voip.js +13 -4
- package/lib/engine-components/Voip.js.map +1 -1
- package/lib/engine-components/WebXRRig.js +12 -0
- package/lib/engine-components/WebXRRig.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +7 -2
- package/lib/engine-components/codegen/components.js +7 -2
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/export/{GltfExport.d.ts → gltf/GltfExport.d.ts} +2 -2
- package/lib/engine-components/export/{GltfExport.js → gltf/GltfExport.js} +7 -7
- package/lib/engine-components/export/gltf/GltfExport.js.map +1 -0
- package/lib/engine-components/export/usdz/Extension.d.ts +9 -0
- package/lib/engine-components/export/usdz/Extension.js +2 -0
- package/lib/engine-components/export/usdz/Extension.js.map +1 -0
- package/lib/engine-components/export/usdz/USDZExporter.d.ts +25 -0
- package/lib/engine-components/export/usdz/USDZExporter.js +193 -0
- package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -0
- package/lib/engine-components/export/usdz/extensions/Animation.d.ts +44 -0
- package/lib/engine-components/export/usdz/extensions/Animation.js +264 -0
- package/lib/engine-components/export/usdz/extensions/Animation.js.map +1 -0
- package/lib/engine-components/export/usdz/types.d.ts +34 -0
- package/lib/engine-components/export/usdz/types.js +2 -0
- package/lib/engine-components/export/usdz/types.js.map +1 -0
- package/lib/engine-components/export/usdz/utils/animationutils.d.ts +3 -0
- package/lib/engine-components/export/usdz/utils/animationutils.js +46 -0
- package/lib/engine-components/export/usdz/utils/animationutils.js.map +1 -0
- package/lib/engine-components/export/usdz/utils/quicklook.d.ts +2 -0
- package/lib/engine-components/export/usdz/utils/quicklook.js +36 -0
- package/lib/engine-components/export/usdz/utils/quicklook.js.map +1 -0
- package/lib/engine-components/export/usdz/utils/timeutils.d.ts +1 -0
- package/lib/engine-components/export/usdz/utils/timeutils.js +15 -0
- package/lib/engine-components/export/usdz/utils/timeutils.js.map +1 -0
- package/lib/engine-components/timeline/PlayableDirector.js +6 -0
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/ui/Graphic.d.ts +2 -0
- package/lib/engine-components/ui/Graphic.js +15 -0
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Utils.d.ts +2 -1
- package/lib/engine-components/ui/Utils.js +5 -3
- package/lib/engine-components/ui/Utils.js.map +1 -1
- package/package.json +2 -2
- package/src/engine/codegen/register_types.js +16 -6
- package/src/engine/engine_components.ts +2 -2
- package/src/engine/engine_networking_instantiate.ts +4 -1
- package/src/engine/engine_serialization_builtin_serializer.ts +35 -7
- package/src/engine/engine_serialization_core.ts +7 -1
- package/src/engine/engine_setup.ts +2 -2
- package/src/engine/engine_texture.ts +6 -0
- package/src/engine/engine_utils.ts +13 -2
- package/src/engine/extensions/{NEEDLE_deferred_texture.ts → NEEDLE_progressive.ts} +18 -17
- package/src/engine/extensions/extensions.ts +2 -2
- package/src/engine-components/Camera.ts +53 -5
- package/src/engine-components/EventTrigger.ts +39 -19
- package/src/engine-components/Light.ts +6 -2
- package/src/engine-components/OrbitControls.ts +7 -3
- package/src/engine-components/ParticleSystemModules.ts +0 -3
- package/src/engine-components/Renderer.ts +13 -7
- package/src/engine-components/ShadowCatcher.ts +5 -6
- package/src/engine-components/Skybox.ts +4 -0
- package/src/engine-components/SpriteRenderer.ts +140 -44
- package/src/engine-components/Voip.ts +14 -4
- package/src/engine-components/WebXRRig.ts +14 -1
- package/src/engine-components/codegen/components.ts +7 -2
- package/src/engine-components/export/{GltfExport.ts → gltf/GltfExport.ts} +7 -7
- package/src/engine-components/export/usdz/Extension.ts +12 -0
- package/src/engine-components/export/usdz/USDZExporter.ts +216 -0
- package/src/engine-components/export/usdz/extensions/Animation.ts +306 -0
- package/src/engine-components/export/usdz/types.ts +39 -0
- package/src/engine-components/export/usdz/utils/animationutils.ts +60 -0
- package/src/engine-components/export/usdz/utils/quicklook.ts +43 -0
- package/src/engine-components/export/usdz/utils/timeutils.ts +20 -0
- package/src/engine-components/timeline/PlayableDirector.ts +5 -0
- package/src/engine-components/ui/Graphic.ts +15 -1
- package/src/engine-components/ui/Utils.ts +5 -3
- package/lib/engine/extensions/NEEDLE_deferred_texture.js.map +0 -1
- package/lib/engine-components/export/GltfExport.js.map +0 -1
|
@@ -1,9 +1,48 @@
|
|
|
1
1
|
import { Behaviour } from "./Component";
|
|
2
2
|
import * as THREE from "three";
|
|
3
|
-
import { serializable } from "../engine/engine_serialization_decorator";
|
|
4
|
-
import { Color, Material, Texture } from "three";
|
|
3
|
+
import { serializable, serializeable } from "../engine/engine_serialization_decorator";
|
|
4
|
+
import { Color, Material, NearestFilter, Texture, Vector2, TextureFilter } from "three";
|
|
5
5
|
import { RGBAColor } from "./js-extensions/RGBAColor";
|
|
6
|
+
import { getParam } from "../engine/engine_utils";
|
|
6
7
|
|
|
8
|
+
const debug = getParam("debugspriterenderer")
|
|
9
|
+
|
|
10
|
+
class SpriteUtils {
|
|
11
|
+
|
|
12
|
+
static cache: { [key: string]: THREE.BufferGeometry } = {};
|
|
13
|
+
|
|
14
|
+
static getOrCreateGeometry(sprite: Sprite): THREE.BufferGeometry {
|
|
15
|
+
if (sprite._geometry) return sprite._geometry;
|
|
16
|
+
if (sprite.guid) {
|
|
17
|
+
if (SpriteUtils.cache[sprite.guid]) {
|
|
18
|
+
if (debug) console.log("Take cached geometry for sprite", sprite.guid);
|
|
19
|
+
return SpriteUtils.cache[sprite.guid];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const geo = new THREE.BufferGeometry();
|
|
23
|
+
sprite._geometry = geo;
|
|
24
|
+
const vertices = new Float32Array(sprite.triangles.length * 3);
|
|
25
|
+
const uvs = new Float32Array(sprite.triangles.length * 2);
|
|
26
|
+
for (let i = 0; i < sprite.triangles.length; i += 1) {
|
|
27
|
+
const index = sprite.triangles[i];
|
|
28
|
+
|
|
29
|
+
vertices[i * 3] = -sprite.vertices[index].x;
|
|
30
|
+
vertices[i * 3 + 1] = sprite.vertices[index].y;
|
|
31
|
+
|
|
32
|
+
vertices[i * 3 + 2] = 0;
|
|
33
|
+
const uv = sprite.uv[index];
|
|
34
|
+
uvs[i * 2] = uv.x;
|
|
35
|
+
uvs[i * 2 + 1] = 1 - uv.y;
|
|
36
|
+
}
|
|
37
|
+
geo.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
|
|
38
|
+
geo.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));
|
|
39
|
+
if (sprite.guid)
|
|
40
|
+
this.cache[sprite.guid] = geo;
|
|
41
|
+
if (debug)
|
|
42
|
+
console.log("Built sprite geometry", sprite, geo);
|
|
43
|
+
return geo;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
7
46
|
|
|
8
47
|
/// <summary>
|
|
9
48
|
/// <para>SpriteRenderer draw mode.</para>
|
|
@@ -30,42 +69,59 @@ class Vec2 {
|
|
|
30
69
|
|
|
31
70
|
export class Sprite {
|
|
32
71
|
|
|
72
|
+
@serializable()
|
|
73
|
+
guid?: string;
|
|
33
74
|
@serializable(Texture)
|
|
34
75
|
texture?: THREE.Texture;
|
|
35
|
-
|
|
76
|
+
@serializeable()
|
|
36
77
|
triangles!: Array<number>;
|
|
78
|
+
@serializeable()
|
|
37
79
|
uv!: Array<Vec2>;
|
|
80
|
+
@serializeable()
|
|
38
81
|
vertices!: Array<Vec2>;
|
|
39
82
|
|
|
40
83
|
_geometry?: THREE.BufferGeometry;
|
|
41
84
|
}
|
|
42
85
|
|
|
43
|
-
class SpriteUtils {
|
|
44
86
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
87
|
+
class Slice {
|
|
88
|
+
@serializable()
|
|
89
|
+
name!: string;
|
|
90
|
+
@serializable(Vector2)
|
|
91
|
+
offset!: Vector2;
|
|
92
|
+
@serializable(Vector2)
|
|
93
|
+
size!: Vector2;
|
|
94
|
+
}
|
|
53
95
|
|
|
54
|
-
|
|
55
|
-
vertices[i * 3 + 1] = sprite.vertices[index].y;
|
|
96
|
+
const $spriteTexOwner = Symbol("spriteOwner");
|
|
56
97
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
98
|
+
export class SpriteSheet {
|
|
99
|
+
|
|
100
|
+
@serializable(Sprite)
|
|
101
|
+
sprite?: Sprite;
|
|
102
|
+
@serializable()
|
|
103
|
+
index: number = 0;
|
|
104
|
+
@serializable(Slice)
|
|
105
|
+
slices!: Slice[];
|
|
106
|
+
|
|
107
|
+
update() {
|
|
108
|
+
const index = this.index;
|
|
109
|
+
if (index < 0 || index >= this.slices.length)
|
|
110
|
+
return;
|
|
111
|
+
const slice = this.slices[index];
|
|
112
|
+
let tex = this.sprite?.texture;
|
|
113
|
+
if (!tex) return;
|
|
114
|
+
tex.encoding = THREE.sRGBEncoding;
|
|
115
|
+
tex.offset.set(slice.offset.x, slice.offset.y);
|
|
116
|
+
// aniso > 1 makes the texture blurry
|
|
117
|
+
if (tex.minFilter == NearestFilter && tex.magFilter == NearestFilter)
|
|
118
|
+
tex.anisotropy = 1;
|
|
119
|
+
// tex.repeat.set(slice.size.x, -slice.size.y);
|
|
120
|
+
tex.needsUpdate = true;
|
|
66
121
|
}
|
|
67
122
|
}
|
|
68
123
|
|
|
124
|
+
|
|
69
125
|
export class SpriteRenderer extends Behaviour {
|
|
70
126
|
|
|
71
127
|
@serializable()
|
|
@@ -79,37 +135,69 @@ export class SpriteRenderer extends Behaviour {
|
|
|
79
135
|
@serializable(Material)
|
|
80
136
|
sharedMaterial?: THREE.Material;
|
|
81
137
|
|
|
82
|
-
|
|
83
|
-
|
|
138
|
+
@serializable(SpriteSheet)
|
|
139
|
+
get sprite(): SpriteSheet | undefined {
|
|
140
|
+
return this._spriteSheet;
|
|
84
141
|
}
|
|
85
|
-
set sprite(value:
|
|
86
|
-
if(value === this.
|
|
87
|
-
|
|
88
|
-
|
|
142
|
+
set sprite(value: SpriteSheet | undefined | number) {
|
|
143
|
+
if (value === this._spriteSheet) return;
|
|
144
|
+
if (typeof value === "number") {
|
|
145
|
+
const index = Math.floor(value);;
|
|
146
|
+
if (index === value)
|
|
147
|
+
this.spriteIndex = index;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
this._spriteSheet = value;
|
|
152
|
+
this.updateSprite();
|
|
153
|
+
}
|
|
89
154
|
}
|
|
90
155
|
|
|
91
|
-
|
|
156
|
+
set spriteIndex(value: number) {
|
|
157
|
+
if (!this._spriteSheet) return;
|
|
158
|
+
this._spriteSheet.index = value;
|
|
159
|
+
this._spriteSheet.update();
|
|
160
|
+
}
|
|
161
|
+
get spriteIndex(): number {
|
|
162
|
+
return this._spriteSheet?.index ?? 0;
|
|
163
|
+
}
|
|
164
|
+
get spriteFrames(): number {
|
|
165
|
+
return this._spriteSheet?.slices.length ?? 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private _spriteSheet?: SpriteSheet;
|
|
92
169
|
private _currentSprite?: THREE.Mesh;
|
|
93
170
|
|
|
94
171
|
awake(): void {
|
|
95
172
|
this._currentSprite = undefined;
|
|
173
|
+
if(debug) {
|
|
174
|
+
console.log("Awake", this.name, this, this.sprite?.sprite?.texture);
|
|
175
|
+
if(this.sprite?.sprite?.texture)
|
|
176
|
+
console.log(this.sprite.sprite.texture.minFilter.toString(), this.sprite.sprite.texture.magFilter.toString());
|
|
177
|
+
}
|
|
96
178
|
}
|
|
97
179
|
|
|
98
180
|
start() {
|
|
99
|
-
if (this.drawMode === SpriteDrawMode.Tiled) {
|
|
100
|
-
console.warn("Tiled draw mode is not supported yet", this);
|
|
101
|
-
}
|
|
102
181
|
if (!this._currentSprite)
|
|
103
182
|
this.updateSprite();
|
|
104
183
|
else if (this.gameObject)
|
|
105
184
|
this.gameObject.add(this._currentSprite);
|
|
106
185
|
}
|
|
107
186
|
|
|
187
|
+
// frame : number = 0;
|
|
188
|
+
// update(){
|
|
189
|
+
// // const frameRate = 12;
|
|
190
|
+
// // this.frame += frameRate * this.context.time.deltaTime;
|
|
191
|
+
// // if(this.frame >= this.spriteFrames)
|
|
192
|
+
// // this.frame = 0;
|
|
193
|
+
// // this.spriteIndex = Math.floor(this.frame);
|
|
194
|
+
// // console.log(this.spriteIndex);
|
|
195
|
+
// }
|
|
196
|
+
|
|
108
197
|
private updateSprite() {
|
|
109
198
|
if (!this.__didAwake) return;
|
|
110
|
-
if (!this.sprite) return;
|
|
111
|
-
|
|
112
|
-
|
|
199
|
+
if (!this.sprite?.sprite) return;
|
|
200
|
+
const sprite = this.sprite.sprite;
|
|
113
201
|
if (!this._currentSprite) {
|
|
114
202
|
const mat = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide });
|
|
115
203
|
if (!mat) return;
|
|
@@ -120,17 +208,23 @@ export class SpriteRenderer extends Behaviour {
|
|
|
120
208
|
}
|
|
121
209
|
mat.alphaTest = 0.5;
|
|
122
210
|
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
//
|
|
126
|
-
|
|
211
|
+
if (sprite.texture && !mat.wireframe) {
|
|
212
|
+
let tex = sprite.texture;
|
|
213
|
+
// the sprite renderer modifies the textue offset
|
|
214
|
+
// so we need to clone the texture
|
|
215
|
+
// if the same texture is used multiple times
|
|
216
|
+
if (tex[$spriteTexOwner] !== undefined && tex[$spriteTexOwner] !== this && this.spriteFrames > 1) {
|
|
217
|
+
tex = sprite!.texture = tex.clone();
|
|
218
|
+
}
|
|
219
|
+
tex[$spriteTexOwner] = this;
|
|
220
|
+
mat["map"] = tex;
|
|
127
221
|
}
|
|
128
|
-
|
|
129
|
-
this._currentSprite = new THREE.Mesh(SpriteUtils.getOrCreateGeometry(
|
|
222
|
+
this.sharedMaterial = mat;
|
|
223
|
+
this._currentSprite = new THREE.Mesh(SpriteUtils.getOrCreateGeometry(sprite), mat);
|
|
130
224
|
}
|
|
131
225
|
else {
|
|
132
|
-
this._currentSprite.geometry = SpriteUtils.getOrCreateGeometry(
|
|
133
|
-
this._currentSprite.material["map"] =
|
|
226
|
+
this._currentSprite.geometry = SpriteUtils.getOrCreateGeometry(sprite);
|
|
227
|
+
this._currentSprite.material["map"] = sprite.texture;
|
|
134
228
|
}
|
|
135
229
|
|
|
136
230
|
if (this._currentSprite.parent !== this.gameObject) {
|
|
@@ -139,5 +233,7 @@ export class SpriteRenderer extends Behaviour {
|
|
|
139
233
|
if (this.gameObject)
|
|
140
234
|
this.gameObject.add(this._currentSprite);
|
|
141
235
|
}
|
|
236
|
+
|
|
237
|
+
this._spriteSheet?.update();
|
|
142
238
|
}
|
|
143
239
|
}
|
|
@@ -307,6 +307,11 @@ export class Voip extends Behaviour {
|
|
|
307
307
|
return;
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
+
if (utils.isiOS() && utils.isSafari()) {
|
|
311
|
+
console.log("VOIP is currently not supported on Safari iOS")
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
310
315
|
this.peer = new Peer();
|
|
311
316
|
navigator["getUserMedia"] = (navigator["getUserMedia"] || navigator["webkitGetUserMedia"] || navigator["mozGetUserMedia"] || navigator["msGetUserMedia"]);
|
|
312
317
|
|
|
@@ -360,10 +365,15 @@ export class Voip extends Behaviour {
|
|
|
360
365
|
onDisable(): void {
|
|
361
366
|
console.log("TODO: close all");
|
|
362
367
|
for (const key in this.currentIncomingCalls) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
368
|
+
try {
|
|
369
|
+
const call = this.currentIncomingCalls[key];
|
|
370
|
+
call?.close();
|
|
371
|
+
const con = this.connections[key];
|
|
372
|
+
con?.close();
|
|
373
|
+
}
|
|
374
|
+
catch (err) {
|
|
375
|
+
console.error(err);
|
|
376
|
+
}
|
|
367
377
|
}
|
|
368
378
|
}
|
|
369
379
|
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Object3D } from "three";
|
|
2
|
+
import { IGameObject } from "../engine/engine_types";
|
|
3
|
+
import { getParam } from "../engine/engine_utils";
|
|
4
|
+
import { Behaviour, GameObject } from "./Component";
|
|
5
|
+
import { BoxGizmo } from "./Gizmos";
|
|
2
6
|
|
|
7
|
+
const debug = getParam("debugrig");
|
|
3
8
|
|
|
4
9
|
export class XRRig extends Behaviour {
|
|
5
10
|
awake(): void {
|
|
6
11
|
// const helper = new AxesHelper(.1);
|
|
7
12
|
// this.gameObject.add(helper);
|
|
13
|
+
if (debug) {
|
|
14
|
+
const gizmoObj = new Object3D() as IGameObject;
|
|
15
|
+
gizmoObj.position.y += .5;
|
|
16
|
+
this.gameObject.add(gizmoObj);
|
|
17
|
+
const gizmo = gizmoObj.addNewComponent(BoxGizmo);
|
|
18
|
+
if (gizmo)
|
|
19
|
+
gizmo.isGizmo = false;
|
|
20
|
+
}
|
|
8
21
|
}
|
|
9
22
|
}
|
|
@@ -85,6 +85,7 @@ export { SpatialTriggerReceiver } from "../SpatialTrigger";
|
|
|
85
85
|
export { SpatialTrigger } from "../SpatialTrigger";
|
|
86
86
|
export { SpectatorCamera } from "../SpectatorCamera";
|
|
87
87
|
export { Sprite } from "../SpriteRenderer";
|
|
88
|
+
export { SpriteSheet } from "../SpriteRenderer";
|
|
88
89
|
export { SpriteRenderer } from "../SpriteRenderer";
|
|
89
90
|
export { SyncedCamera } from "../SyncedCamera";
|
|
90
91
|
export { SyncedRoom } from "../SyncedRoom";
|
|
@@ -122,8 +123,6 @@ export { Avatar_Brain_LookAt } from "../avatar/Avatar_Brain_LookAt";
|
|
|
122
123
|
export { Avatar_MouthShapes } from "../avatar/Avatar_MouthShapes";
|
|
123
124
|
export { Avatar_MustacheShake } from "../avatar/Avatar_MustacheShake";
|
|
124
125
|
export { LogStats } from "../debug/LogStats";
|
|
125
|
-
export { GltfExportBox } from "../export/GltfExport";
|
|
126
|
-
export { GltfExport } from "../export/GltfExport";
|
|
127
126
|
export { RGBAColor } from "../js-extensions/RGBAColor";
|
|
128
127
|
export { PlayableDirector } from "../timeline/PlayableDirector";
|
|
129
128
|
export { SignalAsset } from "../timeline/SignalAsset";
|
|
@@ -159,3 +158,9 @@ export { Rect } from "../ui/RectTransform";
|
|
|
159
158
|
export { RectTransform } from "../ui/RectTransform";
|
|
160
159
|
export { SpatialHtml } from "../ui/SpatialHtml";
|
|
161
160
|
export { Text } from "../ui/Text";
|
|
161
|
+
export { GltfExportBox } from "../export/gltf/GltfExport";
|
|
162
|
+
export { GltfExport } from "../export/gltf/GltfExport";
|
|
163
|
+
export { USDZExporter } from "../export/usdz/USDZExporter";
|
|
164
|
+
export { RegisteredAnimationInfo } from "../export/usdz/extensions/Animation";
|
|
165
|
+
export { TransformData } from "../export/usdz/extensions/Animation";
|
|
166
|
+
export { AnimationExtension } from "../export/usdz/extensions/Animation";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Behaviour, GameObject } from "
|
|
1
|
+
import { Behaviour, GameObject } from "../../Component";
|
|
2
2
|
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
|
|
3
|
-
import GLTFMeshGPUInstancingExtension from '
|
|
4
|
-
import { Renderer } from "
|
|
3
|
+
import GLTFMeshGPUInstancingExtension from '../../../include/three/EXT_mesh_gpu_instancing_exporter.js';
|
|
4
|
+
import { Renderer } from "../../Renderer";
|
|
5
5
|
import { Object3D, Vector3 } from "three";
|
|
6
|
-
import { SerializationContext } from "
|
|
7
|
-
import { NEEDLE_components } from "
|
|
8
|
-
import { getWorldPosition } from "
|
|
9
|
-
import { BoxHelperComponent } from "
|
|
6
|
+
import { SerializationContext } from "../../../engine/engine_serialization_core";
|
|
7
|
+
import { NEEDLE_components } from "../../../engine/extensions/NEEDLE_components";
|
|
8
|
+
import { getWorldPosition } from "../../../engine/engine_three_utils";
|
|
9
|
+
import { BoxHelperComponent } from "../../BoxHelperComponent";
|
|
10
10
|
import { AnimationClip } from "three";
|
|
11
11
|
|
|
12
12
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { USDZObject } from "./types";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export interface IUSDZExporterExtension {
|
|
5
|
+
|
|
6
|
+
get extensionName(): string;
|
|
7
|
+
onBeforeBuildDocument?(context);
|
|
8
|
+
onAfterBuildDocument?(context);
|
|
9
|
+
onExportObject?(object, model : USDZObject, context);
|
|
10
|
+
onAfterSerialize?(context);
|
|
11
|
+
onAfterHierarchy?(context);
|
|
12
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { delay, getParam, isiOS, isMobileDevice, isSafari } from "../../../engine/engine_utils";
|
|
2
|
+
import { Object3D, Color } from "three";
|
|
3
|
+
import * as THREE from "three";
|
|
4
|
+
import { USDZExporter as ThreeUSDZExporter } from "three/examples/jsm/exporters/USDZExporter";
|
|
5
|
+
import { AnimationExtension } from "./extensions/Animation"
|
|
6
|
+
import { ensureQuicklookLinkIsCreated } from "./utils/quicklook";
|
|
7
|
+
import { getFormattedDate } from "./utils/timeutils";
|
|
8
|
+
import { registerAnimatorsImplictly } from "./utils/animationutils";
|
|
9
|
+
import { IUSDZExporterExtension } from "./Extension";
|
|
10
|
+
import { Behaviour, GameObject } from "../../Component";
|
|
11
|
+
import { WebXR } from "../../WebXR"
|
|
12
|
+
import { serializable } from "../../../engine/engine_serialization";
|
|
13
|
+
import { showBalloonWarning } from "../../../engine/debug/debug";
|
|
14
|
+
import { Context } from "../../../engine/engine_setup";
|
|
15
|
+
|
|
16
|
+
const debug = getParam("debugusdz");
|
|
17
|
+
|
|
18
|
+
export type QuickLookOverlay = {
|
|
19
|
+
callToAction?: string;
|
|
20
|
+
checkoutTitle?: string;
|
|
21
|
+
checkoutSubtitle?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class USDZExporter extends Behaviour {
|
|
25
|
+
|
|
26
|
+
@serializable(Object3D)
|
|
27
|
+
objectToExport?: THREE.Object3D;
|
|
28
|
+
|
|
29
|
+
@serializable()
|
|
30
|
+
autoExportAnimations: boolean = false;
|
|
31
|
+
|
|
32
|
+
extensions: IUSDZExporterExtension[] = [];
|
|
33
|
+
|
|
34
|
+
private link!: HTMLAnchorElement;
|
|
35
|
+
private webxr?: WebXR;
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
start() {
|
|
39
|
+
if (debug) {
|
|
40
|
+
window.addEventListener("keydown", (evt) => {
|
|
41
|
+
switch (evt.key) {
|
|
42
|
+
case "t":
|
|
43
|
+
this.exportAsync();
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
if (isMobileDevice()) {
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
this.exportAsync();
|
|
50
|
+
}, 2000)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
document.getElementById("open-in-ar")?.addEventListener("click", (evt) => {
|
|
54
|
+
evt.preventDefault();
|
|
55
|
+
this.exportAsync();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!this.objectToExport) this.objectToExport = this.gameObject;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
onEnable() {
|
|
64
|
+
const ios = isiOS()
|
|
65
|
+
const safari = isSafari();
|
|
66
|
+
if (debug || (ios && safari)) {
|
|
67
|
+
this.createQuicklookButton();
|
|
68
|
+
this.lastCallback = this.quicklookCallback.bind(this);
|
|
69
|
+
this.link = ensureQuicklookLinkIsCreated(this.context);
|
|
70
|
+
this.link.addEventListener('message', this.lastCallback);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
onDisable() {
|
|
75
|
+
this.link?.removeEventListener('message', this.lastCallback);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async exportAsync() {
|
|
79
|
+
if (!this.objectToExport) return;
|
|
80
|
+
|
|
81
|
+
const exporter = new ThreeUSDZExporter();
|
|
82
|
+
const extensions: any = [...this.extensions]
|
|
83
|
+
|
|
84
|
+
// collect animators and their clips
|
|
85
|
+
const animExt = new AnimationExtension();
|
|
86
|
+
extensions.push(animExt);
|
|
87
|
+
|
|
88
|
+
if (this.autoExportAnimations)
|
|
89
|
+
registerAnimatorsImplictly(this.objectToExport, animExt);
|
|
90
|
+
|
|
91
|
+
const eventArgs = { self: this, exporter: exporter, extensions: extensions };
|
|
92
|
+
this.dispatchEvent(new CustomEvent("before-export", { detail: eventArgs }))
|
|
93
|
+
|
|
94
|
+
let name = "needle";
|
|
95
|
+
if (debug) name += "-" + getFormattedDate();
|
|
96
|
+
|
|
97
|
+
//@ts-ignore
|
|
98
|
+
exporter.debug = debug;
|
|
99
|
+
//@ts-ignore
|
|
100
|
+
const arraybuffer = await exporter.parse(this.objectToExport, extensions);
|
|
101
|
+
const blob = new Blob([arraybuffer], { type: 'application/octet-stream' });
|
|
102
|
+
|
|
103
|
+
// second file: USDA (without assets)
|
|
104
|
+
//@ts-ignore
|
|
105
|
+
// const usda = exporter.lastUsda;
|
|
106
|
+
// const blob2 = new Blob([usda], { type: 'text/plain' });
|
|
107
|
+
// this.link.download = name + ".usda";
|
|
108
|
+
// this.link.href = URL.createObjectURL(blob2);
|
|
109
|
+
// this.link.click();
|
|
110
|
+
|
|
111
|
+
// see https://developer.apple.com/documentation/arkit/adding_an_apple_pay_button_or_a_custom_action_in_ar_quick_look
|
|
112
|
+
const overlay = this.buildQuicklookOverlay();
|
|
113
|
+
const callToAction = overlay.callToAction ? encodeURIComponent(overlay.callToAction) : "";
|
|
114
|
+
const checkoutTitle = overlay.checkoutTitle ? encodeURIComponent(overlay.checkoutTitle) : "";
|
|
115
|
+
const checkoutSubtitle = overlay.checkoutSubtitle ? encodeURIComponent(overlay.checkoutSubtitle) : "";
|
|
116
|
+
this.link.href = URL.createObjectURL(blob) + `#callToAction=${callToAction}&checkoutTitle=${checkoutTitle}&checkoutSubtitle=${checkoutSubtitle}&`;
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
if (!this.lastCallback) {
|
|
120
|
+
this.lastCallback = this.quicklookCallback.bind(this);
|
|
121
|
+
this.link.addEventListener('message', this.lastCallback);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// open quicklook
|
|
125
|
+
this.link.download = name + ".usdz";
|
|
126
|
+
this.link.click();
|
|
127
|
+
|
|
128
|
+
// TODO detect QuickLook availability:
|
|
129
|
+
// https://webkit.org/blog/8421/viewing-augmented-reality-assets-in-safari-for-ios/#:~:text=inside%20the%20anchor.-,Feature%20Detection,-To%20detect%20support
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private lastCallback?: any;
|
|
133
|
+
|
|
134
|
+
private quicklookCallback(event) {
|
|
135
|
+
if ((event as any)?.data == '_apple_ar_quicklook_button_tapped') {
|
|
136
|
+
if (debug) showBalloonWarning("Quicklook closed via call to action button");
|
|
137
|
+
this.dispatchEvent(new CustomEvent("quicklook-button-tapped", { detail: this }));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private buildQuicklookOverlay(): QuickLookOverlay {
|
|
142
|
+
const obj: QuickLookOverlay = {};
|
|
143
|
+
obj.callToAction = "Close";
|
|
144
|
+
obj.checkoutTitle = "🌵 Made with Needle";
|
|
145
|
+
obj.checkoutSubtitle = "_";
|
|
146
|
+
// Use the quicklook-overlay event to customize the overlay
|
|
147
|
+
this.dispatchEvent(new CustomEvent("quicklook-overlay", { detail: obj }));
|
|
148
|
+
return obj;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private _arButton?: HTMLElement;
|
|
152
|
+
private async createQuicklookButton() {
|
|
153
|
+
if (!this.webxr) {
|
|
154
|
+
await delay(1);
|
|
155
|
+
this.webxr = GameObject.findObjectOfType(WebXR) ?? undefined;
|
|
156
|
+
if (this.webxr) {
|
|
157
|
+
if(this.webxr.VRButton) this.webxr.VRButton.parentElement?.removeChild(this.webxr.VRButton);
|
|
158
|
+
// check if we have an AR button already and re-use that
|
|
159
|
+
if (this.webxr.ARButton && this._arButton !== this.webxr.ARButton) {
|
|
160
|
+
this._arButton = this.webxr.ARButton;
|
|
161
|
+
// Hack to remove the immersiveweb link
|
|
162
|
+
const linkInButton = this.webxr.ARButton.parentElement?.querySelector("a");
|
|
163
|
+
if (linkInButton) {
|
|
164
|
+
linkInButton.href = "";
|
|
165
|
+
}
|
|
166
|
+
this.webxr.ARButton.innerText = "Open in Quicklook";
|
|
167
|
+
this.webxr.ARButton.disabled = false;
|
|
168
|
+
this.webxr.ARButton.addEventListener("click", evt => {
|
|
169
|
+
evt.preventDefault();
|
|
170
|
+
this.exportAsync();
|
|
171
|
+
});
|
|
172
|
+
this.webxr.ARButton.classList.add("quicklook-ar-button");
|
|
173
|
+
}
|
|
174
|
+
// create a button if WebXR didnt create one yet
|
|
175
|
+
else {
|
|
176
|
+
this.webxr.createARButton = false;
|
|
177
|
+
this.webxr.createVRButton = false;
|
|
178
|
+
let container = window.document.querySelector(".webxr-buttons");
|
|
179
|
+
if (!container) {
|
|
180
|
+
container = document.createElement("div");
|
|
181
|
+
container.classList.add("webxr-buttons");
|
|
182
|
+
}
|
|
183
|
+
const button = document.createElement("button");
|
|
184
|
+
button.innerText = "Open in Quicklook";
|
|
185
|
+
button.addEventListener("click", () => {
|
|
186
|
+
this.exportAsync();
|
|
187
|
+
});
|
|
188
|
+
button.classList.add('webxr-ar-button');
|
|
189
|
+
button.classList.add('webxr-button');
|
|
190
|
+
button.classList.add("quicklook-ar-button");
|
|
191
|
+
container.appendChild(button);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
console.warn("Could not find WebXR component: will not create Quicklook button", Context.Current);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private resetStyles(el: HTMLElement) {
|
|
201
|
+
el.style.position = "";
|
|
202
|
+
el.style.top = "";
|
|
203
|
+
el.style.left = "";
|
|
204
|
+
el.style.width = "";
|
|
205
|
+
el.style.height = "";
|
|
206
|
+
el.style.margin = "";
|
|
207
|
+
el.style.padding = "";
|
|
208
|
+
el.style.border = "";
|
|
209
|
+
el.style.background = "";
|
|
210
|
+
el.style.color = "";
|
|
211
|
+
el.style.font = "";
|
|
212
|
+
el.style.textAlign = "";
|
|
213
|
+
el.style.opacity = "";
|
|
214
|
+
el.style.zIndex = "";
|
|
215
|
+
}
|
|
216
|
+
}
|