@forgeax/engine-gltf 0.1.6 → 0.1.19
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 +9 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/transmission-pack-carrier.integration.test.d.ts +2 -0
- package/dist/__tests__/transmission-pack-carrier.integration.test.d.ts.map +1 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/check-extensions.d.ts +3 -3
- package/dist/check-extensions.d.ts.map +1 -1
- package/dist/cli-gltf.mjs +161 -69
- package/dist/cli-gltf.mjs.map +1 -1
- package/dist/errors.d.ts +7 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/gltf-importer.d.ts.map +1 -1
- package/dist/importer-entry.mjs +177 -72
- package/dist/importer-entry.mjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +177 -72
- package/dist/index.mjs.map +1 -1
- package/dist/material/parse-material.d.ts +118 -0
- package/dist/material/parse-material.d.ts.map +1 -0
- package/dist/node-file-entry.mjs +161 -69
- package/dist/node-file-entry.mjs.map +1 -1
- package/dist/parse-gltf.d.ts +17 -103
- package/dist/parse-gltf.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/__tests__/bridge-material-values.unit.test.ts +46 -0
- package/src/__tests__/gltf-error-derived-views.test-d.ts +4 -0
- package/src/__tests__/gltf-error-policy-owner.unit.test.ts +26 -178
- package/src/__tests__/gltf.unit.test.ts +28 -4
- package/src/__tests__/material-pack-refs.integration.test.ts +12 -0
- package/src/__tests__/parse-gltf.unit.test.ts +121 -0
- package/src/__tests__/transmission-pack-carrier.integration.test.ts +82 -0
- package/src/bridge.ts +12 -1
- package/src/check-extensions.ts +14 -9
- package/src/errors.ts +12 -0
- package/src/gltf-importer.ts +6 -0
- package/src/index.ts +1 -0
- package/src/material/parse-material.ts +342 -0
- package/src/parse-gltf.ts +50 -277
|
@@ -14,6 +14,8 @@ describe('glTF material Pack refs', () => {
|
|
|
14
14
|
normalTexture: { texture: 2, sampler: 2 },
|
|
15
15
|
occlusionTexture: { texture: 3, sampler: 3 },
|
|
16
16
|
emissiveTexture: { texture: 4, sampler: 4 },
|
|
17
|
+
transmissionTexture: { texture: 5, sampler: 5 },
|
|
18
|
+
thicknessTexture: { texture: 6, sampler: 6 },
|
|
17
19
|
} as unknown as GltfMaterialIr;
|
|
18
20
|
const doc = {
|
|
19
21
|
textures: [
|
|
@@ -22,6 +24,8 @@ describe('glTF material Pack refs', () => {
|
|
|
22
24
|
{ source: 2, sampler: 2 },
|
|
23
25
|
{ source: 3, sampler: 3 },
|
|
24
26
|
{ source: 4, sampler: 4 },
|
|
27
|
+
{ source: 5, sampler: 5 },
|
|
28
|
+
{ source: 6, sampler: 6 },
|
|
25
29
|
],
|
|
26
30
|
} as unknown as GltfDoc;
|
|
27
31
|
const refs = materialRefsForPack(
|
|
@@ -33,6 +37,8 @@ describe('glTF material Pack refs', () => {
|
|
|
33
37
|
[2, 'texture-2'],
|
|
34
38
|
[3, 'texture-3'],
|
|
35
39
|
[4, 'texture-4'],
|
|
40
|
+
[5, 'texture-5'],
|
|
41
|
+
[6, 'texture-6'],
|
|
36
42
|
]),
|
|
37
43
|
new Map([
|
|
38
44
|
[0, 'sampler-0'],
|
|
@@ -40,6 +46,8 @@ describe('glTF material Pack refs', () => {
|
|
|
40
46
|
[2, 'sampler-2'],
|
|
41
47
|
[3, 'sampler-3'],
|
|
42
48
|
[4, 'sampler-4'],
|
|
49
|
+
[5, 'sampler-5'],
|
|
50
|
+
[6, 'sampler-6'],
|
|
43
51
|
]),
|
|
44
52
|
);
|
|
45
53
|
expect(refs.map((ref) => ref.guid)).toEqual([
|
|
@@ -53,6 +61,10 @@ describe('glTF material Pack refs', () => {
|
|
|
53
61
|
'sampler-3',
|
|
54
62
|
'texture-4',
|
|
55
63
|
'sampler-4',
|
|
64
|
+
'texture-5',
|
|
65
|
+
'sampler-5',
|
|
66
|
+
'texture-6',
|
|
67
|
+
'sampler-6',
|
|
56
68
|
]);
|
|
57
69
|
});
|
|
58
70
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { describe, expect, it } from 'vitest';
|
|
3
3
|
import { dataUriBase64Payload, decodeBase64 } from '../data-uri.js';
|
|
4
|
+
import { parseMaterial as parseMaterialIr } from '../material/parse-material.js';
|
|
4
5
|
import { parseGltf } from '../parse-gltf.js';
|
|
5
6
|
|
|
6
7
|
const noopLoader = async (_uri: string) => new ArrayBuffer(0);
|
|
@@ -41,6 +42,126 @@ describe('glTF MASK alpha cutoff parsing', () => {
|
|
|
41
42
|
});
|
|
42
43
|
});
|
|
43
44
|
|
|
45
|
+
describe('glTF transmission material IR', () => {
|
|
46
|
+
it('rejects BLEND materials with effective transmission as a structured error', () => {
|
|
47
|
+
const result = parseMaterialIr(
|
|
48
|
+
{
|
|
49
|
+
alphaMode: 'BLEND',
|
|
50
|
+
extensions: { KHR_materials_transmission: { transmissionFactor: 1 } },
|
|
51
|
+
},
|
|
52
|
+
[],
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
expect(result.ok).toBe(false);
|
|
56
|
+
if (result.ok) return;
|
|
57
|
+
expect(result.error.code).toBe('gltf-material-transmission-invalid');
|
|
58
|
+
expect(result.error.detail).toEqual({
|
|
59
|
+
extension: 'KHR_materials_transmission',
|
|
60
|
+
field: 'alphaMode',
|
|
61
|
+
reason: 'blend',
|
|
62
|
+
actual: 'BLEND',
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('projects transmission, IOR, volume, channel, and texture transform facts', async () => {
|
|
67
|
+
const result = await parseGltf(
|
|
68
|
+
{
|
|
69
|
+
asset: { version: '2.0' },
|
|
70
|
+
extensionsUsed: ['KHR_materials_transmission', 'KHR_materials_ior', 'KHR_materials_volume'],
|
|
71
|
+
materials: [
|
|
72
|
+
{
|
|
73
|
+
pbrMetallicRoughness: {
|
|
74
|
+
baseColorTexture: {
|
|
75
|
+
index: 0,
|
|
76
|
+
texCoord: 1,
|
|
77
|
+
extensions: {
|
|
78
|
+
KHR_texture_transform: {
|
|
79
|
+
offset: [0.25, 0.5],
|
|
80
|
+
rotation: 0.25,
|
|
81
|
+
scale: [2, 3],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
extensions: {
|
|
87
|
+
KHR_materials_transmission: {
|
|
88
|
+
transmissionFactor: 0.75,
|
|
89
|
+
transmissionTexture: { index: 1, texCoord: 2 },
|
|
90
|
+
},
|
|
91
|
+
KHR_materials_ior: { ior: 1.33 },
|
|
92
|
+
KHR_materials_volume: {
|
|
93
|
+
thicknessFactor: 0.04,
|
|
94
|
+
thicknessTexture: { index: 2, texCoord: 3 },
|
|
95
|
+
attenuationColor: [0.2, 0.4, 0.8],
|
|
96
|
+
attenuationDistance: Number.POSITIVE_INFINITY,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
textures: [
|
|
102
|
+
{ sampler: 7, source: 0 },
|
|
103
|
+
{ sampler: 8, source: 1 },
|
|
104
|
+
{ sampler: 9, source: 2 },
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
noopLoader,
|
|
108
|
+
'/material-transmission.gltf',
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
expect(result.ok).toBe(true);
|
|
112
|
+
if (!result.ok) return;
|
|
113
|
+
expect(result.value.materials[0]).toMatchObject({
|
|
114
|
+
transmissionFactor: 0.75,
|
|
115
|
+
transmissionTexture: { texture: 1, sampler: 8, texCoord: 2 },
|
|
116
|
+
ior: 1.33,
|
|
117
|
+
thicknessFactor: 0.04,
|
|
118
|
+
thicknessTexture: { texture: 2, sampler: 9, texCoord: 3 },
|
|
119
|
+
attenuationColor: [0.2, 0.4, 0.8],
|
|
120
|
+
});
|
|
121
|
+
expect(result.value.materials[0]).not.toHaveProperty('attenuationDistance');
|
|
122
|
+
expect(result.value.materials[0]?.baseColorTexture).toMatchObject({
|
|
123
|
+
transform: { offset: [0.25, 0.5], rotation: 0.25, scale: [2, 3] },
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('rejects an IOR at the non-positive boundary', async () => {
|
|
128
|
+
const result = await parseGltf(
|
|
129
|
+
{
|
|
130
|
+
asset: { version: '2.0' },
|
|
131
|
+
extensionsUsed: ['KHR_materials_ior'],
|
|
132
|
+
materials: [{ extensions: { KHR_materials_ior: { ior: 0 } } }],
|
|
133
|
+
},
|
|
134
|
+
noopLoader,
|
|
135
|
+
'/material-invalid-ior.gltf',
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(result.ok).toBe(false);
|
|
139
|
+
if (result.ok) return;
|
|
140
|
+
expect(result.error.code).toBe('gltf-material-transmission-invalid');
|
|
141
|
+
expect(result.error.detail).toMatchObject({ extension: 'KHR_materials_ior', field: 'ior' });
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('accepts all transmission material required extensions through the parse path', async () => {
|
|
145
|
+
const result = await parseGltf(
|
|
146
|
+
{
|
|
147
|
+
asset: { version: '2.0' },
|
|
148
|
+
extensionsUsed: ['KHR_materials_transmission', 'KHR_materials_ior', 'KHR_materials_volume'],
|
|
149
|
+
extensionsRequired: [
|
|
150
|
+
'KHR_materials_transmission',
|
|
151
|
+
'KHR_materials_ior',
|
|
152
|
+
'KHR_materials_volume',
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
noopLoader,
|
|
156
|
+
'/material-required-transmission.gltf',
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
expect(result.ok).toBe(true);
|
|
160
|
+
if (!result.ok) return;
|
|
161
|
+
expect(result.value.diagnostics.unsupportedExtensions).toEqual([]);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
44
165
|
describe('glTF COLOR_0 importer carrier', () => {
|
|
45
166
|
it('publishes normalized VEC3 FLOAT colors as importer-owned RGBA', async () => {
|
|
46
167
|
const fixture = JSON.parse(
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { toMaterialAsset } from '../bridge.js';
|
|
3
|
+
import { parseGltf, toAssetPack } from '../parse-gltf.js';
|
|
4
|
+
|
|
5
|
+
const noopLoader = async (_uri: string) => new ArrayBuffer(0);
|
|
6
|
+
|
|
7
|
+
describe('glTF transmission carrier route', () => {
|
|
8
|
+
it('keeps required transmission extensions through parse, pack identity, and Standard bridge', async () => {
|
|
9
|
+
const source = {
|
|
10
|
+
asset: { version: '2.0' },
|
|
11
|
+
extensionsRequired: [
|
|
12
|
+
'KHR_materials_transmission',
|
|
13
|
+
'KHR_materials_ior',
|
|
14
|
+
'KHR_materials_volume',
|
|
15
|
+
],
|
|
16
|
+
extensionsUsed: ['KHR_materials_transmission', 'KHR_materials_ior', 'KHR_materials_volume'],
|
|
17
|
+
materials: [
|
|
18
|
+
{
|
|
19
|
+
name: 'TransmissionSphere',
|
|
20
|
+
pbrMetallicRoughness: {
|
|
21
|
+
baseColorFactor: [0.76, 0.9, 1, 1],
|
|
22
|
+
metallicFactor: 0,
|
|
23
|
+
roughnessFactor: 0.06,
|
|
24
|
+
},
|
|
25
|
+
extensions: {
|
|
26
|
+
KHR_materials_transmission: { transmissionFactor: 1 },
|
|
27
|
+
KHR_materials_ior: { ior: 1.45 },
|
|
28
|
+
KHR_materials_volume: {
|
|
29
|
+
thicknessFactor: 0.12,
|
|
30
|
+
attenuationColor: [0.9, 0.97, 1],
|
|
31
|
+
attenuationDistance: 3,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const parsed = await parseGltf(source, noopLoader, 'carrier/transmission.gltf');
|
|
39
|
+
expect(parsed.ok).toBe(true);
|
|
40
|
+
if (!parsed.ok) return;
|
|
41
|
+
|
|
42
|
+
const material = parsed.value.materials[0];
|
|
43
|
+
if (material === undefined) throw new Error('transmission carrier did not parse a material');
|
|
44
|
+
expect(material).toMatchObject({
|
|
45
|
+
name: 'TransmissionSphere',
|
|
46
|
+
transmissionFactor: 1,
|
|
47
|
+
ior: 1.45,
|
|
48
|
+
thicknessFactor: 0.12,
|
|
49
|
+
attenuationColor: [0.9, 0.97, 1],
|
|
50
|
+
attenuationDistance: 3,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const pack = toAssetPack(parsed.value, undefined, 'transmission.gltf');
|
|
54
|
+
expect(pack.ok).toBe(true);
|
|
55
|
+
if (!pack.ok) return;
|
|
56
|
+
expect(pack.value.subAssets).toEqual([
|
|
57
|
+
expect.objectContaining({
|
|
58
|
+
kind: 'material',
|
|
59
|
+
name: 'TransmissionSphere',
|
|
60
|
+
sourceKey: 'material:TransmissionSphere',
|
|
61
|
+
}),
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
const bridged = toMaterialAsset(material);
|
|
65
|
+
const pass = bridged.passes?.[0];
|
|
66
|
+
if (pass === undefined) throw new Error('transmission bridge did not emit a Forward pass');
|
|
67
|
+
if (pass.renderState === undefined)
|
|
68
|
+
throw new Error('transmission bridge pass has no render state');
|
|
69
|
+
expect(pass.program.module).toBe('forgeax::default-standard-pbr');
|
|
70
|
+
expect(pass.renderState.queue).toBe(2000);
|
|
71
|
+
expect(bridged.values).toMatchObject({
|
|
72
|
+
baseColor: [0.76, 0.9, 1, 1],
|
|
73
|
+
metallic: 0,
|
|
74
|
+
roughness: 0.06,
|
|
75
|
+
transmission: 1,
|
|
76
|
+
ior: 1.45,
|
|
77
|
+
thickness: 0.12,
|
|
78
|
+
attenuationColor: [0.9, 0.97, 1],
|
|
79
|
+
attenuationDistance: 3,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
package/src/bridge.ts
CHANGED
|
@@ -776,7 +776,9 @@ type MaterialTextureSlot =
|
|
|
776
776
|
| 'metallicRoughnessTexture'
|
|
777
777
|
| 'normalTexture'
|
|
778
778
|
| 'occlusionTexture'
|
|
779
|
-
| 'emissiveTexture'
|
|
779
|
+
| 'emissiveTexture'
|
|
780
|
+
| 'transmissionTexture'
|
|
781
|
+
| 'thicknessTexture';
|
|
780
782
|
|
|
781
783
|
function textureValue(
|
|
782
784
|
info: GltfTextureInfoIr | number | undefined,
|
|
@@ -830,6 +832,8 @@ export function validateMaterialUvSets(
|
|
|
830
832
|
['normalTexture', mat.normalTexture],
|
|
831
833
|
['occlusionTexture', mat.occlusionTexture],
|
|
832
834
|
['emissiveTexture', mat.emissiveTexture],
|
|
835
|
+
['transmissionTexture', mat.transmissionTexture],
|
|
836
|
+
['thicknessTexture', mat.thicknessTexture],
|
|
833
837
|
];
|
|
834
838
|
for (const [slot, rawBinding] of slots) {
|
|
835
839
|
const binding = textureInfo(rawBinding);
|
|
@@ -867,6 +871,8 @@ export function toMaterialAsset(mat: GltfMaterialIr, ctx?: MaterialBridgeContext
|
|
|
867
871
|
['normalTexture', mat.normalTexture],
|
|
868
872
|
['occlusionTexture', mat.occlusionTexture],
|
|
869
873
|
['emissiveTexture', mat.emissiveTexture],
|
|
874
|
+
['transmissionTexture', mat.transmissionTexture],
|
|
875
|
+
['thicknessTexture', mat.thicknessTexture],
|
|
870
876
|
];
|
|
871
877
|
for (const [slot, info] of textureSlots) {
|
|
872
878
|
const value = textureValue(info, slot, ctx);
|
|
@@ -875,6 +881,11 @@ export function toMaterialAsset(mat: GltfMaterialIr, ctx?: MaterialBridgeContext
|
|
|
875
881
|
if (mat.occlusionTexture !== undefined && values.occlusionStrength === undefined) {
|
|
876
882
|
values.occlusionStrength = 1;
|
|
877
883
|
}
|
|
884
|
+
if (mat.transmissionFactor !== undefined) values.transmission = mat.transmissionFactor;
|
|
885
|
+
if (mat.ior !== undefined) values.ior = mat.ior;
|
|
886
|
+
if (mat.thicknessFactor !== undefined) values.thickness = mat.thicknessFactor;
|
|
887
|
+
if (mat.attenuationColor !== undefined) values.attenuationColor = mat.attenuationColor;
|
|
888
|
+
if (mat.attenuationDistance !== undefined) values.attenuationDistance = mat.attenuationDistance;
|
|
878
889
|
|
|
879
890
|
const module = ctx?.skinned === true ? 'forgeax::pbr-skin' : 'forgeax::default-standard-pbr';
|
|
880
891
|
|
package/src/check-extensions.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
// check-extensions.ts - KHR / vendor extension gate.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
// KHR_lights_punctual,
|
|
5
|
-
//
|
|
3
|
+
// Required-extension support contains EXT_mesh_gpu_instancing,
|
|
4
|
+
// EXT_meshopt_compression, KHR_lights_punctual, KHR_texture_transform, and
|
|
5
|
+
// the KHR material transmission/IOR/volume extensions. The exported legacy
|
|
6
|
+
// list remains the original mesh extension list for callers that display the
|
|
7
|
+
// v1 mesh-only surface.
|
|
6
8
|
// (feat-20260518-gltf-instancing-and-name-component plan-strategy section
|
|
7
9
|
// 2 D-1 / D-3). Any extension listed in `extensionsRequired[]` outside
|
|
8
|
-
//
|
|
10
|
+
// the supported extension set triggers `gltf-extension-unsupported` (hard fail).
|
|
9
11
|
// Extensions listed in `extensionsUsed[]` (but not required and not in
|
|
10
|
-
//
|
|
12
|
+
// supported extension set) are recorded in `importSettings.diagnostics
|
|
11
13
|
// .unsupportedExtensions` so AI users can observe them downstream — and
|
|
12
14
|
// nothing else: `extensionsUsed` is purely informational per the glTF spec
|
|
13
15
|
// (only `extensionsRequired` is binding), and exporters routinely
|
|
@@ -16,12 +18,12 @@
|
|
|
16
18
|
// diagnostics list is the single channel (no `console.error`).
|
|
17
19
|
//
|
|
18
20
|
// Future expansion (KHR_materials_unlit, ...) extends
|
|
19
|
-
// `
|
|
21
|
+
// `SUPPORTED_EXTENSIONS` in place; each addition lands under its own feat-*
|
|
20
22
|
// loop with breaking-change registry entry.
|
|
21
23
|
|
|
22
24
|
import { err, type GltfError, gltfErr, ok, type Result } from './errors.js';
|
|
23
25
|
|
|
24
|
-
/**
|
|
26
|
+
/** Legacy v1 mesh-only list kept for callers that display that surface. */
|
|
25
27
|
export const EXTENSION_ALLOWLIST: readonly string[] = [
|
|
26
28
|
'EXT_mesh_gpu_instancing',
|
|
27
29
|
'EXT_meshopt_compression',
|
|
@@ -30,10 +32,13 @@ const SUPPORTED_EXTENSIONS: readonly string[] = [
|
|
|
30
32
|
...EXTENSION_ALLOWLIST,
|
|
31
33
|
'KHR_lights_punctual',
|
|
32
34
|
'KHR_texture_transform',
|
|
35
|
+
'KHR_materials_transmission',
|
|
36
|
+
'KHR_materials_ior',
|
|
37
|
+
'KHR_materials_volume',
|
|
33
38
|
];
|
|
34
39
|
|
|
35
40
|
export interface ExtensionsCheckResult {
|
|
36
|
-
/** Names listed in extensionsUsed but not in the
|
|
41
|
+
/** Names listed in extensionsUsed but not in the supported extension set. */
|
|
37
42
|
readonly unsupportedUsed: readonly string[];
|
|
38
43
|
}
|
|
39
44
|
|
|
@@ -43,7 +48,7 @@ export interface GltfExtensionsJson {
|
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
/**
|
|
46
|
-
* Validate the glTF JSON's extension declarations against the
|
|
51
|
+
* Validate the glTF JSON's extension declarations against the supported set.
|
|
47
52
|
*
|
|
48
53
|
* Returns:
|
|
49
54
|
* - `Result.err(gltf-extension-unsupported)` for the FIRST entry of
|
package/src/errors.ts
CHANGED
|
@@ -60,6 +60,13 @@ export interface GltfExtensionUnsupportedDetail {
|
|
|
60
60
|
readonly source: 'extensionsRequired' | 'extensionsUsed';
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
export interface GltfMaterialTransmissionInvalidDetail {
|
|
64
|
+
readonly extension: 'KHR_materials_transmission' | 'KHR_materials_ior' | 'KHR_materials_volume';
|
|
65
|
+
readonly field: string;
|
|
66
|
+
readonly reason: 'type' | 'range' | 'non-finite' | 'blend';
|
|
67
|
+
readonly actual?: unknown;
|
|
68
|
+
}
|
|
69
|
+
|
|
63
70
|
/** `gltf-accessor-type-mismatch` payload: 4-member closed reason discriminator. */
|
|
64
71
|
export interface GltfAccessorTypeMismatchDetail {
|
|
65
72
|
readonly accessorIndex: number;
|
|
@@ -256,6 +263,10 @@ const gltfErrorPolicy = {
|
|
|
256
263
|
expected: 'extension listed in v1 allowlist (see EXTENSION_ALLOWLIST in @forgeax/engine-gltf)',
|
|
257
264
|
hint: 'see feat-future-gltf-extensions-allowlist; remove this extension or wait for the allowlist to expand',
|
|
258
265
|
},
|
|
266
|
+
'gltf-material-transmission-invalid': {
|
|
267
|
+
expected: 'KHR transmission, IOR, and volume values are finite and within their glTF ranges',
|
|
268
|
+
hint: 'repair the named glTF material extension value and re-import the source',
|
|
269
|
+
},
|
|
259
270
|
'gltf-accessor-type-mismatch': {
|
|
260
271
|
expected: 'dense fixed-stride accessor with supported componentType',
|
|
261
272
|
hint: 'sparse: see feat-future-gltf-sparse-accessor; morph: see feat-future-gltf-morph; interleaved: see feat-future-gltf-mesh-multi-section',
|
|
@@ -364,6 +375,7 @@ interface DetailFor {
|
|
|
364
375
|
readonly 'gltf-color-accessor-unsupported': GltfColorAccessorUnsupportedDetail;
|
|
365
376
|
readonly 'gltf-color-accessor-malformed': GltfColorAccessorMalformedDetail;
|
|
366
377
|
readonly 'gltf-mesh-bridge-invalid': GltfMeshBridgeInvalidDetail;
|
|
378
|
+
readonly 'gltf-material-transmission-invalid': GltfMaterialTransmissionInvalidDetail;
|
|
367
379
|
}
|
|
368
380
|
|
|
369
381
|
/**
|
package/src/gltf-importer.ts
CHANGED
|
@@ -412,6 +412,8 @@ export function materialRefsForPack(
|
|
|
412
412
|
pushRefsForSlot(mat.normalTexture, 'normalTexture');
|
|
413
413
|
pushRefsForSlot(mat.occlusionTexture, 'occlusionTexture');
|
|
414
414
|
pushRefsForSlot(mat.emissiveTexture, 'emissiveTexture');
|
|
415
|
+
pushRefsForSlot(mat.transmissionTexture, 'transmissionTexture');
|
|
416
|
+
pushRefsForSlot(mat.thicknessTexture, 'thicknessTexture');
|
|
415
417
|
return refs;
|
|
416
418
|
}
|
|
417
419
|
|
|
@@ -439,6 +441,8 @@ function rewriteMaterialAssetRefs(
|
|
|
439
441
|
| 'normalTexture'
|
|
440
442
|
| 'occlusionTexture'
|
|
441
443
|
| 'emissiveTexture'
|
|
444
|
+
| 'transmissionTexture'
|
|
445
|
+
| 'thicknessTexture'
|
|
442
446
|
),
|
|
443
447
|
GltfTextureInfoIr | number | undefined,
|
|
444
448
|
][] = [
|
|
@@ -447,6 +451,8 @@ function rewriteMaterialAssetRefs(
|
|
|
447
451
|
['normalTexture', mat.normalTexture],
|
|
448
452
|
['occlusionTexture', mat.occlusionTexture],
|
|
449
453
|
['emissiveTexture', mat.emissiveTexture],
|
|
454
|
+
['transmissionTexture', mat.transmissionTexture],
|
|
455
|
+
['thicknessTexture', mat.thicknessTexture],
|
|
450
456
|
];
|
|
451
457
|
let cursor = 0;
|
|
452
458
|
for (const [slot, rawBinding] of slots) {
|
package/src/index.ts
CHANGED