@forgeax/engine-gltf 0.1.27 → 0.1.29
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/README.md +13 -11
- package/dist/bridge.d.ts +7 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/cli-gltf.d.ts.map +1 -1
- package/dist/cli-gltf.mjs +19 -17
- package/dist/cli-gltf.mjs.map +1 -1
- package/dist/gltf-importer.d.ts.map +1 -1
- package/dist/importer-entry.mjs +47 -21
- package/dist/importer-entry.mjs.map +1 -1
- package/dist/index.mjs +47 -21
- package/dist/index.mjs.map +1 -1
- package/dist/node-file-entry.mjs +9 -7
- package/dist/node-file-entry.mjs.map +1 -1
- package/dist/parse-gltf.d.ts.map +1 -1
- package/dist/parse-skin.d.ts +8 -16
- package/dist/parse-skin.d.ts.map +1 -1
- package/package.json +13 -16
- package/src/__tests__/bridge.unit.test.ts +70 -51
- package/src/__tests__/cli-gltf.integration.test.ts +1 -1
- package/src/__tests__/gltf.unit.test.ts +96 -16
- package/src/__tests__/morph-import.integration.test.ts +1 -1
- package/src/bridge.ts +34 -10
- package/src/cli-gltf.ts +16 -18
- package/src/errors.ts +3 -3
- package/src/gltf-importer.ts +29 -11
- package/src/parse-gltf.ts +5 -0
- package/src/parse-skin.ts +14 -41
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { err, ok, createMaterialError, standardMaterialParameters, reconcileMeshMaterialSlotTopology, MESH_MATERIAL_SLOT_SOURCE_OVERRIDE_PAYLOAD_SCHEMA, STANDARD_MATERIAL_PARAM_SCHEMA, STANDARD_PHYSICAL_PARAMETER_NAMES, STANDARD_TRANSMISSION_PARAMETER_NAMES, ImportError, STANDARD_LAYER_PARAMETER_GROUPS, IMPORT_ERROR_HINTS, toShared, resolveMeshMaterialSlotDefaultGuid } from '@forgeax/engine-types';
|
|
1
|
+
import { err, ok, createMaterialError, standardMaterialParameters, reconcileMeshMaterialSlotTopology, MESH_MATERIAL_SLOT_SOURCE_OVERRIDE_PAYLOAD_SCHEMA, STANDARD_MATERIAL_PARAM_SCHEMA, STANDARD_PHYSICAL_PARAMETER_NAMES, STANDARD_TRANSMISSION_PARAMETER_NAMES, ImportError, STANDARD_LAYER_PARAMETER_GROUPS, IMPORT_ERROR_HINTS, parseConservativeAnimatedBounds, readConservativeAnimatedBounds, toShared, resolveMeshMaterialSlotDefaultGuid } from '@forgeax/engine-types';
|
|
2
2
|
export { err, ok } from '@forgeax/engine-types';
|
|
3
3
|
import { computeTangentVec4, packInterleavedVertexAttributes } from '@forgeax/engine-geometry';
|
|
4
4
|
import { box3, mat4, vec3, quat } from '@forgeax/engine-math';
|
|
@@ -13,7 +13,7 @@ var GLTF_MESHOPT_FILTERS = ["NONE", "OCTAHEDRAL", "QUATERNION", "EXPONENTIAL"];
|
|
|
13
13
|
var gltfErrorPolicy = {
|
|
14
14
|
"gltf-malformed-header": {
|
|
15
15
|
expected: "GLB 12-byte header (magic 0x46546C67 + version=2 + length) plus mandatory JSON chunk",
|
|
16
|
-
hint: "verify .glb is not truncated; rerun: forgeax
|
|
16
|
+
hint: "verify .glb is not truncated; rerun: forgeax asset import <path> --root <project> --json"
|
|
17
17
|
},
|
|
18
18
|
"gltf-version-unsupported": {
|
|
19
19
|
expected: 'asset.version === "2.0"',
|
|
@@ -49,7 +49,7 @@ var gltfErrorPolicy = {
|
|
|
49
49
|
},
|
|
50
50
|
"gltf-meta-missing": {
|
|
51
51
|
expected: "sidecar <source>.meta.json (importer: 'gltf') present in same directory",
|
|
52
|
-
hint: "run: forgeax
|
|
52
|
+
hint: "run: forgeax asset import <path> --root <project> --json"
|
|
53
53
|
},
|
|
54
54
|
"gltf-instancing-count-mismatch": {
|
|
55
55
|
expected: "all instance attribute accessors share the same count",
|
|
@@ -77,7 +77,7 @@ var gltfErrorPolicy = {
|
|
|
77
77
|
},
|
|
78
78
|
"gltf-image-extract-failed": {
|
|
79
79
|
expected: "image bytes extractable from bufferView / data-URI / external URI without corruption",
|
|
80
|
-
hint: "verify the bufferView byte range / data: URI base64 / external URI sibling file is intact next to the .gltf source; rerun: forgeax
|
|
80
|
+
hint: "verify the bufferView byte range / data: URI base64 / external URI sibling file is intact next to the .gltf source; rerun: forgeax asset import <path> --root <project> --json"
|
|
81
81
|
},
|
|
82
82
|
"gltf-skin-attr-asymmetric": {
|
|
83
83
|
expected: "mesh primitive declares JOINTS_0 and WEIGHTS_0 symmetrically (both present or both absent)",
|
|
@@ -716,7 +716,7 @@ function composeMat4(out, tx, ty, tz, qx, qy, qz, qw, sx, sy, sz) {
|
|
|
716
716
|
function gltfDocToSceneAsset(doc, ctx) {
|
|
717
717
|
const sceneIr = doc.scenes[doc.defaultSceneIndex];
|
|
718
718
|
const resultNodes = [];
|
|
719
|
-
if (sceneIr === void 0) return { kind: "scene", entities:
|
|
719
|
+
if (sceneIr === void 0) return { kind: "scene", entities: {} };
|
|
720
720
|
const importedLights = doc.lights ?? doc.extensions?.KHR_lights_punctual?.lights ?? [];
|
|
721
721
|
const animationTargetIds = /* @__PURE__ */ new Map();
|
|
722
722
|
for (const clip of doc.animationClips) {
|
|
@@ -809,7 +809,10 @@ function gltfDocToSceneAsset(doc, ctx) {
|
|
|
809
809
|
components.MeshRenderer = { materials: [] };
|
|
810
810
|
}
|
|
811
811
|
if (ir.instancing !== void 0) {
|
|
812
|
-
|
|
812
|
+
const collectionId = ctx.instanceCollectionIdsByNodeIndex?.get(gltfNodeIdx);
|
|
813
|
+
if (collectionId !== void 0) {
|
|
814
|
+
components.Instances = { collectionId };
|
|
815
|
+
}
|
|
813
816
|
}
|
|
814
817
|
if (isCamera) {
|
|
815
818
|
components.Camera = {
|
|
@@ -837,10 +840,20 @@ function gltfDocToSceneAsset(doc, ctx) {
|
|
|
837
840
|
for (let i = 0; i < 16; i++) parentWorld[i] = savedParent[i] ?? 0;
|
|
838
841
|
};
|
|
839
842
|
for (const rootIdx of sceneIr.nodes) visit(rootIdx, null);
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
843
|
+
const keyByLocalId = /* @__PURE__ */ new Map();
|
|
844
|
+
for (const node of resultNodes) keyByLocalId.set(node.localIdx, `node-${node.localIdx}`);
|
|
845
|
+
const entities = {};
|
|
846
|
+
for (const node of resultNodes) {
|
|
847
|
+
const components = { ...node.components };
|
|
848
|
+
const childOf = components.ChildOf;
|
|
849
|
+
if (childOf !== void 0 && typeof childOf.parent === "number") {
|
|
850
|
+
const parentKey = keyByLocalId.get(childOf.parent);
|
|
851
|
+
if (parentKey === void 0)
|
|
852
|
+
throw new Error(`gltfDocToSceneAsset: missing parent node ${childOf.parent}`);
|
|
853
|
+
components.ChildOf = { ...childOf, parent: parentKey };
|
|
854
|
+
}
|
|
855
|
+
entities[`node-${node.localIdx}`] = { components };
|
|
856
|
+
}
|
|
844
857
|
const lightFacts = importedLights.map((light) => ({
|
|
845
858
|
kind: light.type,
|
|
846
859
|
intensity: light.intensity,
|
|
@@ -849,7 +862,7 @@ function gltfDocToSceneAsset(doc, ctx) {
|
|
|
849
862
|
}));
|
|
850
863
|
return {
|
|
851
864
|
kind: "scene",
|
|
852
|
-
entities
|
|
865
|
+
entities,
|
|
853
866
|
...lightFacts.length === 0 ? {} : { lights: lightFacts }
|
|
854
867
|
};
|
|
855
868
|
}
|
|
@@ -2303,8 +2316,6 @@ function parseAnimation(animationsJson, nodesJson, accessors, bufferViews, buffe
|
|
|
2303
2316
|
}
|
|
2304
2317
|
return ok(clips);
|
|
2305
2318
|
}
|
|
2306
|
-
|
|
2307
|
-
// src/parse-skin.ts
|
|
2308
2319
|
var MAX_JOINTS = 256;
|
|
2309
2320
|
var SKIN_ACCESSOR_TYPES = ["MAT4"];
|
|
2310
2321
|
function identityMat4() {
|
|
@@ -2385,10 +2396,14 @@ function parseSkin(skinsJson, nodesJson, accessors, bufferViews, buffers) {
|
|
|
2385
2396
|
if (!pathResult.ok) return err(pathResult.error);
|
|
2386
2397
|
jointPaths.push(pathResult.value.join("/"));
|
|
2387
2398
|
}
|
|
2399
|
+
const bounds = parseConservativeAnimatedBounds(
|
|
2400
|
+
skin.extras?.forgeax?.conservativeAnimatedBounds
|
|
2401
|
+
);
|
|
2388
2402
|
records.push({
|
|
2389
2403
|
jointCount: joints.length,
|
|
2390
2404
|
inverseBindMatrices: ibm,
|
|
2391
|
-
jointPaths
|
|
2405
|
+
jointPaths,
|
|
2406
|
+
...bounds === void 0 ? {} : { bounds }
|
|
2392
2407
|
});
|
|
2393
2408
|
}
|
|
2394
2409
|
return ok(records);
|
|
@@ -3599,6 +3614,16 @@ function isGlbBytes(source) {
|
|
|
3599
3614
|
function publishesCatalogProduct(input) {
|
|
3600
3615
|
return input.importSettings.geometry !== "procedural";
|
|
3601
3616
|
}
|
|
3617
|
+
function applyImportSettingsBounds(doc, importSettings) {
|
|
3618
|
+
let changed = false;
|
|
3619
|
+
const skeletons = doc.skeletons.map((record, sourceIndex) => {
|
|
3620
|
+
const bounds = readConservativeAnimatedBounds(importSettings, sourceIndex);
|
|
3621
|
+
if (bounds === void 0 || record.bounds !== void 0) return record;
|
|
3622
|
+
changed = true;
|
|
3623
|
+
return { ...record, bounds };
|
|
3624
|
+
});
|
|
3625
|
+
return changed ? { ...doc, skeletons } : doc;
|
|
3626
|
+
}
|
|
3602
3627
|
function previousMaterialSlotTopology(ctx, meshSourceKey) {
|
|
3603
3628
|
if (meshSourceKey === void 0) return void 0;
|
|
3604
3629
|
const value = ctx.sourceOverrides?.[meshSourceKey]?.materialSlots;
|
|
@@ -3918,7 +3943,7 @@ async function importGltf(ctx, meshopt) {
|
|
|
3918
3943
|
}
|
|
3919
3944
|
const parsed = await parseDoc(ctx.source, read.value, ctx);
|
|
3920
3945
|
if (!parsed.ok) return parsed;
|
|
3921
|
-
const doc = parsed.value;
|
|
3946
|
+
const doc = applyImportSettingsBounds(parsed.value, ctx.importSettings);
|
|
3922
3947
|
const maps = buildHandleMaps(ctx.subAssets, doc);
|
|
3923
3948
|
const imageColorSpaces = deriveTextureColorSpace({
|
|
3924
3949
|
imageCount: (doc.images ?? []).length,
|
|
@@ -4217,7 +4242,7 @@ async function importGltf(ctx, meshopt) {
|
|
|
4217
4242
|
fieldName: prov.fieldName,
|
|
4218
4243
|
...prov.arrayIndex !== void 0 ? { arrayIndex: prov.arrayIndex } : {}
|
|
4219
4244
|
},
|
|
4220
|
-
|
|
4245
|
+
sceneEntityKey: prov.sceneEntityKey
|
|
4221
4246
|
};
|
|
4222
4247
|
}
|
|
4223
4248
|
return { guid };
|
|
@@ -4228,19 +4253,19 @@ async function importGltf(ctx, meshopt) {
|
|
|
4228
4253
|
});
|
|
4229
4254
|
const handleValueProvenance = /* @__PURE__ */ new Map();
|
|
4230
4255
|
const skeletonGuidProvenance = /* @__PURE__ */ new Map();
|
|
4231
|
-
for (const entity of scene.entities) {
|
|
4256
|
+
for (const [sceneEntityKey, entity] of Object.entries(scene.entities)) {
|
|
4232
4257
|
const comps = entity.components;
|
|
4233
4258
|
const mf = comps.MeshFilter;
|
|
4234
4259
|
if (mf !== void 0 && typeof mf.assetHandle === "number") {
|
|
4235
4260
|
handleValueProvenance.set(mf.assetHandle, {
|
|
4236
|
-
|
|
4261
|
+
sceneEntityKey,
|
|
4237
4262
|
componentName: "MeshFilter",
|
|
4238
4263
|
fieldName: "assetHandle"
|
|
4239
4264
|
});
|
|
4240
4265
|
}
|
|
4241
4266
|
const skin = comps.Skin;
|
|
4242
4267
|
if (skin !== void 0 && typeof skin.skeleton === "string") {
|
|
4243
|
-
skeletonGuidProvenance.set(skin.skeleton, {
|
|
4268
|
+
skeletonGuidProvenance.set(skin.skeleton, { sceneEntityKey });
|
|
4244
4269
|
}
|
|
4245
4270
|
}
|
|
4246
4271
|
const meshGuidList = [...maps.meshGuidByIndex.values()];
|
|
@@ -4258,7 +4283,7 @@ async function importGltf(ctx, meshopt) {
|
|
|
4258
4283
|
skProv !== void 0 ? {
|
|
4259
4284
|
guid,
|
|
4260
4285
|
sourceField: { componentName: "Skin", fieldName: "skeleton" },
|
|
4261
|
-
|
|
4286
|
+
sceneEntityKey: skProv.sceneEntityKey
|
|
4262
4287
|
} : { guid }
|
|
4263
4288
|
);
|
|
4264
4289
|
cursor++;
|
|
@@ -4288,7 +4313,8 @@ async function importGltf(ctx, meshopt) {
|
|
|
4288
4313
|
const payload = {
|
|
4289
4314
|
kind: "skeleton",
|
|
4290
4315
|
inverseBindMatrices: rec.inverseBindMatrices,
|
|
4291
|
-
jointCount: rec.jointCount
|
|
4316
|
+
jointCount: rec.jointCount,
|
|
4317
|
+
...rec.bounds === void 0 ? {} : { bounds: rec.bounds }
|
|
4292
4318
|
};
|
|
4293
4319
|
out.push({ guid: sub.guid, kind: "skeleton", payload, refs: [], artifacts: {} });
|
|
4294
4320
|
} else if (sub.kind === "skin") {
|