@@ -1,12 +1,9 @@
|
|
1
1
|
import { NEEDLE_techniques_webgl } from "./NEEDLE_techniques_webgl.js";
|
2
|
-
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
2
|
+
import { GLTFLoader, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader.js";
|
3
3
|
import { NEEDLE_components } from "./NEEDLE_components.js";
|
4
4
|
import { EXT_texture_exr } from "./EXT_texture_exr.js";
|
5
5
|
import { NEEDLE_gameobject_data } from "./NEEDLE_gameobject_data.js";
|
6
|
-
// import { NEEDLE_timeline } from "./NEEDLE_timeline.js";
|
7
|
-
// import { NEEDLE_animator_controller } from "./NEEDLE_animator_controller.js";
|
8
6
|
import { NEEDLE_persistent_assets } from "./NEEDLE_persistent_assets.js";
|
9
|
-
// import { KHR_animation_pointer } from "./KHR_animation_pointer.js";
|
10
7
|
import { NEEDLE_lightmaps } from "../extensions/NEEDLE_lightmaps.js";
|
11
8
|
import { type ConstructorConcrete, type SourceIdentifier } from "../engine_types.js";
|
12
9
|
import { Context } from "../engine_setup.js";
|
@@ -15,10 +12,9 @@
|
|
15
12
|
import { NEEDLE_progressive } from "./NEEDLE_progressive.js";
|
16
13
|
import { InternalUsageTrackerPlugin } from "./usage_tracker.js";
|
17
14
|
import { isResourceTrackingEnabled } from "../engine_assetdatabase.js";
|
18
|
-
import { type GLTFLoaderPlugin } from "three/examples/jsm/loaders/GLTFLoader.js";
|
19
15
|
import { getParam } from "../engine_utils.js";
|
20
16
|
import { isDevEnvironment } from "../debug/index.js";
|
21
|
-
|
17
|
+
import { GLTFExporter, GLTFExporterPlugin, GLTFWriter } from "three/examples/jsm/exporters/GLTFExporter.js";
|
22
18
|
|
23
19
|
const debug = getParam("debugextensions");
|
24
20
|
|
@@ -31,20 +27,32 @@
|
|
31
27
|
console.warn("Failed to import GLTFLoaderAnimationPointer. Please use @needle-tools/three for full KHR_animation support", e);
|
32
28
|
});
|
33
29
|
|
34
|
-
const _addedCustomExtension = new Array<ConstructorConcrete<GLTFLoaderPlugin>>();
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
declare type OnImportCallback = (loader: GLTFLoader, sourceId: SourceIdentifier, context: Context) => void;
|
32
|
+
declare type OnExportCallback = (exp: GLTFExporter, context: Context) => void;
|
33
|
+
|
34
|
+
export interface INeedleGLTFExtensionPlugin {
|
35
|
+
name: string;
|
36
|
+
onImport?: OnImportCallback;
|
37
|
+
onExport?: OnExportCallback
|
38
|
+
}
|
39
|
+
|
40
|
+
/** Register callbacks for registering custom gltf importer or exporter plugins */
|
41
|
+
export function addCustomExtensionPlugin(ext: INeedleGLTFExtensionPlugin) {
|
42
|
+
if (!_plugins.includes(ext)) {
|
43
|
+
_plugins.push(ext);
|
40
44
|
}
|
41
45
|
}
|
42
|
-
|
43
|
-
|
46
|
+
/** Unregister callbacks for registering custom gltf importer or exporter plugins */
|
47
|
+
export function removeCustomImportExtensionType(ext: INeedleGLTFExtensionPlugin) {
|
48
|
+
const index = _plugins.indexOf(ext);
|
44
49
|
if (index >= 0)
|
45
|
-
|
50
|
+
_plugins.splice(index, 1);
|
46
51
|
}
|
52
|
+
const _plugins = new Array<INeedleGLTFExtensionPlugin>();
|
47
53
|
|
54
|
+
|
55
|
+
/** Registers the Needle Engine components extension */
|
48
56
|
export function registerComponentExtension(loader: GLTFLoader): NEEDLE_components {
|
49
57
|
const ext = new NEEDLE_components();
|
50
58
|
loader.register(p => {
|
@@ -83,8 +91,9 @@
|
|
83
91
|
loader.register(p => new EXT_texture_exr(p));
|
84
92
|
if (isResourceTrackingEnabled()) loader.register(p => new InternalUsageTrackerPlugin(p))
|
85
93
|
|
86
|
-
for (const
|
87
|
-
|
94
|
+
for (const plugin of _plugins) {
|
95
|
+
if (plugin.onImport) plugin.onImport(loader, sourceId, context);
|
96
|
+
}
|
88
97
|
|
89
98
|
await KHR_ANIMATIONPOINTER_IMPORT.catch(_ => { })
|
90
99
|
loader.register(p => {
|
@@ -102,4 +111,9 @@
|
|
102
111
|
}
|
103
112
|
});
|
104
113
|
|
114
|
+
}
|
115
|
+
|
116
|
+
export function registerExportExtensions(exp: GLTFExporter, context: Context) {
|
117
|
+
for (const ext of _plugins)
|
118
|
+
if (ext.onExport) ext.onExport(exp, context);
|
105
119
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Object3D, Vector3 } from "three";
|
2
|
-
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
|
2
|
+
import { GLTFExporter, type GLTFExporterOptions } from 'three/examples/jsm/exporters/GLTFExporter.js';
|
3
3
|
|
4
4
|
import { Behaviour, GameObject } from "../../Component.js";
|
5
5
|
import GLTFMeshGPUInstancingExtension from '../../../include/three/EXT_mesh_gpu_instancing_exporter.js';
|
@@ -11,11 +11,11 @@
|
|
11
11
|
import { BoxHelperComponent } from "../../BoxHelperComponent.js";
|
12
12
|
import { AnimationClip } from "three";
|
13
13
|
import { getParam } from "../../../engine/engine_utils.js";
|
14
|
+
import { registerExportExtensions } from "../../../engine/extensions/index.js";
|
14
15
|
|
15
16
|
const debugExport = getParam("debuggltfexport");
|
16
17
|
|
17
|
-
declare type ExportOptions = {
|
18
|
-
binary: boolean,
|
18
|
+
declare type ExportOptions = GLTFExporterOptions & {
|
19
19
|
pivot?: THREE.Vector3
|
20
20
|
}
|
21
21
|
|
@@ -34,7 +34,6 @@
|
|
34
34
|
@serializable(Object3D)
|
35
35
|
objects: Object3D[] = [];
|
36
36
|
|
37
|
-
private exporter?: GLTFExporter;
|
38
37
|
private ext?: NEEDLE_components;
|
39
38
|
|
40
39
|
async exportNow(name: string) {
|
@@ -70,16 +69,11 @@
|
|
70
69
|
return;
|
71
70
|
}
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
72
|
+
// Instantiate a exporter
|
73
|
+
const exporter = new GLTFExporter();
|
74
|
+
exporter.register(writer => new GLTFMeshGPUInstancingExtension(writer));
|
75
|
+
registerExportExtensions(exporter, this.context);
|
77
76
|
|
78
|
-
// TODO
|
79
|
-
// this.ext = new NEEDLE_components();
|
80
|
-
// this.ext.registerExport(this.exporter);
|
81
|
-
}
|
82
|
-
|
83
77
|
GltfExport.filterTopmostParent(objectsToExport);
|
84
78
|
|
85
79
|
// TODO export only worldglb BUT exclude "World" child which contains all build tools
|
@@ -90,11 +84,12 @@
|
|
90
84
|
trs: false,
|
91
85
|
onlyVisible: true,
|
92
86
|
truncateDrawRange: false,
|
93
|
-
binary:
|
87
|
+
binary: true,
|
94
88
|
maxTextureSize: Infinity, // To prevent NaN value,
|
95
89
|
embedImages: true,
|
96
90
|
includeCustomExtensions: true,
|
97
|
-
animations: GltfExport.collectAnimations(objectsToExport),
|
91
|
+
animations: opts?.animations || GltfExport.collectAnimations(objectsToExport),
|
92
|
+
...opts
|
98
93
|
};
|
99
94
|
|
100
95
|
// hide objects that we don't want to export
|
@@ -128,7 +123,7 @@
|
|
128
123
|
if (debugExport) console.log("Starting glTF export.")
|
129
124
|
try {
|
130
125
|
// Parse the input and generate the glTF output
|
131
|
-
|
126
|
+
exporter?.parse(
|
132
127
|
exportScene,
|
133
128
|
// called when the gltf has been generated
|
134
129
|
res => {
|
@@ -140,7 +135,6 @@
|
|
140
135
|
cleanup();
|
141
136
|
reject(err);
|
142
137
|
},
|
143
|
-
//@ts-ignore
|
144
138
|
options
|
145
139
|
);
|
146
140
|
}
|
@@ -1,3 +1,3 @@
|
|
1
1
|
export { USDZExporter } from "./USDZExporter.js";
|
2
|
-
export { USDObject } from "./ThreeUSDZExporter.js";
|
2
|
+
export { USDObject, imageToCanvas } from "./ThreeUSDZExporter.js";
|
3
3
|
export { type UsdzBehaviour } from "./extensions/behavior/Behaviour.js";
|
@@ -8,7 +8,7 @@
|
|
8
8
|
import { AxesHelper, Material, Matrix4, Mesh, Object3D, SkinnedMesh, Texture, Vector4 } from "three";
|
9
9
|
import { NEEDLE_render_objects } from "../engine/extensions/NEEDLE_render_objects.js";
|
10
10
|
import { NEEDLE_progressive } from "../engine/extensions/NEEDLE_progressive.js";
|
11
|
-
import { NEED_UPDATE_INSTANCE_KEY } from "../engine/engine_instancing.js";
|
11
|
+
import { InstancingUtil, NEED_UPDATE_INSTANCE_KEY } from "../engine/engine_instancing.js";
|
12
12
|
import type { IRenderer, ISharedMaterials } from "../engine/engine_types.js";
|
13
13
|
import { ReflectionProbe } from "./ReflectionProbe.js";
|
14
14
|
import { setCustomVisibility } from "../engine/js-extensions/Layers.js";
|
@@ -505,6 +505,9 @@
|
|
505
505
|
start() {
|
506
506
|
if (this.enableInstancing && !suppressInstancing) {
|
507
507
|
this.setInstancingEnabled(true);
|
508
|
+
// make sure the instance is marked dirty once for cases where e.g. an animator animates the instanced object
|
509
|
+
// in the first frame we want the updated matrix then to be applied immediately to the instancing
|
510
|
+
InstancingUtil.markDirty(this.gameObject);
|
508
511
|
}
|
509
512
|
this.gameObject.frustumCulled = this.allowOcclusionWhenDynamic;
|
510
513
|
if (this.isMultiMaterialObject(this.gameObject)) {
|