@forgeax/engine-gltf 0.1.23 → 0.1.25
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 +56 -3
- package/dist/__tests__/physical-clearcoat.unit.test.d.ts +2 -0
- package/dist/__tests__/physical-clearcoat.unit.test.d.ts.map +1 -0
- package/dist/__tests__/physical-material-import.integration.test.d.ts +2 -0
- package/dist/__tests__/physical-material-import.integration.test.d.ts.map +1 -0
- package/dist/bridge.d.ts +1 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/check-extensions.d.ts +1 -1
- package/dist/check-extensions.d.ts.map +1 -1
- package/dist/cli-gltf.mjs +181 -8
- 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/image-color-space.d.ts +12 -0
- package/dist/image-color-space.d.ts.map +1 -1
- package/dist/importer-entry.mjs +377 -26
- package/dist/importer-entry.mjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +378 -27
- package/dist/index.mjs.map +1 -1
- package/dist/material/parse-material.d.ts +66 -0
- package/dist/material/parse-material.d.ts.map +1 -1
- package/dist/node-file-entry.mjs +181 -8
- package/dist/node-file-entry.mjs.map +1 -1
- package/package.json +12 -12
- package/src/__tests__/bridge-material-values.unit.test.ts +107 -1
- package/src/__tests__/bridge-skin-stride.unit.test.ts +22 -0
- package/src/__tests__/gltf-error-derived-views.test-d.ts +4 -0
- package/src/__tests__/gltf-error-migration.test.ts +3 -3
- package/src/__tests__/gltf.unit.test.ts +61 -6
- package/src/__tests__/material-pack-refs.integration.test.ts +53 -0
- package/src/__tests__/parse-gltf.unit.test.ts +29 -1
- package/src/__tests__/physical-clearcoat.unit.test.ts +110 -0
- package/src/__tests__/physical-material-import.integration.test.ts +239 -0
- package/src/bridge.ts +260 -15
- package/src/check-extensions.ts +16 -10
- package/src/errors.ts +21 -2
- package/src/gltf-importer.ts +35 -0
- package/src/image-color-space.ts +29 -4
- package/src/index.ts +8 -1
- package/src/material/parse-material.ts +307 -0
package/README.md
CHANGED
|
@@ -21,6 +21,36 @@ the render phase. The carrier validates the source, Pack, GUID load, and rendere
|
|
|
21
21
|
|
|
22
22
|
If a source requests a UV set that the primitive does not provide, handle `gltf-material-uv-set-missing` using its material, primitive, slot, requested set, and available sets. Add the source UV set and re-import; do not substitute a custom mesh or discard the slot transform.
|
|
23
23
|
|
|
24
|
+
### KHR physical material extensions
|
|
25
|
+
|
|
26
|
+
The importer accepts the five second-stage material extensions below in both
|
|
27
|
+
`extensionsUsed` and `extensionsRequired`. A required extension outside the
|
|
28
|
+
supported set fails closed with `gltf-extension-unsupported`; a supported
|
|
29
|
+
extension is projected into the same Standard `MaterialAsset` root rather than
|
|
30
|
+
an extension-specific runtime type.
|
|
31
|
+
|
|
32
|
+
| Extension | Standard values / slots | Channel and color-space rule | Admission / recovery |
|
|
33
|
+
|:--|:--|:--|:--|
|
|
34
|
+
| `KHR_materials_clearcoat` | `clearcoat`, `clearcoatRoughness`, `clearcoatTexture`, `clearcoatRoughnessTexture`, `clearcoatNormalTexture`, `clearcoatNormalScale` | weight R, roughness G, coat normal RG; data textures are linear | coat normal uses the mesh tangent producer |
|
|
35
|
+
| `KHR_materials_anisotropy` | `anisotropyStrength`, `anisotropyRotation`, `anisotropyTexture` | direction RG, strength B; linear data | scalar and mapped forms both require a tangent frame |
|
|
36
|
+
| `KHR_materials_sheen` | `sheenColor`, `sheenRoughness`, `sheenColorTexture`, `sheenRoughnessTexture` | color RGB is sRGB; roughness A is linear | preserve each slot's UV transform; repair `gltf-material-uv-set-missing` on conflict |
|
|
37
|
+
| `KHR_materials_iridescence` | `iridescence`, `iridescenceIor`, `iridescenceThicknessMinimum/Maximum`, `iridescenceTexture`, `iridescenceThicknessTexture` | strength R and thickness G; both maps are linear | minimum greater than maximum is accepted per glTF semantics |
|
|
38
|
+
| `KHR_materials_specular` | `specular`, `specularTexture`, `specularColor`, `specularColorTexture` | weight A is linear; color RGB is sRGB | texture declarations select the physical Forward contract |
|
|
39
|
+
|
|
40
|
+
All five paths preserve `textureInfo.texCoord` and
|
|
41
|
+
`KHR_texture_transform` into `MaterialTextureValue.coordinates`. A material
|
|
42
|
+
with any of these declarations owns an extended Standard root, so its scalar
|
|
43
|
+
defaults and only its authored physical texture bindings participate in cook,
|
|
44
|
+
reflection, Pack refs, Catalog/load, and runtime sampling.
|
|
45
|
+
|
|
46
|
+
> [!IMPORTANT]
|
|
47
|
+
> `KHR_materials_anisotropy` always needs a finite tangent frame, even when
|
|
48
|
+
> only `anisotropyStrength` or `anisotropyRotation` is authored. If `TANGENT`
|
|
49
|
+
> is absent, the producer may generate it from `NORMAL + TEXCOORD_n + triangle
|
|
50
|
+
> topology`; if those inputs are missing or degenerate, import returns the
|
|
51
|
+
> structured `material-tangent-required` error. The importer persists generated
|
|
52
|
+
> tangents in `MeshAsset.attributes.tangent` and never writes an identity guess.
|
|
53
|
+
|
|
24
54
|
> Runtime glTF 2.0 importer (Tier-C subset). Pure-function pipeline `parseGlb` / `parseGltf` / `toAssetPack` consumed by build-time CLI plugin bin `forgeax-engine-remote-gltf` (resolved via PATH-prefix scan for `forgeax-engine-remote-`) writing `<source>.meta.json` (external-asset-package; dispatch on top-level `importer: 'gltf'`); runtime spawn happens via the existing `loadByGuid<SceneAsset>` plus `world.instantiateScene` 4-step recipe (no `loadGltf(url)` parallel API).
|
|
25
55
|
|
|
26
56
|
> [!IMPORTANT]
|
|
@@ -39,7 +69,7 @@ This package consumes:
|
|
|
39
69
|
- `scenes` + `nodes` (TRS or matrix decomposed via `mat4.decompose` wrapper)
|
|
40
70
|
- `meshes` with **multiple primitives** -- each primitive produces an independent `MeshIr` with UUIDv7 GUID; `SceneAsset` nodes reference individual primitive-level mesh sub-assets
|
|
41
71
|
- Vertex attributes: `POSITION` (VEC3, mandatory), `NORMAL` (VEC3), `TEXCOORD_0` (VEC2), `TANGENT` (VEC4, optional), and `COLOR_0` (see the support matrix below) -- decoded via the accessor SoA path; `INDICES` (U8/U16/U32 scalar — U8 widens to U16; U32 preserved, narrowed to U16 by bridge when maxIndex < 65536)
|
|
42
|
-
- `materials` with metallic-roughness
|
|
72
|
+
- `materials` with metallic-roughness and five KHR physical extensions mapped to pass-based `MaterialAsset` (see MaterialIr table below)
|
|
43
73
|
- `textures` / `images` / `samplers` top-level arrays parsed into `GltfDoc` IR; texture index -> image index -> URI two-hop resolution via `externalLoader`
|
|
44
74
|
- `cameras` of `type: 'perspective'`
|
|
45
75
|
|
|
@@ -102,6 +132,21 @@ The complete closed error/detail union remains owned by
|
|
|
102
132
|
| `metallicRoughnessTexture` | `number` (texture index) | no | Same two-hop resolution |
|
|
103
133
|
| `normalTexture` | `number` (texture index) | no | Same two-hop resolution; TANGENT optional decode |
|
|
104
134
|
|
|
135
|
+
The physical extension fields are projected into the same IR object:
|
|
136
|
+
|
|
137
|
+
| Extension | Scalar fields | Texture fields |
|
|
138
|
+
|:--|:--|:--|
|
|
139
|
+
| `KHR_materials_clearcoat` | `clearcoatFactor`, `clearcoatRoughnessFactor` | `clearcoatTexture`, `clearcoatRoughnessTexture`, `clearcoatNormalTexture` |
|
|
140
|
+
| `KHR_materials_anisotropy` | `anisotropyStrength`, `anisotropyRotation` | `anisotropyTexture` |
|
|
141
|
+
| `KHR_materials_sheen` | `sheenColorFactor`, `sheenRoughnessFactor` | `sheenColorTexture`, `sheenRoughnessTexture` |
|
|
142
|
+
| `KHR_materials_iridescence` | `iridescenceFactor`, `iridescenceIor`, `iridescenceThicknessMinimum/Maximum` | `iridescenceTexture`, `iridescenceThicknessTexture` |
|
|
143
|
+
| `KHR_materials_specular` | `specularFactor`, `specularColorFactor` | `specularTexture`, `specularColorTexture` |
|
|
144
|
+
|
|
145
|
+
Each texture field is a `GltfTextureInfoIr | number` with an explicit texture
|
|
146
|
+
index and optional UV/transform facts. The bridge creates a complete extended
|
|
147
|
+
root for the declarations it sees; base-only materials may still inherit the
|
|
148
|
+
configured `standardMaterialGuid`.
|
|
149
|
+
|
|
105
150
|
### GltfDoc IR (textures / images / samplers)
|
|
106
151
|
|
|
107
152
|
| Array | Element | Notes |
|
|
@@ -119,7 +164,7 @@ only its slot index. Canonical `SceneAsset` nodes carry `MeshFilter` plus an
|
|
|
119
164
|
empty `MeshRenderer.materials` override vector, so imported defaults remain
|
|
120
165
|
mesh-owned and reimport-safe.
|
|
121
166
|
|
|
122
|
-
Out of scope (each routed to its own `feat-future-*` anchor in `requirements.md` OOS-1 .. OOS-15): KHR extensions other than the supported
|
|
167
|
+
Out of scope (each routed to its own `feat-future-*` anchor in `requirements.md` OOS-1 .. OOS-15): KHR material extensions other than the supported transmission/IOR/volume, clearcoat, anisotropy, sheen, iridescence, and specular paths / morph targets other than the explicit `COLOR_0` deferred signal / orthographic camera / sparse accessors / inspector future fields / pixel-parity vs three.js. Dense interleaved `COLOR_0` is supported; other interleaved accessor consumers retain their existing scope. v1.1 OOS additions (locked by feat-20260518-gltf-instancing-and-name-component): multi-primitive instancing / mesh-level + material-level + scene-level Name (only node.name lands as ECS `Name`) / instancing hard cap / SoA TRS direct-to-GPU pipe / IR-to-GPU direct path / ROTATION BYTE/SHORT normalized encoding / Babylon thin-instances style SoA channel / Bevy multi-tier Name propagation.
|
|
123
168
|
|
|
124
169
|
## Importer sub-asset PODs (7 kinds)
|
|
125
170
|
|
|
@@ -150,7 +195,7 @@ Sample reference: `apps/hello/skin` -- 3 Khronos Fox foxes side-by-side, each ru
|
|
|
150
195
|
| `gltf-malformed-header` | GLB magic / version / length header rejection or missing JSON chunk |
|
|
151
196
|
| `gltf-version-unsupported` | `asset.version` is not `'2.0'` |
|
|
152
197
|
| `gltf-buffer-out-of-bounds` | accessor reads past `bufferView.byteLength` |
|
|
153
|
-
| `gltf-extension-unsupported` | `extensionsRequired[]` lists an extension outside the supported allowlist (`EXT_mesh_gpu_instancing`, `KHR_texture_transform
|
|
198
|
+
| `gltf-extension-unsupported` | `extensionsRequired[]` lists an extension outside the supported allowlist exported as `EXTENSION_ALLOWLIST` (`EXT_mesh_gpu_instancing`, `EXT_meshopt_compression`, `KHR_lights_punctual`, `KHR_texture_transform`, transmission/IOR/volume, clearcoat, anisotropy, sheen, iridescence, specular) |
|
|
154
199
|
| `gltf-accessor-type-mismatch` | sparse / morph / interleaved / unknown componentType accessor (4 reasons) |
|
|
155
200
|
| `gltf-texture-load-failed` | `externalLoader` rejected for a texture `uri`; `detail.uri` carries the failing URI; hint: `'check sidecar meta.json + textures/ directory + vite-plugin-pack /__pack/lookup'` |
|
|
156
201
|
| `gltf-meta-missing` | sidecar `<source>.meta.json` is absent next to the `.gltf` / `.glb` source file |
|
|
@@ -162,6 +207,14 @@ Sample reference: `apps/hello/skin` -- 3 Khronos Fox foxes side-by-side, each ru
|
|
|
162
207
|
| `gltf-morph-unsupported` | animation channel targets morph weights (`path==='weights'`, OOS-skin-morph-anim) |
|
|
163
208
|
| `gltf-color-accessor-unsupported` | `COLOR_0` type/component/normalized combination, sparse input, or morph-target input is deferred |
|
|
164
209
|
| `gltf-color-accessor-malformed` | `COLOR_0` count, finite/range, buffer bounds, or reference validation failed |
|
|
210
|
+
| `gltf-material-physical-invalid` | a clearcoat/anisotropy/sheen/iridescence/specular scalar or color violates its finite glTF range |
|
|
211
|
+
|
|
212
|
+
Mesh tangent admission is a material error because the geometry producer owns
|
|
213
|
+
the repairable frame. Branch on `material-tangent-required` and read its
|
|
214
|
+
`detail.material`, `detail.mesh`, `detail.layer`, `detail.uv`,
|
|
215
|
+
`detail.attributes`, and `detail.reason`; fix the source attributes and rerun
|
|
216
|
+
the same importer. Do not parse the human-facing message or silently continue
|
|
217
|
+
with an identity tangent.
|
|
165
218
|
|
|
166
219
|
Source-key conflicts are producer failures, not automatic renames. A
|
|
167
220
|
`duplicate-source-key` or `ambiguous-source-key` detail includes the semantic
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"physical-clearcoat.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/physical-clearcoat.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"physical-material-import.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/physical-material-import.integration.test.ts"],"names":[],"mappings":""}
|
package/dist/bridge.d.ts
CHANGED
|
@@ -98,6 +98,7 @@ export interface MaterialBridgeContext {
|
|
|
98
98
|
readonly skinned?: boolean;
|
|
99
99
|
}
|
|
100
100
|
export declare function validateMaterialUvSets(mat: GltfMaterialIr, primitive: string, availableSets: readonly number[]): Result<void, MaterialError>;
|
|
101
|
+
export declare function validateMaterialTangentInputs(mat: GltfMaterialIr, mesh: GltfMeshIr, layer?: string): Result<void, MaterialError>;
|
|
101
102
|
/** Convert a parsed GltfMaterialIr into a standard-root derived MaterialAsset. */
|
|
102
103
|
export declare function toMaterialAsset(mat: GltfMaterialIr, ctx?: MaterialBridgeContext): MaterialAsset;
|
|
103
104
|
//# sourceMappingURL=bridge.d.ts.map
|
package/dist/bridge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,SAAS,EACT,MAAM,EAEN,aAAa,EACb,aAAa,EAEb,SAAS,EAIT,MAAM,EACN,UAAU,EAIX,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,SAAS,EACT,MAAM,EAEN,aAAa,EACb,aAAa,EAEb,SAAS,EAIT,MAAM,EACN,UAAU,EAIX,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,EAA4B,KAAK,SAAS,EAAe,MAAM,aAAa,CAAC;AACpF,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,UAAU,EACV,UAAU,EAGX,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,SAAS,GAAE;IACT,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpD,GACL,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CA0V9B;AAED,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;IACzE,4DAA4D;IAC5D,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjF;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChE;AA+DD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB,GAAG,UAAU,CA8NpF;AAED,uFAAuF;AACvF,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC;AAEtC,MAAM,WAAW,qBAAqB;IACpC,0DAA0D;IAC1D,QAAQ,CAAC,cAAc,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChF,0DAA0D;IAC1D,QAAQ,CAAC,cAAc,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChF,8EAA8E;IAC9E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IACtC;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAuKD,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAsC7B;AAED,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,UAAU,EAChB,KAAK,SAAc,GAClB,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAoD7B;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,qBAAqB,GAAG,aAAa,CA2H/F"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type GltfError, type Result } from './errors.js';
|
|
2
|
-
/**
|
|
2
|
+
/** Public supported extension list used by the required/used declaration gate. */
|
|
3
3
|
export declare const EXTENSION_ALLOWLIST: readonly string[];
|
|
4
4
|
export interface ExtensionsCheckResult {
|
|
5
5
|
/** Names listed in extensionsUsed but not in the supported extension set. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-extensions.d.ts","sourceRoot":"","sources":["../src/check-extensions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"check-extensions.d.ts","sourceRoot":"","sources":["../src/check-extensions.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAO,KAAK,SAAS,EAAe,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAE5E,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAahD,CAAC;AAOF,MAAM,WAAW,qBAAqB;IACpC,6EAA6E;IAC7E,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,kBAAkB,GACvB,MAAM,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAsB1C"}
|
package/dist/cli-gltf.mjs
CHANGED
|
@@ -25,8 +25,8 @@ var gltfErrorPolicy = {
|
|
|
25
25
|
hint: "rebuild .gltf with valid bufferViews; check accessor index; ensure accessor.byteOffset + EFFECTIVE_STRIDE * (count - 1) + element_size <= bufferView.byteLength"
|
|
26
26
|
},
|
|
27
27
|
"gltf-extension-unsupported": {
|
|
28
|
-
expected: "extension listed in
|
|
29
|
-
hint: "
|
|
28
|
+
expected: "extension listed in the supported allowlist (see EXTENSION_ALLOWLIST in @forgeax/engine-gltf)",
|
|
29
|
+
hint: "remove the unsupported required extension or use a supported glTF extension; extensionsUsed-only entries remain diagnostic"
|
|
30
30
|
},
|
|
31
31
|
"gltf-lod-invalid": {
|
|
32
32
|
expected: "MSFT_lod ids to reference unique existing node indices with valid coverage",
|
|
@@ -36,6 +36,10 @@ var gltfErrorPolicy = {
|
|
|
36
36
|
expected: "KHR transmission, IOR, and volume values are finite and within their glTF ranges",
|
|
37
37
|
hint: "repair the named glTF material extension value and re-import the source"
|
|
38
38
|
},
|
|
39
|
+
"gltf-material-physical-invalid": {
|
|
40
|
+
expected: "KHR clearcoat, anisotropy, sheen, iridescence, and specular values are finite and within their glTF ranges",
|
|
41
|
+
hint: "repair the named physical material extension value and re-import the source"
|
|
42
|
+
},
|
|
39
43
|
"gltf-accessor-type-mismatch": {
|
|
40
44
|
expected: "dense fixed-stride accessor with supported componentType",
|
|
41
45
|
hint: "sparse: see feat-future-gltf-sparse-accessor; morph: see feat-future-gltf-morph; interleaved: see feat-future-gltf-mesh-multi-section"
|
|
@@ -400,16 +404,21 @@ function decodeColorAccessor(input, flags = {}) {
|
|
|
400
404
|
var EXTENSION_ALLOWLIST = [
|
|
401
405
|
"EXT_mesh_gpu_instancing",
|
|
402
406
|
"EXT_meshopt_compression",
|
|
403
|
-
"MSFT_lod",
|
|
404
|
-
"MSFT_screencoverage"
|
|
405
|
-
];
|
|
406
|
-
var SUPPORTED_EXTENSIONS = [
|
|
407
|
-
...EXTENSION_ALLOWLIST,
|
|
408
407
|
"KHR_lights_punctual",
|
|
409
408
|
"KHR_texture_transform",
|
|
410
409
|
"KHR_materials_transmission",
|
|
411
410
|
"KHR_materials_ior",
|
|
412
|
-
"KHR_materials_volume"
|
|
411
|
+
"KHR_materials_volume",
|
|
412
|
+
"KHR_materials_clearcoat",
|
|
413
|
+
"KHR_materials_anisotropy",
|
|
414
|
+
"KHR_materials_sheen",
|
|
415
|
+
"KHR_materials_iridescence",
|
|
416
|
+
"KHR_materials_specular"
|
|
417
|
+
];
|
|
418
|
+
var SUPPORTED_EXTENSIONS = [
|
|
419
|
+
...EXTENSION_ALLOWLIST,
|
|
420
|
+
"MSFT_lod",
|
|
421
|
+
"MSFT_screencoverage"
|
|
413
422
|
];
|
|
414
423
|
function checkExtensions(json) {
|
|
415
424
|
const required = json.extensionsRequired ?? [];
|
|
@@ -602,6 +611,11 @@ function parseMaterial(matJson, textures) {
|
|
|
602
611
|
const transmission = matJson.extensions?.KHR_materials_transmission;
|
|
603
612
|
const ior = matJson.extensions?.KHR_materials_ior;
|
|
604
613
|
const volume = matJson.extensions?.KHR_materials_volume;
|
|
614
|
+
const clearcoat = matJson.extensions?.KHR_materials_clearcoat;
|
|
615
|
+
const anisotropy = matJson.extensions?.KHR_materials_anisotropy;
|
|
616
|
+
const sheen = matJson.extensions?.KHR_materials_sheen;
|
|
617
|
+
const iridescence = matJson.extensions?.KHR_materials_iridescence;
|
|
618
|
+
const specular = matJson.extensions?.KHR_materials_specular;
|
|
605
619
|
const attenuationColor = tuple3(volume?.attenuationColor);
|
|
606
620
|
const invalid = (extension, field, reason, actual) => err(
|
|
607
621
|
gltfErr("gltf-material-transmission-invalid", {
|
|
@@ -611,6 +625,14 @@ function parseMaterial(matJson, textures) {
|
|
|
611
625
|
...actual === void 0 ? {} : { actual }
|
|
612
626
|
})
|
|
613
627
|
);
|
|
628
|
+
const physicalInvalid = (extension, field, reason, actual) => err(
|
|
629
|
+
gltfErr("gltf-material-physical-invalid", {
|
|
630
|
+
extension,
|
|
631
|
+
field,
|
|
632
|
+
reason,
|
|
633
|
+
...actual === void 0 ? {} : { actual }
|
|
634
|
+
})
|
|
635
|
+
);
|
|
614
636
|
if (transmission?.transmissionFactor !== void 0 && (typeof transmission.transmissionFactor !== "number" || !Number.isFinite(transmission.transmissionFactor))) {
|
|
615
637
|
return invalid(
|
|
616
638
|
"KHR_materials_transmission",
|
|
@@ -661,6 +683,98 @@ function parseMaterial(matJson, textures) {
|
|
|
661
683
|
if (alphaMode === "BLEND" && (transmission?.transmissionFactor ?? 0) > 0) {
|
|
662
684
|
return invalid("KHR_materials_transmission", "alphaMode", "blend", alphaMode);
|
|
663
685
|
}
|
|
686
|
+
if (clearcoat?.clearcoatFactor !== void 0 && (typeof clearcoat.clearcoatFactor !== "number" || !Number.isFinite(clearcoat.clearcoatFactor))) {
|
|
687
|
+
return physicalInvalid(
|
|
688
|
+
"KHR_materials_clearcoat",
|
|
689
|
+
"clearcoatFactor",
|
|
690
|
+
"non-finite",
|
|
691
|
+
clearcoat.clearcoatFactor
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
if (clearcoat?.clearcoatFactor !== void 0 && (clearcoat.clearcoatFactor < 0 || clearcoat.clearcoatFactor > 1)) {
|
|
695
|
+
return physicalInvalid(
|
|
696
|
+
"KHR_materials_clearcoat",
|
|
697
|
+
"clearcoatFactor",
|
|
698
|
+
"range",
|
|
699
|
+
clearcoat.clearcoatFactor
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
if (clearcoat?.clearcoatRoughnessFactor !== void 0 && (typeof clearcoat.clearcoatRoughnessFactor !== "number" || !Number.isFinite(clearcoat.clearcoatRoughnessFactor))) {
|
|
703
|
+
return physicalInvalid(
|
|
704
|
+
"KHR_materials_clearcoat",
|
|
705
|
+
"clearcoatRoughnessFactor",
|
|
706
|
+
"non-finite",
|
|
707
|
+
clearcoat.clearcoatRoughnessFactor
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
if (clearcoat?.clearcoatRoughnessFactor !== void 0 && (clearcoat.clearcoatRoughnessFactor < 0 || clearcoat.clearcoatRoughnessFactor > 1)) {
|
|
711
|
+
return physicalInvalid(
|
|
712
|
+
"KHR_materials_clearcoat",
|
|
713
|
+
"clearcoatRoughnessFactor",
|
|
714
|
+
"range",
|
|
715
|
+
clearcoat.clearcoatRoughnessFactor
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
if (clearcoat?.clearcoatNormalTexture?.scale !== void 0 && (typeof clearcoat.clearcoatNormalTexture.scale !== "number" || !Number.isFinite(clearcoat.clearcoatNormalTexture.scale) || clearcoat.clearcoatNormalTexture.scale < 0)) {
|
|
719
|
+
return physicalInvalid(
|
|
720
|
+
"KHR_materials_clearcoat",
|
|
721
|
+
"clearcoatNormalTexture.scale",
|
|
722
|
+
"range",
|
|
723
|
+
clearcoat.clearcoatNormalTexture.scale
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
const validateUnit = (extension, field, value) => {
|
|
727
|
+
if (value === void 0) return void 0;
|
|
728
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
729
|
+
return physicalInvalid(extension, field, "non-finite", value);
|
|
730
|
+
if (value < 0 || value > 1) return physicalInvalid(extension, field, "range", value);
|
|
731
|
+
return void 0;
|
|
732
|
+
};
|
|
733
|
+
const validateFinite = (extension, field, value, minimum) => {
|
|
734
|
+
if (value === void 0) return void 0;
|
|
735
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
736
|
+
return physicalInvalid(extension, field, "non-finite", value);
|
|
737
|
+
if (minimum !== void 0 && value < minimum)
|
|
738
|
+
return physicalInvalid(extension, field, "range", value);
|
|
739
|
+
return void 0;
|
|
740
|
+
};
|
|
741
|
+
const validateColor = (extension, field, value) => {
|
|
742
|
+
if (value === void 0) return void 0;
|
|
743
|
+
if (value.length < 3 || value.slice(0, 3).some((channel) => typeof channel !== "number" || !Number.isFinite(channel))) {
|
|
744
|
+
return physicalInvalid(extension, field, "type", value);
|
|
745
|
+
}
|
|
746
|
+
if (value.slice(0, 3).some((channel) => channel < 0 || channel > 1)) {
|
|
747
|
+
return physicalInvalid(extension, field, "range", value);
|
|
748
|
+
}
|
|
749
|
+
return void 0;
|
|
750
|
+
};
|
|
751
|
+
const physicalChecks = [
|
|
752
|
+
validateUnit("KHR_materials_anisotropy", "anisotropyStrength", anisotropy?.anisotropyStrength),
|
|
753
|
+
validateFinite(
|
|
754
|
+
"KHR_materials_anisotropy",
|
|
755
|
+
"anisotropyRotation",
|
|
756
|
+
anisotropy?.anisotropyRotation
|
|
757
|
+
),
|
|
758
|
+
validateUnit("KHR_materials_sheen", "sheenRoughnessFactor", sheen?.sheenRoughnessFactor),
|
|
759
|
+
validateColor("KHR_materials_sheen", "sheenColorFactor", sheen?.sheenColorFactor),
|
|
760
|
+
validateUnit("KHR_materials_iridescence", "iridescenceFactor", iridescence?.iridescenceFactor),
|
|
761
|
+
validateFinite("KHR_materials_iridescence", "iridescenceIor", iridescence?.iridescenceIor, 1),
|
|
762
|
+
validateFinite(
|
|
763
|
+
"KHR_materials_iridescence",
|
|
764
|
+
"iridescenceThicknessMinimum",
|
|
765
|
+
iridescence?.iridescenceThicknessMinimum,
|
|
766
|
+
0
|
|
767
|
+
),
|
|
768
|
+
validateFinite(
|
|
769
|
+
"KHR_materials_iridescence",
|
|
770
|
+
"iridescenceThicknessMaximum",
|
|
771
|
+
iridescence?.iridescenceThicknessMaximum,
|
|
772
|
+
0
|
|
773
|
+
),
|
|
774
|
+
validateUnit("KHR_materials_specular", "specularFactor", specular?.specularFactor),
|
|
775
|
+
validateColor("KHR_materials_specular", "specularColorFactor", specular?.specularColorFactor)
|
|
776
|
+
];
|
|
777
|
+
for (const check of physicalChecks) if (check !== void 0) return check;
|
|
664
778
|
return ok({
|
|
665
779
|
...matJson.name === void 0 ? {} : { name: matJson.name },
|
|
666
780
|
baseColorFactor: baseColor4,
|
|
@@ -697,6 +811,65 @@ function parseMaterial(matJson, textures) {
|
|
|
697
811
|
...attenuationColor === void 0 ? {} : { attenuationColor },
|
|
698
812
|
...finiteOrUndefined(volume.attenuationDistance) === void 0 ? {} : { attenuationDistance: volume.attenuationDistance }
|
|
699
813
|
},
|
|
814
|
+
...clearcoat === void 0 ? {} : {
|
|
815
|
+
clearcoatFactor: clearcoat.clearcoatFactor ?? 0,
|
|
816
|
+
clearcoatChannel: 0,
|
|
817
|
+
clearcoatRoughnessFactor: clearcoat.clearcoatRoughnessFactor ?? 0,
|
|
818
|
+
clearcoatRoughnessChannel: 1,
|
|
819
|
+
clearcoatNormalChannel: [0, 1],
|
|
820
|
+
...clearcoat.clearcoatTexture === void 0 ? {} : { clearcoatTexture: parseTextureInfo(clearcoat.clearcoatTexture, textures) },
|
|
821
|
+
...clearcoat.clearcoatRoughnessTexture === void 0 ? {} : {
|
|
822
|
+
clearcoatRoughnessTexture: parseTextureInfo(
|
|
823
|
+
clearcoat.clearcoatRoughnessTexture,
|
|
824
|
+
textures
|
|
825
|
+
)
|
|
826
|
+
},
|
|
827
|
+
...clearcoat.clearcoatNormalTexture === void 0 ? {} : {
|
|
828
|
+
clearcoatNormalTexture: {
|
|
829
|
+
...parseTextureInfo(clearcoat.clearcoatNormalTexture, textures),
|
|
830
|
+
...clearcoat.clearcoatNormalTexture.scale === void 0 ? {} : { scale: clearcoat.clearcoatNormalTexture.scale }
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
},
|
|
834
|
+
...anisotropy === void 0 ? {} : {
|
|
835
|
+
anisotropyStrength: anisotropy.anisotropyStrength ?? 0,
|
|
836
|
+
anisotropyRotation: anisotropy.anisotropyRotation ?? 0,
|
|
837
|
+
anisotropyChannel: [0, 1, 2],
|
|
838
|
+
...anisotropy.anisotropyTexture === void 0 ? {} : { anisotropyTexture: parseTextureInfo(anisotropy.anisotropyTexture, textures) }
|
|
839
|
+
},
|
|
840
|
+
...sheen === void 0 ? {} : {
|
|
841
|
+
sheenColorFactor: tuple3(sheen.sheenColorFactor) ?? [0, 0, 0],
|
|
842
|
+
sheenColorChannel: [0, 1, 2],
|
|
843
|
+
sheenRoughnessFactor: sheen.sheenRoughnessFactor ?? 0,
|
|
844
|
+
sheenRoughnessChannel: 3,
|
|
845
|
+
...sheen.sheenColorTexture === void 0 ? {} : { sheenColorTexture: parseTextureInfo(sheen.sheenColorTexture, textures) },
|
|
846
|
+
...sheen.sheenRoughnessTexture === void 0 ? {} : { sheenRoughnessTexture: parseTextureInfo(sheen.sheenRoughnessTexture, textures) }
|
|
847
|
+
},
|
|
848
|
+
...iridescence === void 0 ? {} : {
|
|
849
|
+
iridescenceFactor: iridescence.iridescenceFactor ?? 0,
|
|
850
|
+
iridescenceIor: iridescence.iridescenceIor ?? 1.3,
|
|
851
|
+
iridescenceThicknessMinimum: iridescence.iridescenceThicknessMinimum ?? 100,
|
|
852
|
+
iridescenceThicknessMaximum: iridescence.iridescenceThicknessMaximum ?? 400,
|
|
853
|
+
iridescenceChannel: 0,
|
|
854
|
+
iridescenceThicknessChannel: 1,
|
|
855
|
+
...iridescence.iridescenceTexture === void 0 ? {} : { iridescenceTexture: parseTextureInfo(iridescence.iridescenceTexture, textures) },
|
|
856
|
+
...iridescence.iridescenceThicknessTexture === void 0 ? {} : {
|
|
857
|
+
iridescenceThicknessTexture: parseTextureInfo(
|
|
858
|
+
iridescence.iridescenceThicknessTexture,
|
|
859
|
+
textures
|
|
860
|
+
)
|
|
861
|
+
}
|
|
862
|
+
},
|
|
863
|
+
...specular === void 0 ? {} : {
|
|
864
|
+
specularFactor: specular.specularFactor ?? 1,
|
|
865
|
+
specularChannel: 3,
|
|
866
|
+
specularColorFactor: tuple3(specular.specularColorFactor) ?? [1, 1, 1],
|
|
867
|
+
specularColorChannel: [0, 1, 2],
|
|
868
|
+
...specular.specularTexture === void 0 ? {} : { specularTexture: parseTextureInfo(specular.specularTexture, textures) },
|
|
869
|
+
...specular.specularColorTexture === void 0 ? {} : {
|
|
870
|
+
specularColorTexture: parseTextureInfo(specular.specularColorTexture, textures)
|
|
871
|
+
}
|
|
872
|
+
},
|
|
700
873
|
...alphaMode === void 0 ? {} : { alphaMode },
|
|
701
874
|
...alphaCutoff === void 0 ? {} : { alphaCutoff },
|
|
702
875
|
...matJson.doubleSided === true ? { doubleSided: true } : {},
|