@domgell/gltf-parser 1.0.0 → 1.0.2
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/.idea/copilot.data.migration.agent.xml +6 -0
- package/.idea/copilot.data.migration.ask2agent.xml +6 -0
- package/.idea/copilot.data.migration.edit.xml +6 -0
- package/.idea/gltf-parser.iml +12 -0
- package/.idea/modules.xml +8 -0
- package/package.json +5 -8
- package/src/Parser.ts +25 -21
- package/src/index.ts +2 -2
- package/src/types.ts +259 -244
- package/src/util.ts +59 -67
- package/tsconfig.json +35 -36
- package/.gitattributes +0 -2
- package/gltf-importer.iml +0 -9
- package/index.html +0 -14
- package/res/suzanne.glb +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="WEB_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$">
|
|
5
|
+
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
|
6
|
+
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
|
7
|
+
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
|
8
|
+
</content>
|
|
9
|
+
<orderEntry type="inheritedJdk" />
|
|
10
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
11
|
+
</component>
|
|
12
|
+
</module>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectModuleManager">
|
|
4
|
+
<modules>
|
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/gltf-parser.iml" filepath="$PROJECT_DIR$/.idea/gltf-parser.iml" />
|
|
6
|
+
</modules>
|
|
7
|
+
</component>
|
|
8
|
+
</project>
|
package/package.json
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@domgell/gltf-parser",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"exports": "./src/index.ts",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
-
},
|
|
9
|
-
"keywords": ["gltf", "glb", "mesh", "parser"],
|
|
10
6
|
"author": "domgell",
|
|
11
7
|
"license": "ISC",
|
|
12
8
|
"description": "Parse .GLTF/.GLF files into JS objects",
|
|
9
|
+
"keywords": ["gltf", "glb", "mesh", "parser", "model"],
|
|
13
10
|
"dependencies": {
|
|
14
|
-
"gltf-types": "
|
|
11
|
+
"@domgell/gltf-types": "*",
|
|
12
|
+
"@domgell/ts-util": "*",
|
|
15
13
|
"dom-game-math": "*"
|
|
16
|
-
}
|
|
17
|
-
"devDependencies": {}
|
|
14
|
+
}
|
|
18
15
|
}
|
package/src/Parser.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AccessorArrayType,
|
|
3
3
|
AccessorConstructorType,
|
|
4
|
-
assert,
|
|
5
4
|
chunk,
|
|
6
|
-
fail,
|
|
7
5
|
getTransform,
|
|
8
6
|
} from "./util.ts";
|
|
9
7
|
import * as Parsed from "./types.ts";
|
|
10
|
-
import * as GLTF from "gltf-types";
|
|
8
|
+
import * as GLTF from "@domgell/gltf-types";
|
|
11
9
|
import {mat4, TransformOrder} from "dom-game-math";
|
|
12
10
|
import {Matrix4x4, TextureFilterMap, TextureWrapModeMap} from "./types.ts";
|
|
11
|
+
import {assert, fail} from "@domgell/ts-util";
|
|
13
12
|
|
|
14
|
-
export
|
|
13
|
+
export interface ParserOptions {
|
|
15
14
|
transformOrder: TransformOrder,
|
|
16
15
|
}
|
|
17
16
|
|
|
@@ -30,7 +29,6 @@ export class Parser {
|
|
|
30
29
|
|
|
31
30
|
const data = await r.arrayBuffer();
|
|
32
31
|
const dataView = new DataView(data);
|
|
33
|
-
|
|
34
32
|
let offset = 12;
|
|
35
33
|
|
|
36
34
|
// Get JSON Header
|
|
@@ -39,12 +37,12 @@ export class Parser {
|
|
|
39
37
|
const textDecoder = new TextDecoder("utf-8");
|
|
40
38
|
const json = textDecoder.decode(jsonChunkData);
|
|
41
39
|
const header = JSON.parse(json);
|
|
42
|
-
|
|
43
40
|
offset += 8 + jsonChunkLength;
|
|
44
41
|
|
|
45
42
|
// Get binary data
|
|
46
43
|
const binaryChunkLength = dataView.getUint32(offset, true);
|
|
47
44
|
const binary = new ArrayBuffer(binaryChunkLength);
|
|
45
|
+
|
|
48
46
|
const binaryChunkView = new Uint8Array(binary);
|
|
49
47
|
binaryChunkView.set(new Uint8Array(data, offset + 8, binaryChunkLength));
|
|
50
48
|
|
|
@@ -53,7 +51,10 @@ export class Parser {
|
|
|
53
51
|
|
|
54
52
|
// ----------------------------------- Accessor ------------------------------------
|
|
55
53
|
|
|
56
|
-
accessor<
|
|
54
|
+
accessor<
|
|
55
|
+
T extends AccessorArrayType,
|
|
56
|
+
I extends number | undefined
|
|
57
|
+
>(index: I, type: T): I extends number ? AccessorConstructorType<T> : AccessorConstructorType<T> | undefined {
|
|
57
58
|
if (index === undefined) return undefined as any;
|
|
58
59
|
|
|
59
60
|
assert(this.header.accessors !== undefined, "Accessors are undefined");
|
|
@@ -63,7 +64,6 @@ export class Parser {
|
|
|
63
64
|
?? fail(`Accessor at index ${index} not found`);
|
|
64
65
|
|
|
65
66
|
assert(accessor.bufferView !== undefined, "Accessor bufferView is undefined");
|
|
66
|
-
|
|
67
67
|
const bufferView = this.header.bufferViews[accessor.bufferView];
|
|
68
68
|
const byteOffset = (bufferView.byteOffset ?? 0) + (accessor.byteOffset ?? 0);
|
|
69
69
|
|
|
@@ -79,6 +79,7 @@ export class Parser {
|
|
|
79
79
|
5125: Uint32Array,
|
|
80
80
|
5126: Float32Array,
|
|
81
81
|
}[accessor.componentType];
|
|
82
|
+
|
|
82
83
|
assert(assertType.name === type.name, `Mismatched types: requested '${type.name}' but got '${assertType.name}'`);
|
|
83
84
|
|
|
84
85
|
const byteLength = numComponents * accessor.count * type.BYTES_PER_ELEMENT;
|
|
@@ -89,6 +90,7 @@ export class Parser {
|
|
|
89
90
|
|
|
90
91
|
async mesh(gltfMesh: GLTF.Mesh) {
|
|
91
92
|
const primitives = new Array<Parsed.MeshPrimitive>(gltfMesh.primitives.length);
|
|
93
|
+
|
|
92
94
|
for (let i = 0; i < primitives.length; i++) {
|
|
93
95
|
primitives[i] = await this.primitive(gltfMesh.primitives[i]);
|
|
94
96
|
}
|
|
@@ -133,7 +135,7 @@ export class Parser {
|
|
|
133
135
|
skin(gltfSkin: GLTF.Skin) {
|
|
134
136
|
assert(this.header.nodes !== undefined, "`Nodes` is undefined");
|
|
135
137
|
|
|
136
|
-
// Default
|
|
138
|
+
// Default to array of identity matrices with length = number of joints
|
|
137
139
|
const inverseBindMatrices = gltfSkin.inverseBindMatrices
|
|
138
140
|
? chunk(this.accessor(gltfSkin.inverseBindMatrices, Float32Array), 16)
|
|
139
141
|
: gltfSkin.joints.map(() => Array.from(mat4.idt) as Matrix4x4);
|
|
@@ -152,11 +154,8 @@ export class Parser {
|
|
|
152
154
|
|
|
153
155
|
const children = gltfJoint.children?.map(i => this.header.nodes![i].name!) ?? [];
|
|
154
156
|
|
|
155
|
-
//const inverseBindTransform = inverseBindMatrices[jointIndex];
|
|
156
157
|
const inverseBindTransform = inverseBindMatrices[i];
|
|
157
|
-
|
|
158
158
|
joints[gltfJoint.name] = {name: gltfJoint.name, transform, children, inverseBindTransform};
|
|
159
|
-
|
|
160
159
|
i++;
|
|
161
160
|
}
|
|
162
161
|
|
|
@@ -166,6 +165,7 @@ export class Parser {
|
|
|
166
165
|
// Set parents
|
|
167
166
|
for (let name in joints) {
|
|
168
167
|
const joint = joints[name];
|
|
168
|
+
|
|
169
169
|
for (let childName of joint.children) {
|
|
170
170
|
joints[childName].parent = name;
|
|
171
171
|
}
|
|
@@ -183,6 +183,7 @@ export class Parser {
|
|
|
183
183
|
|
|
184
184
|
// TEMP: Calculate global inverse transform
|
|
185
185
|
const skinParentNode = this.header.nodes.find(n => n.children?.includes(gltfSkin.joints[0]));
|
|
186
|
+
|
|
186
187
|
const globalInverseTransform = skinParentNode
|
|
187
188
|
? getTransform(skinParentNode, this.options.transformOrder)
|
|
188
189
|
: Array.from(mat4.idt) as Matrix4x4;
|
|
@@ -192,6 +193,7 @@ export class Parser {
|
|
|
192
193
|
|
|
193
194
|
animation(gltfAnimation: GLTF.Animation): Parsed.Animation {
|
|
194
195
|
assert(this.header.nodes !== undefined, "`Nodes` is undefined");
|
|
196
|
+
|
|
195
197
|
const channels: Record<string, Parsed.AnimationChannel> = {};
|
|
196
198
|
let duration = 0;
|
|
197
199
|
|
|
@@ -201,18 +203,15 @@ export class Parser {
|
|
|
201
203
|
|
|
202
204
|
// Init channel if not already present
|
|
203
205
|
channels[gltfTargetNode.name] ??= {translation: [], rotation: [], scale: []};
|
|
204
|
-
|
|
205
206
|
const sampler = gltfAnimation.samplers[gltfChannel.sampler];
|
|
206
207
|
const times = this.accessor(sampler.input, Float32Array);
|
|
207
208
|
const values = this.accessor(sampler.output, Float32Array);
|
|
208
|
-
|
|
209
209
|
const numComponents = values.length / times.length;
|
|
210
210
|
assert(numComponents === 3 || numComponents === 4, `Invalid number of components: '${numComponents}'`);
|
|
211
211
|
|
|
212
212
|
// Set keyframes array of current 'path', e.g. 'translation'
|
|
213
213
|
const keyframes = chunk(values, numComponents).map((value, i) => ({time: times[i], value}));
|
|
214
214
|
channels[gltfTargetNode.name][gltfChannel.target.path] = keyframes as any;
|
|
215
|
-
|
|
216
215
|
duration = Math.max(duration, ...keyframes.map(k => k.time));
|
|
217
216
|
}
|
|
218
217
|
|
|
@@ -233,17 +232,17 @@ export class Parser {
|
|
|
233
232
|
|
|
234
233
|
let normal: Parsed.MaterialNormalInfo | undefined;
|
|
235
234
|
if (gltfMaterial.normalTexture !== undefined) {
|
|
236
|
-
fail("TODO");
|
|
235
|
+
fail("TODO: Normal Texture");
|
|
237
236
|
}
|
|
238
237
|
|
|
239
238
|
let emissive: Parsed.MaterialEmissiveInfo | undefined;
|
|
240
239
|
if (gltfMaterial.emissiveTexture !== undefined) {
|
|
241
|
-
fail("TODO");
|
|
240
|
+
fail("TODO: Emissive Texture");
|
|
242
241
|
}
|
|
243
242
|
|
|
244
243
|
let ambientOcclusion: Parsed.MaterialAmbientOcclusionInfo | undefined;
|
|
245
244
|
if (gltfMaterial.occlusionTexture !== undefined) {
|
|
246
|
-
fail("TODO");
|
|
245
|
+
fail("TODO: Occlusion Texture");
|
|
247
246
|
}
|
|
248
247
|
|
|
249
248
|
const alpha: Parsed.MaterialAlphaInfo = {
|
|
@@ -271,6 +270,7 @@ export class Parser {
|
|
|
271
270
|
|
|
272
271
|
// Parse sampler
|
|
273
272
|
const sampler: Parsed.Sampler = {wrap: {s: "repeat", t: "repeat"}, filter: {min: "linear", mag: "linear"}};
|
|
273
|
+
|
|
274
274
|
if (this.header.samplers !== undefined && gltfTexture.sampler !== undefined) {
|
|
275
275
|
const gltfSampler = this.header.samplers[gltfTexture.sampler];
|
|
276
276
|
|
|
@@ -290,22 +290,26 @@ export class Parser {
|
|
|
290
290
|
const response = await fetch(this.path + gltfImage.uri);
|
|
291
291
|
assert(response.ok, `Failed to fetch image at URI: '${gltfImage.uri}'`);
|
|
292
292
|
const blob = await response.blob();
|
|
293
|
+
|
|
293
294
|
return await createImageBitmap(blob);
|
|
294
295
|
}
|
|
295
296
|
// Image from buffer
|
|
296
297
|
else {
|
|
297
298
|
assert(this.header.bufferViews !== undefined, "Header `BufferViews` property is undefined");
|
|
298
299
|
assert(this.header.buffers !== undefined, "Header `Buffers` property is undefined");
|
|
300
|
+
|
|
299
301
|
const bufferView = this.header.bufferViews[gltfImage.bufferView];
|
|
300
302
|
const buffer = this.header.buffers[bufferView.buffer];
|
|
301
303
|
|
|
302
304
|
if (buffer.uri !== undefined) {
|
|
303
|
-
fail("TODO");
|
|
305
|
+
fail("TODO: Buffer URI");
|
|
304
306
|
}
|
|
305
307
|
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
+
const dataBegin = bufferView.byteOffset ?? 0;
|
|
309
|
+
const dataEnd = dataBegin + bufferView.byteLength;
|
|
310
|
+
const data = this.binary.slice(dataBegin, dataEnd);
|
|
308
311
|
const blob = new Blob([new Uint8Array(data)]);
|
|
312
|
+
|
|
309
313
|
return await createImageBitmap(blob);
|
|
310
314
|
}
|
|
311
315
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./types.ts";
|
|
2
|
-
export * from "./Parser.ts";
|
|
1
|
+
export * from "./types.ts";
|
|
2
|
+
export * from "./Parser.ts";
|
package/src/types.ts
CHANGED
|
@@ -1,244 +1,259 @@
|
|
|
1
|
-
import {Tuple} from "./util.ts";
|
|
2
|
-
|
|
3
|
-
export type Matrix4x4 = Tuple<number, 16>
|
|
4
|
-
export type Vector2 = Tuple<number, 2>
|
|
5
|
-
export type Vector3 = Tuple<number, 3>
|
|
6
|
-
export type Vector4 = Tuple<number, 4>
|
|
7
|
-
|
|
8
|
-
// ------------------------------- Scene -------------------------------
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
/**
|
|
12
|
-
* All nodes in scene
|
|
13
|
-
*/
|
|
14
|
-
nodes: Node[]
|
|
15
|
-
cameras: Camera[],
|
|
16
|
-
meshes: Mesh[],
|
|
17
|
-
skins: Skin[],
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
name
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
export
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
export
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
export
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
export
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* The
|
|
196
|
-
*/
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* The
|
|
200
|
-
*/
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* The
|
|
215
|
-
*/
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* The
|
|
219
|
-
*/
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* The
|
|
230
|
-
*/
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* The
|
|
241
|
-
*/
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
1
|
+
import {Tuple} from "./util.ts";
|
|
2
|
+
|
|
3
|
+
export type Matrix4x4 = Tuple<number, 16>
|
|
4
|
+
export type Vector2 = Tuple<number, 2>
|
|
5
|
+
export type Vector3 = Tuple<number, 3>
|
|
6
|
+
export type Vector4 = Tuple<number, 4>
|
|
7
|
+
|
|
8
|
+
// ------------------------------- Scene -------------------------------
|
|
9
|
+
|
|
10
|
+
export interface Scene {
|
|
11
|
+
/**
|
|
12
|
+
* All nodes in scene
|
|
13
|
+
*/
|
|
14
|
+
nodes: Node[]
|
|
15
|
+
cameras: Camera[],
|
|
16
|
+
meshes: Mesh[],
|
|
17
|
+
skins: Skin[],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ------------------------------- Node --------------------------------
|
|
21
|
+
|
|
22
|
+
export type Node = {
|
|
23
|
+
transform: Matrix4x4,
|
|
24
|
+
name?: string,
|
|
25
|
+
children: Node[],
|
|
26
|
+
parent?: Node,
|
|
27
|
+
} & (MeshNode | SkinNode | CameraNode)
|
|
28
|
+
|
|
29
|
+
interface MeshNode {
|
|
30
|
+
mesh: Mesh,
|
|
31
|
+
skin?: undefined,
|
|
32
|
+
camera?: undefined
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface SkinNode {
|
|
36
|
+
skin: Skin,
|
|
37
|
+
mesh?: undefined,
|
|
38
|
+
camera?: undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface CameraNode {
|
|
42
|
+
camera: Camera,
|
|
43
|
+
mesh?: undefined,
|
|
44
|
+
skin?: undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ------------------------------ Camera -------------------------------
|
|
48
|
+
|
|
49
|
+
export interface OrthographicCamera {
|
|
50
|
+
type: "Orthographic"
|
|
51
|
+
xmag: number,
|
|
52
|
+
ymag: number,
|
|
53
|
+
zfar: number,
|
|
54
|
+
znear: number,
|
|
55
|
+
view: Matrix4x4,
|
|
56
|
+
projection: Matrix4x4,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface PerspectiveCamera {
|
|
60
|
+
type: "Perspective"
|
|
61
|
+
aspectRatio: number,
|
|
62
|
+
yfov: number,
|
|
63
|
+
zfar: number,
|
|
64
|
+
znear: number,
|
|
65
|
+
view: Matrix4x4,
|
|
66
|
+
projection: Matrix4x4,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type Camera = OrthographicCamera | PerspectiveCamera
|
|
70
|
+
|
|
71
|
+
// ------------------------------- Mesh --------------------------------
|
|
72
|
+
|
|
73
|
+
export interface MeshPrimitiveAttributes {
|
|
74
|
+
positions: Vector3[],
|
|
75
|
+
uvs?: Vector2[],
|
|
76
|
+
normals?: Vector3[],
|
|
77
|
+
colors?: Vector4[]
|
|
78
|
+
weights?: Vector4[],
|
|
79
|
+
joints?: Vector4[],
|
|
80
|
+
tangents?: Vector4[], // TODO
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface MeshPrimitive {
|
|
84
|
+
/**
|
|
85
|
+
* Vertex attributes of the mesh primitive
|
|
86
|
+
*/
|
|
87
|
+
attributes: MeshPrimitiveAttributes,
|
|
88
|
+
indices?: Uint32Array,
|
|
89
|
+
material?: Material,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface Mesh {
|
|
93
|
+
primitives: MeshPrimitive[],
|
|
94
|
+
name?: string,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// -------------------------------- Skin -------------------------------
|
|
98
|
+
|
|
99
|
+
export interface Joint {
|
|
100
|
+
name: string,
|
|
101
|
+
transform: Matrix4x4,
|
|
102
|
+
inverseBindTransform: Matrix4x4,
|
|
103
|
+
children: string[],
|
|
104
|
+
parent?: string,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface Skin {
|
|
108
|
+
root: Joint,
|
|
109
|
+
joints: Record<string, Joint>,
|
|
110
|
+
animations: Animation[],
|
|
111
|
+
globalInverseTransform: Matrix4x4,
|
|
112
|
+
name?: string,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ----------------------------- Animation -----------------------------
|
|
116
|
+
|
|
117
|
+
export interface Animation {
|
|
118
|
+
duration: number,
|
|
119
|
+
name?: string,
|
|
120
|
+
channels: Record<string, AnimationChannel>,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface AnimationChannel {
|
|
124
|
+
translation: AnimationKeyframe<Vector3>[];
|
|
125
|
+
rotation: AnimationKeyframe<Vector4>[];
|
|
126
|
+
scale: AnimationKeyframe<Vector3>[];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface AnimationKeyframe<T> {
|
|
130
|
+
time: number,
|
|
131
|
+
value: T
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ----------------------------- Texture -------------------------------
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
// TODO: If source is undefined, don't create texture, if sampler is undefined create default sampler
|
|
138
|
+
export interface Texture {
|
|
139
|
+
source: ImageBitmap,
|
|
140
|
+
sampler: Sampler,
|
|
141
|
+
name?: string,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface Sampler {
|
|
145
|
+
wrap: { s: TextureWrapMode, t: TextureWrapMode },
|
|
146
|
+
filter: { min: TextureMinFilter, mag: TextureMagFilter },
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export type TextureMagFilter = "nearest" | "linear"
|
|
150
|
+
|
|
151
|
+
export type TextureMinFilter =
|
|
152
|
+
| "nearest"
|
|
153
|
+
| "linear"
|
|
154
|
+
| "nearest-mipmap-nearest"
|
|
155
|
+
| "linear-mipmap-nearest"
|
|
156
|
+
| "nearest-mipmap-linear"
|
|
157
|
+
| "linear-mipmap-linear"
|
|
158
|
+
|
|
159
|
+
export type TextureWrapMode =
|
|
160
|
+
| "clamp-to-edge"
|
|
161
|
+
| "mirrored-repeat"
|
|
162
|
+
| "repeat"
|
|
163
|
+
|
|
164
|
+
export const TextureWrapModeMap = {
|
|
165
|
+
[33071]: "clamp-to-edge",
|
|
166
|
+
[33648]: "mirrored-repeat",
|
|
167
|
+
[10497]: "repeat",
|
|
168
|
+
} as const;
|
|
169
|
+
|
|
170
|
+
export const TextureFilterMap = {
|
|
171
|
+
[9728]: "nearest",
|
|
172
|
+
[9729]: "linear",
|
|
173
|
+
[9984]: "nearest-mipmap-nearest",
|
|
174
|
+
[9985]: "linear-mipmap-nearest",
|
|
175
|
+
[9986]: "nearest-mipmap-linear",
|
|
176
|
+
[9987]: "linear-mipmap-linear",
|
|
177
|
+
} as const;
|
|
178
|
+
|
|
179
|
+
// ----------------------------- Material ------------------------------
|
|
180
|
+
|
|
181
|
+
export interface Material {
|
|
182
|
+
metallicRoughness: MaterialMetallicRoughnessInfo,
|
|
183
|
+
normal?: MaterialNormalInfo,
|
|
184
|
+
emissive?: MaterialEmissiveInfo,
|
|
185
|
+
ambientOcclusion?: MaterialAmbientOcclusionInfo,
|
|
186
|
+
alpha: MaterialAlphaInfo,
|
|
187
|
+
/**
|
|
188
|
+
* Whether the material is double-sided. Default is `false`.
|
|
189
|
+
*/
|
|
190
|
+
doubleSided: boolean,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface MaterialAlphaInfo {
|
|
194
|
+
/**
|
|
195
|
+
* The alpha rendering mode of the material. Default is `"OPAQUE"`.
|
|
196
|
+
*/
|
|
197
|
+
mode: "OPAQUE" | "MASK" | "BLEND",
|
|
198
|
+
/**
|
|
199
|
+
* The alpha cutoff value of the material. Default is `0.5`.
|
|
200
|
+
*/
|
|
201
|
+
cutoff: number,
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface MaterialMetallicRoughnessInfo {
|
|
205
|
+
/**
|
|
206
|
+
* The base color factor of the material. Default is `[1, 1, 1, 1]`.
|
|
207
|
+
*/
|
|
208
|
+
baseColor: Vector4,
|
|
209
|
+
/**
|
|
210
|
+
* The base color texture of the material.
|
|
211
|
+
*/
|
|
212
|
+
baseColorTexture?: Texture,
|
|
213
|
+
/**
|
|
214
|
+
* The factor for the metalness of the material. Default is `1`.
|
|
215
|
+
*/
|
|
216
|
+
metallicFactor: number,
|
|
217
|
+
/**
|
|
218
|
+
* The factor for the roughness of the material. Default is `1`.
|
|
219
|
+
*/
|
|
220
|
+
roughnessFactor: number,
|
|
221
|
+
/**
|
|
222
|
+
* The metallic roughness texture of the material.
|
|
223
|
+
*/
|
|
224
|
+
metallicRoughnessTexture?: Texture,
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export interface MaterialNormalInfo {
|
|
228
|
+
/**
|
|
229
|
+
* The normal texture of the material.
|
|
230
|
+
*/
|
|
231
|
+
texture: Texture,
|
|
232
|
+
/**
|
|
233
|
+
* The scale applied to each vector of the normal map. Default is `1`.
|
|
234
|
+
*/
|
|
235
|
+
scale: number,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface MaterialEmissiveInfo {
|
|
239
|
+
/**
|
|
240
|
+
* The emissive texture of the material.
|
|
241
|
+
*/
|
|
242
|
+
texture: Texture,
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The emissive factor of the material. Default is `[0, 0, 0]`.
|
|
246
|
+
*/
|
|
247
|
+
factor: Vector3,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export interface MaterialAmbientOcclusionInfo {
|
|
251
|
+
/**
|
|
252
|
+
* The occlusion texture of the material.
|
|
253
|
+
*/
|
|
254
|
+
texture: Texture,
|
|
255
|
+
/**
|
|
256
|
+
* The occlusion strength of the material. Default is `1`.
|
|
257
|
+
*/
|
|
258
|
+
strength: number,
|
|
259
|
+
}
|
package/src/util.ts
CHANGED
|
@@ -1,67 +1,59 @@
|
|
|
1
|
-
import {TransformOrder, mat4, vec3, quat, Matrix4} from "dom-game-math";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
out
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
rotation: transform.rotation && quat.fromArray(transform.rotation),
|
|
61
|
-
scale: transform.scale && vec3.fromArray(transform.scale),
|
|
62
|
-
order,
|
|
63
|
-
}, out as Matrix4);
|
|
64
|
-
|
|
65
|
-
return out;
|
|
66
|
-
}
|
|
67
|
-
|
|
1
|
+
import {TransformOrder, mat4, vec3, quat, Matrix4} from "dom-game-math";
|
|
2
|
+
|
|
3
|
+
// ------------------------------------- Accessor --------------------------------------
|
|
4
|
+
|
|
5
|
+
export type AccessorArrayType =
|
|
6
|
+
| Float32ArrayConstructor
|
|
7
|
+
| Uint32ArrayConstructor
|
|
8
|
+
| Uint16ArrayConstructor
|
|
9
|
+
| Int16ArrayConstructor
|
|
10
|
+
| Uint8ArrayConstructor
|
|
11
|
+
| Int8ArrayConstructor
|
|
12
|
+
|
|
13
|
+
export type AccessorConstructorType<T extends AccessorArrayType> = ReturnType<T["from"]>
|
|
14
|
+
|
|
15
|
+
// --------------------------------------- Tuple ---------------------------------------
|
|
16
|
+
|
|
17
|
+
export type Tuple<T, N extends number> = T[] & { length: N };
|
|
18
|
+
|
|
19
|
+
export function chunk<T, N extends number>(array: Iterable<T>, size: N): Tuple<T, N>[] {
|
|
20
|
+
const result = new Array<T[]>;
|
|
21
|
+
let chunk = new Array<T>();
|
|
22
|
+
|
|
23
|
+
for (const value of Array.from(array)) {
|
|
24
|
+
chunk.push(value);
|
|
25
|
+
|
|
26
|
+
if (chunk.length === size) {
|
|
27
|
+
result.push(chunk);
|
|
28
|
+
chunk = [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (chunk.length) {
|
|
33
|
+
result.push(chunk);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return result as Tuple<T, N>[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getTransform(transform: {
|
|
40
|
+
translation?: number[],
|
|
41
|
+
rotation?: number[],
|
|
42
|
+
scale?: number[]
|
|
43
|
+
}, order: TransformOrder, out?: Tuple<number, 16>) {
|
|
44
|
+
out ??= Array.from(mat4.idt) as Tuple<number, 16>;
|
|
45
|
+
|
|
46
|
+
mat4.compose({
|
|
47
|
+
|
|
48
|
+
translation: transform.translation && vec3.fromArray(transform.translation),
|
|
49
|
+
|
|
50
|
+
rotation: transform.rotation && quat.fromArray(transform.rotation),
|
|
51
|
+
|
|
52
|
+
scale: transform.scale && vec3.fromArray(transform.scale),
|
|
53
|
+
|
|
54
|
+
order,
|
|
55
|
+
|
|
56
|
+
}, out as Matrix4);
|
|
57
|
+
|
|
58
|
+
return out;
|
|
59
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,36 +1,35 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"DOM
|
|
9
|
-
],
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"lib": [
|
|
7
|
+
"ESNext",
|
|
8
|
+
"DOM"
|
|
9
|
+
],
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
/* Bundler mode */
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"noImplicitAny": false,
|
|
18
|
+
/* Linting */
|
|
19
|
+
"strict": true,
|
|
20
|
+
"noUnusedLocals": false,
|
|
21
|
+
"noUnusedParameters": false,
|
|
22
|
+
"noFallthroughCasesInSwitch": true,
|
|
23
|
+
"declaration": true,
|
|
24
|
+
"accessor-pairs": [
|
|
25
|
+
"error",
|
|
26
|
+
{
|
|
27
|
+
"setWithoutGet": true,
|
|
28
|
+
"getWithoutSet": true
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"include": [
|
|
33
|
+
"src"
|
|
34
|
+
]
|
|
35
|
+
}
|
package/.gitattributes
DELETED
package/gltf-importer.iml
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="GENERAL_MODULE" version="4">
|
|
3
|
-
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
4
|
-
<exclude-output />
|
|
5
|
-
<content url="file://$MODULE_DIR$" />
|
|
6
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
-
<orderEntry type="module" module-name="gltf-types" />
|
|
8
|
-
</component>
|
|
9
|
-
</module>
|
package/index.html
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<!-- Get rid of "http://localhost:5173/favicon.ico not found" -->
|
|
5
|
-
<link rel="shortcut icon" href="#" />
|
|
6
|
-
|
|
7
|
-
<meta charset="UTF-8"/>
|
|
8
|
-
<script type="module" src="src/index.ts"></script>
|
|
9
|
-
<title></title>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<canvas></canvas>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
package/res/suzanne.glb
DELETED
|
Binary file
|