@zephyr3d/scene 0.9.4 → 0.9.5
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/dist/animation/animationmask.js +224 -0
- package/dist/animation/animationmask.js.map +1 -0
- package/dist/animation/animationset.js +268 -67
- package/dist/animation/animationset.js.map +1 -1
- package/dist/animation/animationtrack.js.map +1 -1
- package/dist/animation/eulerrotationtrack.js +3 -0
- package/dist/animation/eulerrotationtrack.js.map +1 -1
- package/dist/animation/fixed_geometry_cache_track.js +7 -0
- package/dist/animation/fixed_geometry_cache_track.js.map +1 -1
- package/dist/animation/ik_modifier.js.map +1 -1
- package/dist/animation/joint_dynamics/collision.js +6 -4
- package/dist/animation/joint_dynamics/collision.js.map +1 -1
- package/dist/animation/joint_dynamics/controller.js +390 -43
- package/dist/animation/joint_dynamics/controller.js.map +1 -1
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +62 -3
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
- package/dist/animation/joint_dynamics/solver.js +4 -3
- package/dist/animation/joint_dynamics/solver.js.map +1 -1
- package/dist/animation/joint_dynamics/types.js.map +1 -1
- package/dist/animation/joint_dynamics_modifier.js +2 -0
- package/dist/animation/joint_dynamics_modifier.js.map +1 -1
- package/dist/animation/morphtarget.js +3 -72
- package/dist/animation/morphtarget.js.map +1 -1
- package/dist/animation/morphtrack.js +3 -0
- package/dist/animation/morphtrack.js.map +1 -1
- package/dist/animation/pca_geometry_cache_track.js +3 -0
- package/dist/animation/pca_geometry_cache_track.js.map +1 -1
- package/dist/animation/proptrack.js +3 -0
- package/dist/animation/proptrack.js.map +1 -1
- package/dist/animation/rotationtrack.js +3 -0
- package/dist/animation/rotationtrack.js.map +1 -1
- package/dist/animation/scaletrack.js +3 -0
- package/dist/animation/scaletrack.js.map +1 -1
- package/dist/animation/skeleton.js +254 -79
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/animation/skeleton_modifier.js.map +1 -1
- package/dist/animation/spring_modifier.js.map +1 -1
- package/dist/animation/translationtrack.js +3 -0
- package/dist/animation/translationtrack.js.map +1 -1
- package/dist/app/engine.js +171 -107
- package/dist/app/engine.js.map +1 -1
- package/dist/app/scriptregistry.js +251 -80
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +344 -365
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/loaders/gltf/gltf_loader.js +17 -14
- package/dist/asset/loaders/gltf/gltf_loader.js.map +1 -1
- package/dist/asset/loaders/loader.js +1 -6
- package/dist/asset/loaders/loader.js.map +1 -1
- package/dist/asset/loaders/zabc/zabc_loader.js.map +1 -1
- package/dist/asset/model.js +1000 -131
- package/dist/asset/model.js.map +1 -1
- package/dist/avatar/wardrobe.js +474 -0
- package/dist/avatar/wardrobe.js.map +1 -0
- package/dist/index.d.ts +1125 -199
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +6 -3
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +72 -15
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/msdf_text_sprite.js +4 -4
- package/dist/material/msdf_text_sprite.js.map +1 -1
- package/dist/material/pbrblueprint.js +102 -102
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/render/envlight.js +54 -1
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/sky.js +9 -0
- package/dist/render/sky.js.map +1 -1
- package/dist/scene/batchgroup.js +11 -13
- package/dist/scene/batchgroup.js.map +1 -1
- package/dist/scene/environment.js +15 -2
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/mesh.js +79 -16
- package/dist/scene/mesh.js.map +1 -1
- package/dist/scene/scene.js +1 -0
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/scene_node.js +203 -2
- package/dist/scene/scene_node.js.map +1 -1
- package/dist/text/font/font_asset.js.map +1 -1
- package/dist/text/msdf/generator.js.map +1 -1
- package/dist/text/msdf/shape.js +4 -1
- package/dist/text/msdf/shape.js.map +1 -1
- package/dist/text/runtime/msdf_text_atlas_manager.js +4 -1
- package/dist/text/runtime/msdf_text_atlas_manager.js.map +1 -1
- package/dist/utility/blueprint/material/inputs.js +1157 -1154
- package/dist/utility/blueprint/material/inputs.js.map +1 -1
- package/dist/utility/bounding_volume.js.map +1 -1
- package/dist/utility/pmrem.js +34 -8
- package/dist/utility/pmrem.js.map +1 -1
- package/dist/utility/serialization/manager.js +22 -9
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +700 -7
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +64 -4
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +187 -8
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/types.js.map +1 -1
- package/dist/utility/textures/sheenlut.js +138 -0
- package/dist/utility/textures/sheenlut.js.map +1 -0
- package/package.json +2 -2
package/dist/asset/model.js
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import { Vector3, Quaternion, Matrix4x4, Disposable, DRef } from '@zephyr3d/base';
|
|
1
|
+
import { Vector3, Quaternion, Matrix4x4, Disposable, uint8ArrayToBase64, ASSERT, DRef, Vector4 } from '@zephyr3d/base';
|
|
2
|
+
import { getVertexFormatComponentCount } from '@zephyr3d/device';
|
|
2
3
|
import { Mesh } from '../scene/mesh.js';
|
|
3
|
-
import {
|
|
4
|
+
import { BoundingBox } from '../utility/bounding_volume.js';
|
|
5
|
+
import { SceneNode, setSceneMeshAssetBinding } from '../scene/scene_node.js';
|
|
6
|
+
import { SkeletonRig, SkinBinding } from '../animation/skeleton.js';
|
|
4
7
|
import { NodeRotationTrack } from '../animation/rotationtrack.js';
|
|
5
8
|
import '../animation/eulerrotationtrack.js';
|
|
6
9
|
import { NodeTranslationTrack } from '../animation/translationtrack.js';
|
|
7
10
|
import { NodeScaleTrack } from '../animation/scaletrack.js';
|
|
8
|
-
import { Skeleton } from '../animation/skeleton.js';
|
|
9
11
|
import { MorphTargetTrack } from '../animation/morphtrack.js';
|
|
10
12
|
import { FixedGeometryCacheTrack } from '../animation/fixed_geometry_cache_track.js';
|
|
13
|
+
import { getDevice } from '../app/api.js';
|
|
11
14
|
import { PCAGeometryCacheTrack } from '../animation/pca_geometry_cache_track.js';
|
|
12
|
-
import '@zephyr3d/device';
|
|
13
15
|
import '../animation/joint_dynamics/collision.js';
|
|
14
16
|
import '../animation/joint_dynamics/solver.js';
|
|
15
|
-
import '../animation/joint_dynamics/joint_dynamics_system.js';
|
|
16
|
-
import {
|
|
17
|
-
import { MAX_MORPH_TARGETS } from '../values.js';
|
|
17
|
+
import { createTransformAccess, JointDynamicsSystem } from '../animation/joint_dynamics/joint_dynamics_system.js';
|
|
18
|
+
import { JointDynamicsModifier } from '../animation/joint_dynamics_modifier.js';
|
|
19
|
+
import { MAX_MORPH_TARGETS, MAX_MORPH_ATTRIBUTES } from '../values.js';
|
|
20
|
+
import { Primitive } from '../render/primitive.js';
|
|
21
|
+
import { UnlitMaterial } from '../material/unlit.js';
|
|
22
|
+
import { PBRSpecularGlossinessMaterial } from '../material/pbrsg.js';
|
|
23
|
+
import { PBRMetallicRoughnessMaterial } from '../material/pbrmr.js';
|
|
18
24
|
|
|
19
25
|
/**
|
|
20
26
|
* Named object interface for model loading
|
|
@@ -39,7 +45,6 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
39
45
|
_mesh;
|
|
40
46
|
_skeleton;
|
|
41
47
|
_attachToSkeleton;
|
|
42
|
-
_meshAttached;
|
|
43
48
|
_matrix;
|
|
44
49
|
_worldMatrix;
|
|
45
50
|
_weights;
|
|
@@ -49,8 +54,9 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
49
54
|
* Creates an instance of AssetHierarchyNode
|
|
50
55
|
* @param name - Name of the node
|
|
51
56
|
* @param parent - Parent of the node
|
|
52
|
-
*/ constructor(name, parent){
|
|
57
|
+
*/ constructor(name, model, parent){
|
|
53
58
|
super(name);
|
|
59
|
+
model.nodes.push(this);
|
|
54
60
|
this._parent = null;
|
|
55
61
|
this._position = Vector3.zero();
|
|
56
62
|
this._rotation = Quaternion.identity();
|
|
@@ -59,7 +65,6 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
59
65
|
this._mesh = null;
|
|
60
66
|
this._skeleton = null;
|
|
61
67
|
this._attachToSkeleton = null;
|
|
62
|
-
this._meshAttached = false;
|
|
63
68
|
this._matrix = null;
|
|
64
69
|
this._weights = null;
|
|
65
70
|
this._worldMatrix = null;
|
|
@@ -80,10 +85,9 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
80
85
|
}
|
|
81
86
|
set mesh(data) {
|
|
82
87
|
this._mesh = data;
|
|
83
|
-
this.setMeshAttached();
|
|
84
88
|
}
|
|
85
89
|
/** instances */ get instances() {
|
|
86
|
-
return this._instances
|
|
90
|
+
return this._instances;
|
|
87
91
|
}
|
|
88
92
|
/** Default morph target weights */ get weights() {
|
|
89
93
|
return this._weights;
|
|
@@ -115,16 +119,22 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
115
119
|
set scaling(val) {
|
|
116
120
|
this._scaling = val;
|
|
117
121
|
}
|
|
118
|
-
/** true if the node is parent of a mesh node */ get meshAttached() {
|
|
119
|
-
return this._meshAttached;
|
|
120
|
-
}
|
|
121
122
|
/** Children of the node */ get children() {
|
|
122
123
|
return this._children;
|
|
123
124
|
}
|
|
124
125
|
/** The skeleton to which the node belongs if this is a joint node */ get skeletonAttached() {
|
|
125
126
|
return this._attachToSkeleton;
|
|
126
127
|
}
|
|
127
|
-
|
|
128
|
+
isParentOf(child) {
|
|
129
|
+
while(child && child !== this){
|
|
130
|
+
child = child.parent;
|
|
131
|
+
}
|
|
132
|
+
return child === this;
|
|
133
|
+
}
|
|
134
|
+
getWorldPosition() {
|
|
135
|
+
return new Vector3(this.worldMatrix.m03, this.worldMatrix.m13, this.worldMatrix.m23);
|
|
136
|
+
}
|
|
137
|
+
computeTransforms(parentTransform) {
|
|
128
138
|
this._matrix = Matrix4x4.scaling(this._scaling).rotateLeft(this._rotation).translateLeft(this._position);
|
|
129
139
|
this._worldMatrix = parentTransform ? Matrix4x4.multiply(parentTransform, this._matrix) : new Matrix4x4(this._matrix);
|
|
130
140
|
for (const child of this._children){
|
|
@@ -140,9 +150,6 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
140
150
|
}
|
|
141
151
|
this._children.push(child);
|
|
142
152
|
child._parent = this;
|
|
143
|
-
if (child.meshAttached) {
|
|
144
|
-
this.setMeshAttached();
|
|
145
|
-
}
|
|
146
153
|
}
|
|
147
154
|
/**
|
|
148
155
|
* Removes a child of this node
|
|
@@ -165,10 +172,6 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
165
172
|
}
|
|
166
173
|
this._attachToSkeleton.add(skeleton);
|
|
167
174
|
}
|
|
168
|
-
/** @internal */ setMeshAttached() {
|
|
169
|
-
this._meshAttached = true;
|
|
170
|
-
this._parent?.setMeshAttached();
|
|
171
|
-
}
|
|
172
175
|
}
|
|
173
176
|
/**
|
|
174
177
|
* Skeleton information for model loading
|
|
@@ -203,6 +206,18 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
203
206
|
scale: joint.scaling.clone()
|
|
204
207
|
});
|
|
205
208
|
}
|
|
209
|
+
get root() {
|
|
210
|
+
if (this.pivot) {
|
|
211
|
+
return this.pivot;
|
|
212
|
+
}
|
|
213
|
+
let root = this.joints[0];
|
|
214
|
+
for(let i = 1; i < this.joints.length; i++){
|
|
215
|
+
while(root && !root.isParentOf(this.joints[i])){
|
|
216
|
+
root = root.parent;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return root;
|
|
220
|
+
}
|
|
206
221
|
}
|
|
207
222
|
/**
|
|
208
223
|
* Scene for model loading
|
|
@@ -221,41 +236,75 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
221
236
|
* Model information that can be shared by multiple model nodes
|
|
222
237
|
* @public
|
|
223
238
|
*/ class SharedModel extends Disposable {
|
|
224
|
-
/** @internal */ _name;
|
|
225
|
-
/** @internal */ _skeletons;
|
|
226
239
|
/** @internal */ _nodes;
|
|
240
|
+
/** @internal */ _skeletons;
|
|
227
241
|
/** @internal */ _animations;
|
|
228
242
|
/** @internal */ _scenes;
|
|
229
243
|
/** @internal */ _activeScene;
|
|
244
|
+
/** @internal */ _imageList;
|
|
245
|
+
/** @internal */ _primitiveList;
|
|
246
|
+
/** @internal */ _materialList;
|
|
247
|
+
/** @internal */ _springBoneColliders;
|
|
248
|
+
/** @internal */ _springBoneColliderGroups;
|
|
249
|
+
/** @internal */ _springBones;
|
|
250
|
+
/** @internal */ _jointDynamicsColliders;
|
|
251
|
+
/** @internal */ _jointDynamicsSpringBones;
|
|
252
|
+
/** @internal */ _morphTargetGroups;
|
|
253
|
+
/** @internal */ _textureMap;
|
|
254
|
+
/** @internal */ _primitiveMap;
|
|
230
255
|
/**
|
|
231
256
|
* Creates an instance of SharedModel
|
|
232
|
-
|
|
233
|
-
*/ constructor(name){
|
|
257
|
+
*/ constructor(){
|
|
234
258
|
super();
|
|
235
|
-
this._name = name || '';
|
|
236
|
-
this._skeletons = [];
|
|
237
259
|
this._nodes = [];
|
|
260
|
+
this._skeletons = [];
|
|
238
261
|
this._scenes = [];
|
|
239
262
|
this._animations = [];
|
|
263
|
+
this._imageList = [];
|
|
264
|
+
this._primitiveList = [];
|
|
265
|
+
this._materialList = {};
|
|
266
|
+
this._springBoneColliders = [];
|
|
267
|
+
this._springBoneColliderGroups = [];
|
|
268
|
+
this._springBones = [];
|
|
269
|
+
this._jointDynamicsColliders = [];
|
|
270
|
+
this._jointDynamicsSpringBones = [];
|
|
271
|
+
this._morphTargetGroups = [];
|
|
240
272
|
this._activeScene = -1;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
return this._name;
|
|
244
|
-
}
|
|
245
|
-
set name(val) {
|
|
246
|
-
this._name = val;
|
|
273
|
+
this._textureMap = new Map();
|
|
274
|
+
this._primitiveMap = new Map();
|
|
247
275
|
}
|
|
248
276
|
/** All scenes that the model contains */ get scenes() {
|
|
249
277
|
return this._scenes;
|
|
250
278
|
}
|
|
279
|
+
/** All Primitives that the model contains */ get primitives() {
|
|
280
|
+
return this._primitiveList;
|
|
281
|
+
}
|
|
282
|
+
/** All nodes that the model contains */ get nodes() {
|
|
283
|
+
return this._nodes;
|
|
284
|
+
}
|
|
251
285
|
/** All animations that the model contains */ get animations() {
|
|
252
286
|
return this._animations;
|
|
253
287
|
}
|
|
254
288
|
/** All skeletons that the model contains */ get skeletons() {
|
|
255
289
|
return this._skeletons;
|
|
256
290
|
}
|
|
257
|
-
/** All
|
|
258
|
-
return this.
|
|
291
|
+
/** All SpringBone colliders that the model contains */ get springBoneColliders() {
|
|
292
|
+
return this._springBoneColliders;
|
|
293
|
+
}
|
|
294
|
+
/** All SpringBone collider groups that the model contains */ get springBoneColliderGroups() {
|
|
295
|
+
return this._springBoneColliderGroups;
|
|
296
|
+
}
|
|
297
|
+
/** All SpringBone springs that the model contains */ get springBones() {
|
|
298
|
+
return this._springBones;
|
|
299
|
+
}
|
|
300
|
+
/** SpringBone colliders converted to Zephyr3D JointDynamics collider format */ get jointDynamicsColliders() {
|
|
301
|
+
return this._jointDynamicsColliders;
|
|
302
|
+
}
|
|
303
|
+
/** SpringBone springs converted to Zephyr3D JointDynamics system format */ get jointDynamicsSpringBones() {
|
|
304
|
+
return this._jointDynamicsSpringBones;
|
|
305
|
+
}
|
|
306
|
+
/** Model-level morph target groups, commonly facial expressions. */ get morphTargetGroups() {
|
|
307
|
+
return this._morphTargetGroups;
|
|
259
308
|
}
|
|
260
309
|
/** The active scene of the model */ get activeScene() {
|
|
261
310
|
return this._activeScene;
|
|
@@ -263,16 +312,75 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
263
312
|
set activeScene(val) {
|
|
264
313
|
this._activeScene = val;
|
|
265
314
|
}
|
|
315
|
+
getImage(index) {
|
|
316
|
+
return this._imageList[index];
|
|
317
|
+
}
|
|
318
|
+
setImage(index, img) {
|
|
319
|
+
this._imageList[index] = img;
|
|
320
|
+
}
|
|
321
|
+
getMaterial(hash) {
|
|
322
|
+
return this._materialList[hash];
|
|
323
|
+
}
|
|
324
|
+
setMaterial(hash, material) {
|
|
325
|
+
this._materialList[hash] = material;
|
|
326
|
+
}
|
|
327
|
+
addPrimitive(prim) {
|
|
328
|
+
this._primitiveList.push(prim);
|
|
329
|
+
}
|
|
266
330
|
/**
|
|
267
|
-
* Adds a
|
|
268
|
-
* @param
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
331
|
+
* Adds a model-level morph target group.
|
|
332
|
+
* @param group - Morph target group to add
|
|
333
|
+
*/ addMorphTargetGroup(group) {
|
|
334
|
+
if (group?.name && group.bindings?.length > 0) {
|
|
335
|
+
this._morphTargetGroups.push(group);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Removes all model-level morph target groups.
|
|
340
|
+
*/ clearMorphTargetGroups() {
|
|
341
|
+
this._morphTargetGroups = [];
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Finds a model-level morph target group by name.
|
|
345
|
+
* @param name - Group name
|
|
346
|
+
* @returns The matching group, or null if not found
|
|
347
|
+
*/ getMorphTargetGroup(name) {
|
|
348
|
+
return this._morphTargetGroups.find((group)=>group.name === name) ?? null;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Builds morph target groups by collecting morph target names from every mesh.
|
|
352
|
+
* @returns Generated morph target groups
|
|
353
|
+
*/ buildMorphTargetGroupsByName() {
|
|
354
|
+
this.clearMorphTargetGroups();
|
|
355
|
+
const groups = new Map();
|
|
356
|
+
const meshes = new Set();
|
|
357
|
+
for (const node of this._nodes){
|
|
358
|
+
if (node.mesh) {
|
|
359
|
+
meshes.add(node.mesh);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (const mesh of meshes){
|
|
363
|
+
const count = getAssetMeshMorphTargetCount(mesh);
|
|
364
|
+
for(let i = 0; i < count; i++){
|
|
365
|
+
const targetName = getAssetMeshMorphTargetName(mesh, i);
|
|
366
|
+
let group = groups.get(targetName);
|
|
367
|
+
if (!group) {
|
|
368
|
+
group = {
|
|
369
|
+
name: targetName,
|
|
370
|
+
bindings: []
|
|
371
|
+
};
|
|
372
|
+
groups.set(targetName, group);
|
|
373
|
+
}
|
|
374
|
+
group.bindings.push({
|
|
375
|
+
mesh,
|
|
376
|
+
targetIndex: i,
|
|
377
|
+
targetName,
|
|
378
|
+
weight: 1
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
this._morphTargetGroups = Array.from(groups.values());
|
|
383
|
+
return this._morphTargetGroups;
|
|
276
384
|
}
|
|
277
385
|
/**
|
|
278
386
|
* Adds a skeleton to the scene
|
|
@@ -286,67 +394,297 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
286
394
|
*/ addAnimation(animation) {
|
|
287
395
|
this._animations.push(animation);
|
|
288
396
|
}
|
|
289
|
-
|
|
397
|
+
static async writePrimitive(vfs, primitive, path) {
|
|
398
|
+
const data = {
|
|
399
|
+
vertices: {},
|
|
400
|
+
indices: primitive.indices ? uint8ArrayToBase64(new Uint8Array(primitive.indices.buffer, primitive.indices.byteOffset, primitive.indices.byteLength)) : null,
|
|
401
|
+
indexType: primitive.indices ? primitive.indices instanceof Uint16Array ? 'u16' : 'u32' : '',
|
|
402
|
+
indexCount: primitive.indexCount,
|
|
403
|
+
type: primitive.type,
|
|
404
|
+
boxMin: [
|
|
405
|
+
primitive.boxMin.x,
|
|
406
|
+
primitive.boxMin.y,
|
|
407
|
+
primitive.boxMin.z
|
|
408
|
+
],
|
|
409
|
+
boxMax: [
|
|
410
|
+
primitive.boxMax.x,
|
|
411
|
+
primitive.boxMax.y,
|
|
412
|
+
primitive.boxMax.z
|
|
413
|
+
]
|
|
414
|
+
};
|
|
415
|
+
for(const k in primitive.vertices){
|
|
416
|
+
const v = primitive.vertices[k];
|
|
417
|
+
data.vertices[k] = {
|
|
418
|
+
format: v.format,
|
|
419
|
+
data: uint8ArrayToBase64(new Uint8Array(v.data.buffer, v.data.byteOffset, v.data.byteLength))
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const content = JSON.stringify({
|
|
423
|
+
type: 'Primitive',
|
|
424
|
+
data
|
|
425
|
+
}, null, 2);
|
|
426
|
+
await vfs.writeFile(path, content, {
|
|
427
|
+
encoding: 'utf8',
|
|
428
|
+
create: true
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
/** preprocess */ async preprocess(manager, name, destPath, srcVFS, dstVFS) {
|
|
432
|
+
const destName = name;
|
|
433
|
+
if (this._imageList.length > 0) {
|
|
434
|
+
console.info(`Importing ${this._imageList.length} textures`);
|
|
435
|
+
for(let i = 0; i < this._imageList.length; i++){
|
|
436
|
+
const img = this._imageList[i];
|
|
437
|
+
if (!img) {
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
let ext = '';
|
|
441
|
+
const mimeType = img.uri ? srcVFS.guessMIMEType(img.uri) : img.data ? img.mimeType : '';
|
|
442
|
+
if (mimeType === 'image/jpeg') {
|
|
443
|
+
ext = '.jpg';
|
|
444
|
+
} else if (mimeType === 'image/png') {
|
|
445
|
+
ext = '.png';
|
|
446
|
+
} else if (mimeType === 'image/webp') {
|
|
447
|
+
ext = '.webp';
|
|
448
|
+
} else if (mimeType === 'image/tga') {
|
|
449
|
+
ext = '.tga';
|
|
450
|
+
} else if (mimeType === 'image/vnd.radiance') {
|
|
451
|
+
ext = '.hdr';
|
|
452
|
+
} else if (mimeType === 'image/ktx') {
|
|
453
|
+
ext = '.ktx';
|
|
454
|
+
} else if (mimeType === 'image/ktx2') {
|
|
455
|
+
ext = '.ktx2';
|
|
456
|
+
} else {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
ASSERT(!!ext, `Unknown image mime type: ${mimeType}`);
|
|
460
|
+
const path = dstVFS.join(destPath, `${destName}_texture_${i}${ext}`);
|
|
461
|
+
if (img.uri) {
|
|
462
|
+
img.data = new Uint8Array(await srcVFS.readFile(img.uri, {
|
|
463
|
+
encoding: 'binary'
|
|
464
|
+
}));
|
|
465
|
+
}
|
|
466
|
+
await dstVFS.writeFile(path, img.data.buffer.slice(img.data.byteOffset, img.data.byteOffset + img.data.byteLength), {
|
|
467
|
+
encoding: 'binary',
|
|
468
|
+
create: true
|
|
469
|
+
});
|
|
470
|
+
img.uri = path;
|
|
471
|
+
img.data = undefined;
|
|
472
|
+
img.mimeType = '';
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const materialKeys = Object.keys(this._materialList);
|
|
476
|
+
if (materialKeys.length > 0) {
|
|
477
|
+
console.info(`Importing ${materialKeys.length} materials`);
|
|
478
|
+
for (const k of materialKeys){
|
|
479
|
+
const path = dstVFS.join(destPath, `${destName}_material_${k}.zmtl`);
|
|
480
|
+
const m = await this.createMaterial(manager, this._materialList[k], dstVFS);
|
|
481
|
+
const data = await manager.serializeObject(m);
|
|
482
|
+
const content = JSON.stringify({
|
|
483
|
+
type: 'Default',
|
|
484
|
+
data
|
|
485
|
+
}, null, 2);
|
|
486
|
+
await dstVFS.writeFile(path, content, {
|
|
487
|
+
encoding: 'utf8',
|
|
488
|
+
create: true
|
|
489
|
+
});
|
|
490
|
+
this._materialList[k].path = path;
|
|
491
|
+
m.dispose();
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (this._primitiveList.length > 0) {
|
|
495
|
+
console.info(`Importing ${this._primitiveList.length} meshes`);
|
|
496
|
+
for(let i = 0; i < this._primitiveList.length; i++){
|
|
497
|
+
const info = this._primitiveList[i];
|
|
498
|
+
if (!info) {
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
const path = dstVFS.join(destPath, `${destName}_mesh_${i}.zmsh`);
|
|
502
|
+
await SharedModel.writePrimitive(dstVFS, info, path);
|
|
503
|
+
info.path = path;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
createJointDynamics(rootNode, nodeMap) {
|
|
508
|
+
if (rootNode.animationSet.rigs.length === 0) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
for (const jd of this._jointDynamicsSpringBones){
|
|
512
|
+
const chains = jd.chains.map((chain)=>{
|
|
513
|
+
const start = nodeMap.get(chain.start);
|
|
514
|
+
const end = nodeMap.get(chain.end);
|
|
515
|
+
return {
|
|
516
|
+
start,
|
|
517
|
+
end
|
|
518
|
+
};
|
|
519
|
+
}).filter((chain)=>{
|
|
520
|
+
if (!chain.start || !chain.end) {
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
return true;
|
|
524
|
+
});
|
|
525
|
+
const rigs = rootNode.animationSet.rigs.filter((ref)=>{
|
|
526
|
+
const joints = ref.get().joints;
|
|
527
|
+
return chains.every((chain)=>joints.includes(chain.start));
|
|
528
|
+
});
|
|
529
|
+
if (rigs.length === 0) {
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
const colliders = jd.colliders.map((collider)=>{
|
|
533
|
+
const parent = nodeMap.get(collider.node);
|
|
534
|
+
if (!parent) {
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
const node = new SceneNode(parent.scene);
|
|
538
|
+
node.name = collider.name ? `${collider.name}_JointDynamicsCollider` : 'JointDynamicsCollider';
|
|
539
|
+
node.parent = parent;
|
|
540
|
+
node.position.set(collider.localPosition);
|
|
541
|
+
node.rotation.set(collider.localRotation);
|
|
542
|
+
return {
|
|
543
|
+
r: {
|
|
544
|
+
...collider.collider
|
|
545
|
+
},
|
|
546
|
+
transform: createTransformAccess(node)
|
|
547
|
+
};
|
|
548
|
+
}).filter((collider)=>{
|
|
549
|
+
return !!collider;
|
|
550
|
+
});
|
|
551
|
+
const flatPlanes = jd.flatPlanes.map((flatPlane)=>{
|
|
552
|
+
const node = nodeMap.get(flatPlane.node);
|
|
553
|
+
if (!node) {
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
const up = node.worldMatrix.transformVectorAffine(flatPlane.up, new Vector3());
|
|
557
|
+
if (up.magnitudeSq === 0) {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
return {
|
|
561
|
+
up: up.inplaceNormalize(),
|
|
562
|
+
position: node.worldMatrix.transformPointAffine(flatPlane.position, new Vector3())
|
|
563
|
+
};
|
|
564
|
+
}).filter((flatPlane)=>{
|
|
565
|
+
return !!flatPlane;
|
|
566
|
+
});
|
|
567
|
+
for (const rig of rigs){
|
|
568
|
+
const system = new JointDynamicsSystem({
|
|
569
|
+
chainConfig: {
|
|
570
|
+
chains,
|
|
571
|
+
systemRoot: rootNode
|
|
572
|
+
},
|
|
573
|
+
controllerConfig: jd.controllerConfig
|
|
574
|
+
}, colliders, [], flatPlanes);
|
|
575
|
+
const modifier = new JointDynamicsModifier(system);
|
|
576
|
+
rig.get().modifiers.push(modifier);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
createMorphTargetGroups(rootNode, meshMap) {
|
|
581
|
+
const runtimeGroups = [];
|
|
582
|
+
for (const group of this._morphTargetGroups){
|
|
583
|
+
const bindings = [];
|
|
584
|
+
for (const binding of group.bindings){
|
|
585
|
+
const assetMesh = binding.node?.mesh ?? binding.mesh ?? null;
|
|
586
|
+
if (!assetMesh) {
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
for (const subMesh of assetMesh.subMeshes){
|
|
590
|
+
const mesh = meshMap.get(subMesh);
|
|
591
|
+
if (mesh) {
|
|
592
|
+
bindings.push({
|
|
593
|
+
mesh,
|
|
594
|
+
targetIndex: binding.targetIndex,
|
|
595
|
+
targetName: binding.targetName,
|
|
596
|
+
weight: binding.weight
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (bindings.length > 0) {
|
|
602
|
+
runtimeGroups.push({
|
|
603
|
+
name: group.name,
|
|
604
|
+
bindings,
|
|
605
|
+
isBinary: group.isBinary,
|
|
606
|
+
weight: this.getInitialMorphTargetGroupWeight(bindings, group.isBinary)
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
rootNode.morphTargetGroups = runtimeGroups;
|
|
611
|
+
}
|
|
612
|
+
getInitialMorphTargetGroupWeight(bindings, isBinary) {
|
|
613
|
+
let result = 0;
|
|
614
|
+
let found = false;
|
|
615
|
+
for (const binding of bindings){
|
|
616
|
+
if (!binding.weight) {
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
const targetWeight = this.getMorphTargetBindingWeight(binding);
|
|
620
|
+
if (targetWeight === null) {
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
const groupWeight = targetWeight / binding.weight;
|
|
624
|
+
if (!found || Math.abs(groupWeight) > Math.abs(result)) {
|
|
625
|
+
result = groupWeight;
|
|
626
|
+
found = true;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return isBinary ? result > 0.5 ? 1 : 0 : result;
|
|
630
|
+
}
|
|
631
|
+
getMorphTargetBindingWeight(binding) {
|
|
632
|
+
const targetIndex = binding.targetIndex;
|
|
633
|
+
if (typeof targetIndex === 'number' && targetIndex >= 0 && targetIndex < binding.mesh.getNumMorphTargets()) {
|
|
634
|
+
const targetName = binding.mesh.getMorphTargetName(targetIndex);
|
|
635
|
+
if (targetName) {
|
|
636
|
+
return binding.mesh.getMorphWeight(targetName);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (binding.targetName) {
|
|
640
|
+
return binding.mesh.getMorphWeight(binding.targetName);
|
|
641
|
+
}
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
async createSceneNode(manager, scene, instancing, saveMeshes, saveSkeletons, saveAnimations, saveJointDynamics, srcVFS) {
|
|
290
645
|
const group = new SceneNode(scene);
|
|
291
|
-
|
|
292
|
-
const
|
|
646
|
+
const nodeMap = new Map();
|
|
647
|
+
const meshMap = new Map();
|
|
293
648
|
for(let i = 0; i < this.scenes.length; i++){
|
|
294
649
|
const assetScene = this.scenes[i];
|
|
295
650
|
const skeletonMeshMap = new Map();
|
|
296
|
-
const nodeMap = new Map();
|
|
297
651
|
for(let k = 0; k < assetScene.rootNodes.length; k++){
|
|
298
|
-
this.setAssetNodeToSceneNode(scene, group, assetScene.rootNodes[k], skeletonMeshMap, nodeMap, instancing);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
break;
|
|
308
|
-
}
|
|
652
|
+
await this.setAssetNodeToSceneNode(manager, scene, group, assetScene.rootNodes[k], skeletonMeshMap, nodeMap, meshMap, instancing, saveMeshes, saveSkeletons, saveAnimations, srcVFS);
|
|
653
|
+
}
|
|
654
|
+
if (saveSkeletons) {
|
|
655
|
+
for (const sk of this.skeletons){
|
|
656
|
+
if (!skeletonMeshMap.has(sk)) {
|
|
657
|
+
skeletonMeshMap.set(sk, {
|
|
658
|
+
mesh: [],
|
|
659
|
+
bounding: []
|
|
660
|
+
});
|
|
309
661
|
}
|
|
310
662
|
}
|
|
311
|
-
const
|
|
312
|
-
for (const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (!subMesh?.mesh) {
|
|
331
|
-
console.error(`Invalid geometry cache sub mesh: ${track.subMeshIndex}`);
|
|
332
|
-
} else {
|
|
333
|
-
if (track.codec === 'pca') {
|
|
334
|
-
const pcaData = this.remapPCAGeometryCacheData(subMesh, track);
|
|
335
|
-
animation.addTrack(subMesh.mesh, new PCAGeometryCacheTrack(pcaData, true));
|
|
336
|
-
} else {
|
|
337
|
-
const frames = this.remapGeometryCacheFrames(subMesh, track.frames);
|
|
338
|
-
animation.addTrack(subMesh.mesh, new FixedGeometryCacheTrack(track.times, frames, true));
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
} else {
|
|
342
|
-
console.error(`Invalid animation track type: ${track.type}`);
|
|
663
|
+
const rigMap = new Map();
|
|
664
|
+
for (const v of skeletonMeshMap){
|
|
665
|
+
const sk = v[0];
|
|
666
|
+
const joints = sk.joints.map((val)=>{
|
|
667
|
+
const node = nodeMap.get(val);
|
|
668
|
+
node.jointTypeT = 'static';
|
|
669
|
+
node.jointTypeS = 'static';
|
|
670
|
+
node.jointTypeR = 'static';
|
|
671
|
+
return node;
|
|
672
|
+
});
|
|
673
|
+
const rootJoint = sk.root ? nodeMap.get(sk.root) ?? null : null;
|
|
674
|
+
const rigKey = SkeletonRig.getRigKey(joints, rootJoint);
|
|
675
|
+
let rig = rigMap.get(rigKey);
|
|
676
|
+
if (!rig) {
|
|
677
|
+
rig = new SkeletonRig(joints, sk.bindPose, {
|
|
678
|
+
rootJoint
|
|
679
|
+
});
|
|
680
|
+
rigMap.set(rigKey, rig);
|
|
681
|
+
group.animationSet.rigs.push(new DRef(rig));
|
|
343
682
|
}
|
|
344
|
-
|
|
345
|
-
for (const sk of animationData.skeletons){
|
|
683
|
+
const binding = new SkinBinding(rig, sk.inverseBindMatrices, joints);
|
|
346
684
|
const nodes = skeletonMeshMap.get(sk);
|
|
347
685
|
if (nodes) {
|
|
348
|
-
if (!nodes.
|
|
349
|
-
nodes.
|
|
686
|
+
if (!nodes.binding) {
|
|
687
|
+
nodes.binding = binding;
|
|
350
688
|
for(let i = 0; i < nodes.mesh.length; i++){
|
|
351
689
|
const mesh = nodes.mesh[i];
|
|
352
690
|
const v = {
|
|
@@ -354,22 +692,82 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
354
692
|
blendIndices: nodes.bounding[i].rawBlendIndices,
|
|
355
693
|
weights: nodes.bounding[i].rawJointWeights
|
|
356
694
|
};
|
|
357
|
-
mesh.setSkinnedBoundingInfo(nodes.
|
|
358
|
-
mesh.skeletonName = nodes.
|
|
695
|
+
mesh.setSkinnedBoundingInfo(nodes.binding.getBoundingInfo(v));
|
|
696
|
+
mesh.skeletonName = nodes.binding.persistentId;
|
|
359
697
|
}
|
|
360
|
-
animationSet.skeletons.push(new DRef(nodes.skeleton));
|
|
361
698
|
}
|
|
362
|
-
animation.addSkeleton(nodes.skeleton.persistentId);
|
|
363
699
|
}
|
|
700
|
+
group.animationSet.skeletons.push(new DRef(nodes.binding));
|
|
364
701
|
}
|
|
365
702
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
703
|
+
if (saveAnimations) {
|
|
704
|
+
for (const animationData of this.animations){
|
|
705
|
+
if (animationData.skeletons.length > 0 && !saveSkeletons) {
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
let name = animationData.name ?? `_embbeded_animation`;
|
|
709
|
+
if (group.animationSet.getAnimationClip(name)) {
|
|
710
|
+
const baseName = name;
|
|
711
|
+
for(let t = 1;; t++){
|
|
712
|
+
name = `${baseName}_${t}`;
|
|
713
|
+
if (!group.animationSet.getAnimationClip(name)) {
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
const animation = group.animationSet.createAnimation(name, true);
|
|
719
|
+
for (const sk of animationData.skeletons){
|
|
720
|
+
const nodes = skeletonMeshMap.get(sk);
|
|
721
|
+
if (nodes) {
|
|
722
|
+
animation.addSkeleton(nodes.binding.rig.persistentId);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
for (const track of animationData.tracks){
|
|
726
|
+
const target = nodeMap.get(track.node);
|
|
727
|
+
if (track.type === 'translation') {
|
|
728
|
+
animation.addTrack(target, new NodeTranslationTrack(track.interpolator, true));
|
|
729
|
+
target.jointTypeT = 'animated';
|
|
730
|
+
} else if (track.type === 'scale') {
|
|
731
|
+
animation.addTrack(target, new NodeScaleTrack(track.interpolator, true));
|
|
732
|
+
target.jointTypeS = 'animated';
|
|
733
|
+
} else if (track.type === 'rotation') {
|
|
734
|
+
animation.addTrack(target, new NodeRotationTrack(track.interpolator, true));
|
|
735
|
+
target.jointTypeR = 'animated';
|
|
736
|
+
} else if (track.type === 'weights') {
|
|
737
|
+
for (const m of track.node.mesh.subMeshes){
|
|
738
|
+
const mesh = meshMap.get(m);
|
|
739
|
+
if (track.interpolator.stride > MAX_MORPH_TARGETS) {
|
|
740
|
+
console.error(`Morph target too large: ${track.interpolator.stride}, the maximum is ${MAX_MORPH_TARGETS}`);
|
|
741
|
+
} else {
|
|
742
|
+
const morphTrack = new MorphTargetTrack(track.interpolator, track.defaultMorphWeights, m.targetBox, mesh.getBoundingVolume().toAABB(), true);
|
|
743
|
+
animation.addTrack(mesh, morphTrack);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
} else if (track.type === 'geometry-cache') {
|
|
747
|
+
const subMesh = track.node.mesh?.subMeshes[track.subMeshIndex];
|
|
748
|
+
const mesh = subMesh ? meshMap.get(subMesh) : null;
|
|
749
|
+
if (!subMesh || !mesh) {
|
|
750
|
+
console.error(`Invalid geometry cache sub mesh: ${track.subMeshIndex}`);
|
|
751
|
+
} else {
|
|
752
|
+
if (track.codec === 'pca') {
|
|
753
|
+
const pcaData = this.remapPCAGeometryCacheData(subMesh, track);
|
|
754
|
+
animation.addTrack(mesh, new PCAGeometryCacheTrack(pcaData, true));
|
|
755
|
+
} else {
|
|
756
|
+
const frames = this.remapGeometryCacheFrames(subMesh, track.frames);
|
|
757
|
+
animation.addTrack(mesh, new FixedGeometryCacheTrack(track.times, frames, true));
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
} else {
|
|
761
|
+
console.error(`Invalid animation track type: ${track.type}`);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
370
765
|
}
|
|
371
|
-
}
|
|
372
|
-
|
|
766
|
+
}
|
|
767
|
+
if (saveJointDynamics && saveSkeletons) {
|
|
768
|
+
this.createJointDynamics(group, nodeMap);
|
|
769
|
+
}
|
|
770
|
+
this.createMorphTargetGroups(group, meshMap);
|
|
373
771
|
return group;
|
|
374
772
|
}
|
|
375
773
|
remapGeometryCacheFrames(subMesh, frames) {
|
|
@@ -547,51 +945,61 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
547
945
|
}
|
|
548
946
|
onDispose() {
|
|
549
947
|
super.onDispose();
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
nodes.push(...node.children);
|
|
556
|
-
const mesh = node.mesh;
|
|
557
|
-
if (mesh) {
|
|
558
|
-
for (const subMesh of mesh.subMeshes){
|
|
559
|
-
subMesh.primitive?.dispose();
|
|
560
|
-
subMesh.material?.dispose();
|
|
561
|
-
}
|
|
562
|
-
}
|
|
948
|
+
for (const prim of this._primitiveMap.values()){
|
|
949
|
+
prim.dispose();
|
|
950
|
+
}
|
|
951
|
+
for (const tex of this._textureMap.values()){
|
|
952
|
+
tex.dispose();
|
|
563
953
|
}
|
|
564
|
-
this._nodes = [];
|
|
565
954
|
this._skeletons = [];
|
|
566
955
|
this._scenes = [];
|
|
567
956
|
this._animations = [];
|
|
568
957
|
}
|
|
569
|
-
setAssetNodeToSceneNode(scene, parent, assetNode, skeletonMeshMap, nodeMap, instancing) {
|
|
958
|
+
async setAssetNodeToSceneNode(manager, scene, parent, assetNode, skeletonMeshMap, nodeMap, meshMap, instancing, saveMeshes, saveSkeletons, saveAnimations, srcVFS) {
|
|
570
959
|
const node = new SceneNode(scene);
|
|
571
960
|
nodeMap.set(assetNode, node);
|
|
572
961
|
node.name = assetNode.name ?? '';
|
|
573
962
|
node.position.set(assetNode.position);
|
|
574
963
|
node.rotation.set(assetNode.rotation);
|
|
575
964
|
node.scale.set(assetNode.scaling);
|
|
576
|
-
if (assetNode.mesh) {
|
|
965
|
+
if (saveMeshes && assetNode.mesh) {
|
|
577
966
|
const meshData = assetNode.mesh;
|
|
578
|
-
const skeleton = assetNode.skeleton;
|
|
967
|
+
const skeleton = saveSkeletons ? assetNode.skeleton : null;
|
|
579
968
|
for (const subMesh of meshData.subMeshes){
|
|
969
|
+
if (assetNode.instances.length === 0) {
|
|
970
|
+
assetNode.instances.push({
|
|
971
|
+
t: Vector3.zero(),
|
|
972
|
+
s: Vector3.one(),
|
|
973
|
+
r: Quaternion.identity()
|
|
974
|
+
});
|
|
975
|
+
}
|
|
580
976
|
for (const instance of assetNode.instances){
|
|
581
977
|
const meshNode = new Mesh(scene);
|
|
582
|
-
const skinAnimation = !!skeleton;
|
|
583
|
-
const morphAnimation = subMesh.numTargets > 0;
|
|
584
978
|
meshNode.position = instance.t;
|
|
585
979
|
meshNode.scale = instance.s;
|
|
586
980
|
meshNode.rotation = instance.r;
|
|
587
981
|
meshNode.name = subMesh.name;
|
|
588
982
|
meshNode.clipTestEnabled = true;
|
|
589
983
|
meshNode.showState = 'inherit';
|
|
590
|
-
|
|
591
|
-
|
|
984
|
+
if (!this._primitiveMap.get(subMesh.primitive)) {
|
|
985
|
+
this._primitiveMap.set(subMesh.primitive, new DRef(await this.createPrimitive(manager, subMesh.primitive, srcVFS) ?? undefined));
|
|
986
|
+
}
|
|
987
|
+
meshNode.primitive = this._primitiveMap.get(subMesh.primitive).get();
|
|
988
|
+
if (!subMesh.material.material) {
|
|
989
|
+
subMesh.material.material = new DRef(await this.createMaterial(manager, subMesh.material, srcVFS) ?? undefined);
|
|
990
|
+
}
|
|
991
|
+
meshNode.material = subMesh.material.material?.get() ?? null;
|
|
992
|
+
if (instancing) {
|
|
993
|
+
meshNode.material = meshNode.material.createInstance();
|
|
994
|
+
}
|
|
592
995
|
meshNode.parent = node;
|
|
593
|
-
subMesh
|
|
594
|
-
|
|
996
|
+
meshMap.set(subMesh, meshNode);
|
|
997
|
+
setSceneMeshAssetBinding(meshNode, {
|
|
998
|
+
node: assetNode,
|
|
999
|
+
mesh: meshData,
|
|
1000
|
+
subMesh
|
|
1001
|
+
});
|
|
1002
|
+
processMorphData(subMesh, meshNode, assetNode.weights ?? meshData.morphWeights, meshData.morphNames);
|
|
595
1003
|
if (skeleton) {
|
|
596
1004
|
if (!skeletonMeshMap.has(skeleton)) {
|
|
597
1005
|
skeletonMeshMap.set(skeleton, {
|
|
@@ -612,9 +1020,470 @@ import { MAX_MORPH_TARGETS } from '../values.js';
|
|
|
612
1020
|
}
|
|
613
1021
|
node.parent = parent;
|
|
614
1022
|
for (const child of assetNode.children){
|
|
615
|
-
this.setAssetNodeToSceneNode(scene, node, child, skeletonMeshMap, nodeMap, instancing);
|
|
1023
|
+
await this.setAssetNodeToSceneNode(manager, scene, node, child, skeletonMeshMap, nodeMap, meshMap, instancing, saveMeshes, saveSkeletons, saveAnimations, srcVFS);
|
|
1024
|
+
}
|
|
1025
|
+
return node;
|
|
1026
|
+
}
|
|
1027
|
+
async image2Texture(manager, info, srcVFS) {
|
|
1028
|
+
if (info.image.uri) {
|
|
1029
|
+
const texture = await manager.fetchTexture(info.image.uri, {
|
|
1030
|
+
linearColorSpace: !info.sRGB,
|
|
1031
|
+
overrideVFS: srcVFS
|
|
1032
|
+
});
|
|
1033
|
+
texture.name = info.image.uri;
|
|
1034
|
+
return texture;
|
|
1035
|
+
} else if (info.image.data && info.image.mimeType) {
|
|
1036
|
+
const texture = await manager.loadTextureFromBuffer(info.image.data, info.image.mimeType, !!info.sRGB);
|
|
1037
|
+
return texture;
|
|
1038
|
+
}
|
|
1039
|
+
return null;
|
|
1040
|
+
}
|
|
1041
|
+
async createTexture(manager, info, srcVFS) {
|
|
1042
|
+
try {
|
|
1043
|
+
let textureRef = this._textureMap.get(info);
|
|
1044
|
+
if (!textureRef) {
|
|
1045
|
+
textureRef = new DRef(await this.image2Texture(manager, info, srcVFS));
|
|
1046
|
+
this._textureMap.set(info, textureRef);
|
|
1047
|
+
}
|
|
1048
|
+
const sampler = getDevice().createSampler({
|
|
1049
|
+
addressU: info.sampler.wrapS,
|
|
1050
|
+
addressV: info.sampler.wrapT,
|
|
1051
|
+
magFilter: info.sampler.magFilter,
|
|
1052
|
+
minFilter: info.sampler.minFilter,
|
|
1053
|
+
mipFilter: info.sampler.mipFilter
|
|
1054
|
+
});
|
|
1055
|
+
const transform = info.transform;
|
|
1056
|
+
const texCoord = info.texCoord;
|
|
1057
|
+
return {
|
|
1058
|
+
texture: textureRef.get(),
|
|
1059
|
+
sampler,
|
|
1060
|
+
texCoord,
|
|
1061
|
+
transform
|
|
1062
|
+
};
|
|
1063
|
+
} catch (err) {
|
|
1064
|
+
console.error(`Load asset texture failed: ${err}`);
|
|
1065
|
+
return null;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
async createPrimitive(manager, info, srcVFS) {
|
|
1069
|
+
if (info.path) {
|
|
1070
|
+
return manager.fetchPrimitive(info.path, {
|
|
1071
|
+
overrideVFS: srcVFS
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
const primitive = new Primitive();
|
|
1075
|
+
for(const k in info.vertices){
|
|
1076
|
+
const v = info.vertices[k];
|
|
1077
|
+
primitive.createAndSetVertexBuffer(v.format, v.data);
|
|
1078
|
+
}
|
|
1079
|
+
if (info.indices) {
|
|
1080
|
+
primitive.createAndSetIndexBuffer(info.indices);
|
|
1081
|
+
}
|
|
1082
|
+
primitive.primitiveType = info.type;
|
|
1083
|
+
primitive.indexCount = info.indexCount;
|
|
1084
|
+
primitive.setBoundingVolume(new BoundingBox(info.boxMin, info.boxMax));
|
|
1085
|
+
return primitive;
|
|
1086
|
+
}
|
|
1087
|
+
async createMaterial(manager, assetMaterial, srcVFS) {
|
|
1088
|
+
if (assetMaterial.path) {
|
|
1089
|
+
return manager.fetchMaterial(assetMaterial.path, {
|
|
1090
|
+
overrideVFS: srcVFS
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
const infoMap = new Map();
|
|
1094
|
+
const that = this;
|
|
1095
|
+
async function getTextureInfo(info) {
|
|
1096
|
+
let t = infoMap.get(info);
|
|
1097
|
+
if (t === undefined) {
|
|
1098
|
+
t = await that.createTexture(manager, info, srcVFS);
|
|
1099
|
+
infoMap.set(info, t);
|
|
1100
|
+
}
|
|
1101
|
+
return t;
|
|
1102
|
+
}
|
|
1103
|
+
if (assetMaterial.type === 'unlit') {
|
|
1104
|
+
const unlitAssetMaterial = assetMaterial;
|
|
1105
|
+
const unlitMaterial = new UnlitMaterial();
|
|
1106
|
+
unlitMaterial.albedoColor = unlitAssetMaterial.diffuse ?? Vector4.one();
|
|
1107
|
+
if (unlitAssetMaterial.diffuseMap) {
|
|
1108
|
+
const info = await getTextureInfo(unlitAssetMaterial.diffuseMap);
|
|
1109
|
+
if (info) {
|
|
1110
|
+
unlitMaterial.albedoTexture = info.texture;
|
|
1111
|
+
unlitMaterial.albedoTextureSampler = info.sampler;
|
|
1112
|
+
unlitMaterial.albedoTexCoordIndex = info.texCoord;
|
|
1113
|
+
unlitMaterial.albedoTexCoordMatrix = info.transform;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
unlitMaterial.vertexColor = unlitAssetMaterial.common.vertexColor;
|
|
1117
|
+
if (assetMaterial.common.alphaMode === 'blend') {
|
|
1118
|
+
unlitMaterial.blendMode = 'blend';
|
|
1119
|
+
} else if (assetMaterial.common.alphaMode === 'mask') {
|
|
1120
|
+
unlitMaterial.alphaCutoff = assetMaterial.common.alphaCutoff;
|
|
1121
|
+
}
|
|
1122
|
+
if (assetMaterial.common.doubleSided) {
|
|
1123
|
+
unlitMaterial.cullMode = 'none';
|
|
1124
|
+
}
|
|
1125
|
+
return unlitMaterial;
|
|
1126
|
+
} else if (assetMaterial.type === 'pbrSpecularGlossiness') {
|
|
1127
|
+
const assetPBRMaterial = assetMaterial;
|
|
1128
|
+
const pbrMaterial = new PBRSpecularGlossinessMaterial();
|
|
1129
|
+
pbrMaterial.ior = assetPBRMaterial.ior;
|
|
1130
|
+
pbrMaterial.albedoColor = assetPBRMaterial.diffuse;
|
|
1131
|
+
pbrMaterial.specularFactor = new Vector3(assetPBRMaterial.specular.x, assetPBRMaterial.specular.y, assetPBRMaterial.specular.z);
|
|
1132
|
+
pbrMaterial.glossinessFactor = assetPBRMaterial.glossness;
|
|
1133
|
+
if (assetPBRMaterial.diffuseMap) {
|
|
1134
|
+
const info = await getTextureInfo(assetPBRMaterial.diffuseMap);
|
|
1135
|
+
if (info) {
|
|
1136
|
+
pbrMaterial.albedoTexture = info.texture;
|
|
1137
|
+
pbrMaterial.albedoTextureSampler = info.sampler;
|
|
1138
|
+
pbrMaterial.albedoTexCoordIndex = info.texCoord;
|
|
1139
|
+
pbrMaterial.albedoTexCoordMatrix = info.transform;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
if (assetPBRMaterial.common.normalMap) {
|
|
1143
|
+
const info = await getTextureInfo(assetPBRMaterial.common.normalMap);
|
|
1144
|
+
if (info) {
|
|
1145
|
+
pbrMaterial.normalTexture = info.texture;
|
|
1146
|
+
pbrMaterial.normalTextureSampler = info.sampler;
|
|
1147
|
+
pbrMaterial.normalTexCoordIndex = info.texCoord;
|
|
1148
|
+
pbrMaterial.normalTexCoordMatrix = info.transform;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
pbrMaterial.normalScale = assetPBRMaterial.common.bumpScale;
|
|
1152
|
+
if (assetPBRMaterial.common.emissiveMap) {
|
|
1153
|
+
const info = await getTextureInfo(assetPBRMaterial.common.emissiveMap);
|
|
1154
|
+
if (info) {
|
|
1155
|
+
pbrMaterial.emissiveTexture = info.texture;
|
|
1156
|
+
pbrMaterial.emissiveTextureSampler = info.sampler;
|
|
1157
|
+
pbrMaterial.emissiveTexCoordIndex = info.texCoord;
|
|
1158
|
+
pbrMaterial.emissiveTexCoordMatrix = info.transform;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
pbrMaterial.emissiveColor = assetPBRMaterial.common.emissiveColor;
|
|
1162
|
+
pbrMaterial.emissiveStrength = assetPBRMaterial.common.emissiveStrength;
|
|
1163
|
+
if (assetPBRMaterial.common.occlusionMap) {
|
|
1164
|
+
const info = await getTextureInfo(assetPBRMaterial.common.occlusionMap);
|
|
1165
|
+
if (info) {
|
|
1166
|
+
pbrMaterial.occlusionTexture = info.texture;
|
|
1167
|
+
pbrMaterial.occlusionTextureSampler = info.sampler;
|
|
1168
|
+
pbrMaterial.occlusionTexCoordIndex = info.texCoord;
|
|
1169
|
+
pbrMaterial.occlusionTexCoordMatrix = info.transform;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
pbrMaterial.occlusionStrength = assetPBRMaterial.common.occlusionStrength;
|
|
1173
|
+
if (assetPBRMaterial.specularGlossnessMap) {
|
|
1174
|
+
const info = await getTextureInfo(assetPBRMaterial.specularGlossnessMap);
|
|
1175
|
+
if (info) {
|
|
1176
|
+
pbrMaterial.specularTexture = info.texture;
|
|
1177
|
+
pbrMaterial.specularTextureSampler = info.sampler;
|
|
1178
|
+
pbrMaterial.specularTexCoordIndex = info.texCoord;
|
|
1179
|
+
pbrMaterial.specularTexCoordMatrix = info.transform;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
pbrMaterial.vertexTangent = assetPBRMaterial.common.useTangent;
|
|
1183
|
+
pbrMaterial.vertexColor = assetPBRMaterial.common.vertexColor;
|
|
1184
|
+
if (assetPBRMaterial.common.alphaMode === 'blend') {
|
|
1185
|
+
pbrMaterial.blendMode = 'blend';
|
|
1186
|
+
} else if (assetPBRMaterial.common.alphaMode === 'mask') {
|
|
1187
|
+
pbrMaterial.alphaCutoff = assetPBRMaterial.common.alphaCutoff;
|
|
1188
|
+
}
|
|
1189
|
+
if (assetPBRMaterial.common.doubleSided) {
|
|
1190
|
+
pbrMaterial.cullMode = 'none';
|
|
1191
|
+
}
|
|
1192
|
+
pbrMaterial.vertexNormal = !!assetMaterial.common.vertexNormal;
|
|
1193
|
+
return pbrMaterial;
|
|
1194
|
+
} else if (assetMaterial.type === 'pbrMetallicRoughness') {
|
|
1195
|
+
const assetPBRMaterial = assetMaterial;
|
|
1196
|
+
const pbrMaterial = new PBRMetallicRoughnessMaterial();
|
|
1197
|
+
pbrMaterial.ior = assetPBRMaterial.ior;
|
|
1198
|
+
pbrMaterial.albedoColor = assetPBRMaterial.diffuse;
|
|
1199
|
+
pbrMaterial.metallic = assetPBRMaterial.metallic;
|
|
1200
|
+
pbrMaterial.roughness = assetPBRMaterial.roughness;
|
|
1201
|
+
if (assetPBRMaterial.diffuseMap) {
|
|
1202
|
+
const info = await getTextureInfo(assetPBRMaterial.diffuseMap);
|
|
1203
|
+
if (info) {
|
|
1204
|
+
pbrMaterial.albedoTexture = info.texture;
|
|
1205
|
+
pbrMaterial.albedoTextureSampler = info.sampler;
|
|
1206
|
+
pbrMaterial.albedoTexCoordIndex = info.texCoord;
|
|
1207
|
+
pbrMaterial.albedoTexCoordMatrix = info.transform;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (assetPBRMaterial.common.normalMap) {
|
|
1211
|
+
const info = await getTextureInfo(assetPBRMaterial.common.normalMap);
|
|
1212
|
+
if (info) {
|
|
1213
|
+
pbrMaterial.normalTexture = info.texture;
|
|
1214
|
+
pbrMaterial.normalTextureSampler = info.sampler;
|
|
1215
|
+
pbrMaterial.normalTexCoordIndex = info.texCoord;
|
|
1216
|
+
pbrMaterial.normalTexCoordMatrix = info.transform;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
pbrMaterial.normalScale = assetPBRMaterial.common.bumpScale;
|
|
1220
|
+
if (assetPBRMaterial.common.emissiveMap) {
|
|
1221
|
+
const info = await getTextureInfo(assetPBRMaterial.common.emissiveMap);
|
|
1222
|
+
if (info) {
|
|
1223
|
+
pbrMaterial.emissiveTexture = info.texture;
|
|
1224
|
+
pbrMaterial.emissiveTextureSampler = info.sampler;
|
|
1225
|
+
pbrMaterial.emissiveTexCoordIndex = info.texCoord;
|
|
1226
|
+
pbrMaterial.emissiveTexCoordMatrix = info.transform;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
pbrMaterial.emissiveColor = assetPBRMaterial.common.emissiveColor;
|
|
1230
|
+
pbrMaterial.emissiveStrength = assetPBRMaterial.common.emissiveStrength;
|
|
1231
|
+
if (assetPBRMaterial.common.occlusionMap) {
|
|
1232
|
+
const info = await getTextureInfo(assetPBRMaterial.common.occlusionMap);
|
|
1233
|
+
if (info) {
|
|
1234
|
+
pbrMaterial.occlusionTexture = info.texture;
|
|
1235
|
+
pbrMaterial.occlusionTextureSampler = info.sampler;
|
|
1236
|
+
pbrMaterial.occlusionTexCoordIndex = info.texCoord;
|
|
1237
|
+
pbrMaterial.occlusionTexCoordMatrix = info.transform;
|
|
1238
|
+
}
|
|
1239
|
+
pbrMaterial.occlusionStrength = assetPBRMaterial.common.occlusionStrength;
|
|
1240
|
+
}
|
|
1241
|
+
if (assetPBRMaterial.metallicMap) {
|
|
1242
|
+
const info = await getTextureInfo(assetPBRMaterial.metallicMap);
|
|
1243
|
+
if (info) {
|
|
1244
|
+
pbrMaterial.metallicRoughnessTexture = info.texture;
|
|
1245
|
+
pbrMaterial.metallicRoughnessTextureSampler = info.sampler;
|
|
1246
|
+
pbrMaterial.metallicRoughnessTexCoordIndex = info.texCoord;
|
|
1247
|
+
pbrMaterial.metallicRoughnessTexCoordMatrix = info.transform;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
pbrMaterial.specularFactor = assetPBRMaterial.specularFactor;
|
|
1251
|
+
if (assetPBRMaterial.specularMap) {
|
|
1252
|
+
const info = await getTextureInfo(assetPBRMaterial.specularMap);
|
|
1253
|
+
if (info) {
|
|
1254
|
+
pbrMaterial.specularTexture = info.texture;
|
|
1255
|
+
pbrMaterial.specularTextureSampler = info.sampler;
|
|
1256
|
+
pbrMaterial.specularTexCoordIndex = info.texCoord;
|
|
1257
|
+
pbrMaterial.specularTexCoordMatrix = info.transform;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
if (assetPBRMaterial.specularColorMap) {
|
|
1261
|
+
const info = await getTextureInfo(assetPBRMaterial.specularColorMap);
|
|
1262
|
+
if (info) {
|
|
1263
|
+
pbrMaterial.specularColorTexture = info.texture;
|
|
1264
|
+
pbrMaterial.specularColorTextureSampler = info.sampler;
|
|
1265
|
+
pbrMaterial.specularColorTexCoordIndex = info.texCoord;
|
|
1266
|
+
pbrMaterial.specularColorTexCoordMatrix = info.transform;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
if (assetPBRMaterial.sheen) {
|
|
1270
|
+
const sheen = assetPBRMaterial.sheen;
|
|
1271
|
+
pbrMaterial.sheen = true;
|
|
1272
|
+
pbrMaterial.sheenColorFactor = sheen.sheenColorFactor;
|
|
1273
|
+
pbrMaterial.sheenRoughnessFactor = sheen.sheenRoughnessFactor;
|
|
1274
|
+
if (sheen.sheenColorMap) {
|
|
1275
|
+
const info = await getTextureInfo(sheen.sheenColorMap);
|
|
1276
|
+
if (info) {
|
|
1277
|
+
pbrMaterial.sheenColorTexture = info.texture;
|
|
1278
|
+
pbrMaterial.sheenColorTextureSampler = info.sampler;
|
|
1279
|
+
pbrMaterial.sheenColorTexCoordIndex = info.texCoord;
|
|
1280
|
+
pbrMaterial.sheenColorTexCoordMatrix = info.transform;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
if (sheen.sheenRoughnessMap) {
|
|
1284
|
+
const info = await getTextureInfo(sheen.sheenRoughnessMap);
|
|
1285
|
+
if (info) {
|
|
1286
|
+
pbrMaterial.sheenRoughnessTexture = info.texture;
|
|
1287
|
+
pbrMaterial.sheenRoughnessTextureSampler = info.sampler;
|
|
1288
|
+
pbrMaterial.sheenRoughnessTexCoordIndex = info.texCoord;
|
|
1289
|
+
pbrMaterial.sheenRoughnessTexCoordMatrix = info.transform;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
if (assetPBRMaterial.iridescence) {
|
|
1294
|
+
const iridescence = assetPBRMaterial.iridescence;
|
|
1295
|
+
pbrMaterial.iridescence = true;
|
|
1296
|
+
pbrMaterial.iridescenceFactor = iridescence.iridescenceFactor;
|
|
1297
|
+
pbrMaterial.iridescenceIor = iridescence.iridescenceIor;
|
|
1298
|
+
if (iridescence.iridescenceMap) {
|
|
1299
|
+
const info = await getTextureInfo(iridescence.iridescenceMap);
|
|
1300
|
+
if (info) {
|
|
1301
|
+
pbrMaterial.iridescenceTexture = info.texture;
|
|
1302
|
+
pbrMaterial.iridescenceTextureSampler = info.sampler;
|
|
1303
|
+
pbrMaterial.iridescenceTexCoordIndex = info.texCoord;
|
|
1304
|
+
pbrMaterial.iridescenceTexCoordMatrix = info.transform;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
pbrMaterial.iridescenceThicknessMin = iridescence.iridescenceThicknessMinimum;
|
|
1308
|
+
pbrMaterial.iridescenceThicknessMax = iridescence.iridescenceThicknessMaximum;
|
|
1309
|
+
if (iridescence.iridescenceThicknessMap) {
|
|
1310
|
+
const info = await getTextureInfo(iridescence.iridescenceThicknessMap);
|
|
1311
|
+
if (info) {
|
|
1312
|
+
pbrMaterial.iridescenceThicknessTexture = info.texture;
|
|
1313
|
+
pbrMaterial.iridescenceThicknessTextureSampler = info.sampler;
|
|
1314
|
+
pbrMaterial.iridescenceThicknessTexCoordIndex = info.texCoord;
|
|
1315
|
+
pbrMaterial.iridescenceThicknessTexCoordMatrix = info.transform;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
if (assetPBRMaterial.transmission) {
|
|
1320
|
+
const transmission = assetPBRMaterial.transmission;
|
|
1321
|
+
pbrMaterial.transmission = true;
|
|
1322
|
+
pbrMaterial.transmissionFactor = transmission.transmissionFactor;
|
|
1323
|
+
if (transmission.transmissionMap) {
|
|
1324
|
+
const info = await getTextureInfo(transmission.transmissionMap);
|
|
1325
|
+
if (info) {
|
|
1326
|
+
pbrMaterial.transmissionTexture = info.texture;
|
|
1327
|
+
pbrMaterial.transmissionTextureSampler = info.sampler;
|
|
1328
|
+
pbrMaterial.transmissionTexCoordIndex = info.texCoord;
|
|
1329
|
+
pbrMaterial.transmissionTexCoordMatrix = info.transform;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
pbrMaterial.thicknessFactor = transmission.thicknessFactor;
|
|
1333
|
+
if (transmission.thicknessMap) {
|
|
1334
|
+
const info = await getTextureInfo(transmission.thicknessMap);
|
|
1335
|
+
if (info) {
|
|
1336
|
+
pbrMaterial.thicknessTexture = info.texture;
|
|
1337
|
+
pbrMaterial.thicknessTextureSampler = info.sampler;
|
|
1338
|
+
pbrMaterial.thicknessTexCoordIndex = info.texCoord;
|
|
1339
|
+
pbrMaterial.thicknessTexCoordMatrix = info.transform;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
pbrMaterial.attenuationDistance = transmission.attenuationDistance;
|
|
1343
|
+
pbrMaterial.attenuationColor = transmission.attenuationColor;
|
|
1344
|
+
}
|
|
1345
|
+
if (assetPBRMaterial.clearcoat) {
|
|
1346
|
+
const cc = assetPBRMaterial.clearcoat;
|
|
1347
|
+
pbrMaterial.clearcoat = true;
|
|
1348
|
+
pbrMaterial.clearcoatIntensity = cc.clearCoatFactor;
|
|
1349
|
+
pbrMaterial.clearcoatRoughnessFactor = cc.clearCoatRoughnessFactor;
|
|
1350
|
+
if (cc.clearCoatIntensityMap) {
|
|
1351
|
+
const info = await getTextureInfo(cc.clearCoatIntensityMap);
|
|
1352
|
+
if (info) {
|
|
1353
|
+
pbrMaterial.clearcoatIntensityTexture = info.texture;
|
|
1354
|
+
pbrMaterial.clearcoatIntensityTextureSampler = info.sampler;
|
|
1355
|
+
pbrMaterial.clearcoatIntensityTexCoordIndex = info.texCoord;
|
|
1356
|
+
pbrMaterial.clearcoatIntensityTexCoordMatrix = info.transform;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
if (cc.clearCoatRoughnessMap) {
|
|
1360
|
+
const info = await getTextureInfo(cc.clearCoatRoughnessMap);
|
|
1361
|
+
if (info) {
|
|
1362
|
+
pbrMaterial.clearcoatRoughnessTexture = info.texture;
|
|
1363
|
+
pbrMaterial.clearcoatRoughnessTextureSampler = info.sampler;
|
|
1364
|
+
pbrMaterial.clearcoatRoughnessTexCoordIndex = info.texCoord;
|
|
1365
|
+
pbrMaterial.clearcoatRoughnessTexCoordMatrix = info.transform;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
if (cc.clearCoatNormalMap) {
|
|
1369
|
+
const info = await getTextureInfo(cc.clearCoatNormalMap);
|
|
1370
|
+
if (info) {
|
|
1371
|
+
pbrMaterial.clearcoatNormalTexture = info.texture;
|
|
1372
|
+
pbrMaterial.clearcoatNormalTextureSampler = info.sampler;
|
|
1373
|
+
pbrMaterial.clearcoatNormalTexCoordIndex = info.texCoord;
|
|
1374
|
+
pbrMaterial.clearcoatNormalTexCoordMatrix = info.transform;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
pbrMaterial.vertexTangent = assetPBRMaterial.common.useTangent;
|
|
1379
|
+
pbrMaterial.vertexColor = assetPBRMaterial.common.vertexColor;
|
|
1380
|
+
if (assetPBRMaterial.common.alphaMode === 'blend') {
|
|
1381
|
+
pbrMaterial.blendMode = 'blend';
|
|
1382
|
+
} else if (assetPBRMaterial.common.alphaMode === 'mask') {
|
|
1383
|
+
pbrMaterial.alphaCutoff = assetPBRMaterial.common.alphaCutoff;
|
|
1384
|
+
}
|
|
1385
|
+
if (assetPBRMaterial.common.doubleSided) {
|
|
1386
|
+
pbrMaterial.cullMode = 'none';
|
|
1387
|
+
}
|
|
1388
|
+
pbrMaterial.vertexNormal = !!assetMaterial.common.vertexNormal;
|
|
1389
|
+
return pbrMaterial;
|
|
1390
|
+
}
|
|
1391
|
+
return null;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
/** @internal */ function processMorphData(subMesh, mesh, morphWeights, morphNames) {
|
|
1395
|
+
const device = getDevice();
|
|
1396
|
+
const numTargets = subMesh.numTargets;
|
|
1397
|
+
if (numTargets === 0) {
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const attributes = Object.getOwnPropertyNames(subMesh.targets);
|
|
1401
|
+
const positionInfo = subMesh.primitive.vertices['position'];
|
|
1402
|
+
const numVertices = positionInfo ? positionInfo.data.length / getVertexFormatComponentCount(positionInfo.format) >> 0 : 0;
|
|
1403
|
+
const weightsAndOffsets = new Float32Array(4 + MAX_MORPH_TARGETS + MAX_MORPH_ATTRIBUTES);
|
|
1404
|
+
for(let i = 0; i < numTargets; i++){
|
|
1405
|
+
weightsAndOffsets[4 + i] = morphWeights?.[i] ?? 0;
|
|
1406
|
+
}
|
|
1407
|
+
const textureSize = Math.ceil(Math.sqrt(numVertices * attributes.length * numTargets));
|
|
1408
|
+
if (textureSize > device.getDeviceCaps().textureCaps.maxTextureSize) {
|
|
1409
|
+
// TODO: reduce morph attributes
|
|
1410
|
+
throw new Error(`Morph target data too large`);
|
|
1411
|
+
}
|
|
1412
|
+
weightsAndOffsets[0] = textureSize;
|
|
1413
|
+
weightsAndOffsets[1] = textureSize;
|
|
1414
|
+
weightsAndOffsets[2] = numVertices;
|
|
1415
|
+
weightsAndOffsets[3] = numTargets;
|
|
1416
|
+
let offset = 0;
|
|
1417
|
+
const textureData = new Float32Array(textureSize * textureSize * 4);
|
|
1418
|
+
for(let attrib = 0; attrib < MAX_MORPH_ATTRIBUTES; attrib++){
|
|
1419
|
+
const index = attributes.indexOf(String(attrib));
|
|
1420
|
+
if (index < 0) {
|
|
1421
|
+
weightsAndOffsets[4 + MAX_MORPH_TARGETS + attrib] = -1;
|
|
1422
|
+
continue;
|
|
1423
|
+
}
|
|
1424
|
+
weightsAndOffsets[4 + MAX_MORPH_TARGETS + attrib] = offset >> 2;
|
|
1425
|
+
const info = subMesh.targets[attrib];
|
|
1426
|
+
if (info.data.length !== numTargets) {
|
|
1427
|
+
console.error(`Invalid morph target data`);
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
for(let t = 0; t < numTargets; t++){
|
|
1431
|
+
const data = info.data[t];
|
|
1432
|
+
for(let i = 0; i < numVertices; i++){
|
|
1433
|
+
for(let j = 0; j < 4; j++){
|
|
1434
|
+
textureData[offset++] = j < info.numComponents ? data[i * info.numComponents + j] : 1;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
616
1437
|
}
|
|
617
1438
|
}
|
|
1439
|
+
const morphBoundingBox = new BoundingBox();
|
|
1440
|
+
calculateMorphBoundingBox(morphBoundingBox, subMesh.targetBox, weightsAndOffsets.subarray(4, 4 + MAX_MORPH_TARGETS), numTargets);
|
|
1441
|
+
const meshAABB = mesh.getBoundingVolume().toAABB();
|
|
1442
|
+
morphBoundingBox.minPoint.addBy(meshAABB.minPoint);
|
|
1443
|
+
morphBoundingBox.maxPoint.addBy(meshAABB.maxPoint);
|
|
1444
|
+
const names = {};
|
|
1445
|
+
for(let i = 0; i < numTargets; i++){
|
|
1446
|
+
const name = morphNames?.[i] ?? `Target${i}`;
|
|
1447
|
+
names[name] = i;
|
|
1448
|
+
}
|
|
1449
|
+
mesh.setMorphData({
|
|
1450
|
+
width: textureSize,
|
|
1451
|
+
height: textureSize,
|
|
1452
|
+
data: textureData
|
|
1453
|
+
});
|
|
1454
|
+
mesh.setMorphInfo({
|
|
1455
|
+
data: weightsAndOffsets,
|
|
1456
|
+
names
|
|
1457
|
+
});
|
|
1458
|
+
mesh.setMorphBoundingInfo({
|
|
1459
|
+
targetBoxes: subMesh.targetBox,
|
|
1460
|
+
originBox: new BoundingBox(meshAABB)
|
|
1461
|
+
});
|
|
1462
|
+
mesh.setAnimatedBoundingBox(morphBoundingBox);
|
|
1463
|
+
}
|
|
1464
|
+
/** @internal */ function getAssetMeshMorphTargetCount(mesh) {
|
|
1465
|
+
let count = 0;
|
|
1466
|
+
for (const subMesh of mesh.subMeshes){
|
|
1467
|
+
count = Math.max(count, subMesh.numTargets);
|
|
1468
|
+
}
|
|
1469
|
+
return count;
|
|
1470
|
+
}
|
|
1471
|
+
/** @internal */ function getAssetMeshMorphTargetName(mesh, index) {
|
|
1472
|
+
return mesh.morphNames?.[index] ?? `Target${index}`;
|
|
1473
|
+
}
|
|
1474
|
+
/** @internal */ function calculateMorphBoundingBox(morphBoundingBox, keyframeBoundingBox, weights, numTargets) {
|
|
1475
|
+
morphBoundingBox.minPoint.setXYZ(0, 0, 0);
|
|
1476
|
+
morphBoundingBox.maxPoint.setXYZ(0, 0, 0);
|
|
1477
|
+
for(let i = 0; i < numTargets; i++){
|
|
1478
|
+
const weight = weights[i];
|
|
1479
|
+
const keyframeBox = keyframeBoundingBox[i];
|
|
1480
|
+
morphBoundingBox.minPoint.x += keyframeBox.minPoint.x * weight;
|
|
1481
|
+
morphBoundingBox.minPoint.y += keyframeBox.minPoint.y * weight;
|
|
1482
|
+
morphBoundingBox.minPoint.z += keyframeBox.minPoint.z * weight;
|
|
1483
|
+
morphBoundingBox.maxPoint.x += keyframeBox.maxPoint.x * weight;
|
|
1484
|
+
morphBoundingBox.maxPoint.y += keyframeBox.maxPoint.y * weight;
|
|
1485
|
+
morphBoundingBox.maxPoint.z += keyframeBox.maxPoint.z * weight;
|
|
1486
|
+
}
|
|
618
1487
|
}
|
|
619
1488
|
|
|
620
1489
|
export { AssetHierarchyNode, AssetScene, AssetSkeleton, NamedObject, SharedModel };
|