diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f772986..a921d234 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +# Changelog + +## 2.0.0-dev.3.8 + +### New Features + +* Added support for `KHR_materials_iridescence` extension. Added: + * `KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_INVALID` error; + * `KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_WITHOUT_TEXTURE` info; + * `KHR_MATERIALS_IRIDESCENCE_THICKNESS_TEXTURE_UNUSED` info. + +* Added `KHR_MATERIALS_VOLUME_DOUBLE_SIDED` warning. + +* Added new vendor prefixes. + +### Bugfixes + +* Fixed inconsistent handling of meshes with morphed and non-morphed primitives. + ## 2.0.0-dev.3.7 ### New Features @@ -142,17 +161,17 @@ ### Integration updates - * npm tool no longer re-defines `require` (#139). +* npm tool no longer re-defines `require` (#139). - * npm tool no longer requires `options.externalResourceFunction` for GLB or assets with embedded data (#138). +* npm tool no longer requires `options.externalResourceFunction` for GLB or assets with embedded data (#138). - * `options.validateAccessorData` npm tool flag is removed, accessors' data validation is always enabled. +* `options.validateAccessorData` npm tool flag is removed, accessors' data validation is always enabled. - * npm tool now reports `IO_ERROR` for external resources when `options.externalResourceFunction` is not provided. +* npm tool now reports `IO_ERROR` for external resources when `options.externalResourceFunction` is not provided. - * CLI tool now supports `--stdout` flag for writing a single validation report to STDOUT instead of a new file. +* CLI tool now supports `--stdout` flag for writing a single validation report to STDOUT instead of a new file. - * CLI tool validates binary data by default (#138). +* CLI tool validates binary data by default (#138). ## 2.0.0-dev.3.2 @@ -198,15 +217,15 @@ * Added support for `KHR_mesh_quantization` extension. -* Added `NON_REQUIRED_EXTENSION` error for extensions that cannot be optional (such as `KHR_quantized_geometry`). - +* Added `NON_REQUIRED_EXTENSION` error for extensions that cannot be optional (such as `KHR_quantized_geometry`). + * Added vendor prefixes: `MESHOPT`, `POLUTROPON`, and `AGT` (#119). * Added vendor prefixes: `ALCM` and `SKYLINE`. * Added vendor prefixes: `FOXIT`, `KDAB`, and `CAPTURE`. -* Extension names are now validated to have an upper-case prefix separated from the rest on the name with underscore (new `INVALID_EXTENSION_NAME_FORMAT` warning). +* Extension names are now validated to have an upper-case prefix separated from the rest on the name with underscore (new `INVALID_EXTENSION_NAME_FORMAT` warning). * Referencing an image of type defined by an extension from the core objects now results in `TEXTURE_INVALID_IMAGE_MIME_TYPE` error. @@ -231,53 +250,53 @@ * A node with a skinned mesh should be a root node (`NODE_SKINNED_MESH_NON_ROOT` warning). * A node with a skinned mesh should not have local transforms (`NODE_SKINNED_MESH_LOCAL_TRANSFORMS` warning). - + * Vertex influences validation: * All joints values must be within the range of joints in the skin (`ACCESSOR_JOINTS_INDEX_OOB` error). - + * No joint may have more than one non-zero weight for a given vertex (`ACCESSOR_JOINTS_INDEX_DUPLICATE` error). * Weights must be non-negative (`ACCESSOR_WEIGHTS_NEGATIVE` error). - + * Weights for each vertex must be normalized to have a linear sum of `1.0` (`ACCESSOR_WEIGHTS_NON_NORMALIZED` error). - + * Unused joint values (i.e. joints with a weight of zero) should be set to zero (`ACCESSOR_JOINTS_USED_ZERO_WEIGHT` warning). ### Integration updates - * Upgraded to the latest stable SDK. +* Upgraded to the latest stable SDK. + +* Generated npm package no longer requires polyfills when using webpack with certain configurations (fixes #110). + +* It is now possible to omit timestamps from validation reports. + +* It is now possible to set the number of used threads for directory validation (cmd-line tool only). + +* Validation report now consistently uses lower-case enums. + +* Native executable binaries can now be compiled. See the [readme](README.md) for details (fixes #113). - * Generated npm package no longer requires polyfills when using webpack with certain configurations (fixes #110). +* Generated report filename is now `.report.json`. - * It is now possible to omit timestamps from validation reports. - - * It is now possible to set the number of used threads for directory validation (cmd-line tool only). - - * Validation report now consistently uses lower-case enums. - - * Native executable binaries can now be compiled. See the [readme](README.md) for details (fixes #113). - - * Generated report filename is now `.report.json`. - - * Unit tests (300+) are now consistently stored: an asset and its validation report. Combined with provided JSON catalogs, they could be used for testing other glTF implementations. +* Unit tests (300+) are now consistently stored: an asset and its validation report. Combined with provided JSON catalogs, they could be used for testing other glTF implementations. ### Changes * Major refactoring of binary data validation. Now, mesh and animation accessor issues are attributed to the corresponding binding points rather than to accessor objects. This change makes validation reports more precise when accessors are reused. Namely: * `ACCESSOR_ANIMATION_INPUT_NEGATIVE` and `ACCESSOR_ANIMATION_INPUT_NON_INCREASING` are attributed to `animation.sampler.input`. - - * `ANIMATION_SAMPLER_OUTPUT_ACCESSOR_NON_NORMALIZED_QUATERNION` (new) is attributed to `animation.channel.sampler`. - + + * `ANIMATION_SAMPLER_OUTPUT_ACCESSOR_NON_NORMALIZED_QUATERNION` (new) is attributed to `animation.channel.sampler`. + * `ACCESSOR_INVALID_SIGN` is attributed to `mesh.primitive.attributes.TANGENT`; its message is more sound now. - + * `ACCESSOR_VECTOR3_NON_UNIT` (renamed from `ACCESSOR_NON_UNIT`) is attributed to `mesh.primitive.attributes.NORMAL` or `mesh.primitive.attributes.TANGENT`. - + * `ACCESSOR_NON_CLAMPED` is attributed to `mesh.primitive.attributes.COLOR`. - + * `ACCESSOR_INVALID_IBM` is attributed to `skin.inverseBindMatrices`. - + * `ACCESSOR_INDEX_OOB`, `ACCESSOR_INDEX_PRIMITIVE_RESTART`, and `ACCESSOR_INDEX_TRIANGLE_DEGENERATE` are attributed to `mesh.primitive.indices`. * `ACCESSOR_INVALID_FLOAT` message is more specific. @@ -346,7 +365,7 @@ * Added `KHR_lights_punctual` support. -* Renamed error code `NODE_ROTATION_NON_UNIT` to `ROTATION_NON_UNIT`. +* Renamed error code `NODE_ROTATION_NON_UNIT` to `ROTATION_NON_UNIT`. ## 2.0.0-dev.2.6 @@ -386,7 +405,7 @@ * Changed `MESH_PRIMITIVE_NO_POSITION` default severity to Warning. -* Added UTF-8 BOM detection for byte inputs. +* Added UTF-8 BOM detection for byte inputs. ## 2.0.0-dev.2.1 @@ -422,7 +441,7 @@ * Fixed issue pointer corruption on empty accessors. -* Improved drag-n-drop validator UX when assets contain many issues (#60, #65). +* Improved drag-n-drop validator UX when assets contain many issues (#60, #65). * Fixed crash on malformed JSON (#66). diff --git a/ISSUES.md b/ISSUES.md index e93532d5..9383fcd9 100644 --- a/ISSUES.md +++ b/ISSUES.md @@ -43,6 +43,10 @@ |INVALID_GL_VALUE|Invalid value `%1` for GL type '`%2`'.|Error| |KHR_LIGHTS_PUNCTUAL_LIGHT_SPOT_ANGLES|outerConeAngle (`%2`) is less than or equal to innerConeAngle (`%1`).|Error| |KHR_MATERIALS_EMISSIVE_STRENGTH_ZERO_FACTOR|Emissive strength has no effect when the emissive factor is zero or undefined.|Warning| +|KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_INVALID|Thickness maximum must be greater than or equal to the thickness minimum.|Error| +|KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_WITHOUT_TEXTURE|Thickness minimum has no effect when a thickness texture is not defined.|Information| +|KHR_MATERIALS_IRIDESCENCE_THICKNESS_TEXTURE_UNUSED|Thickness texture has no effect when the thickness minimum is equal to the thickness maximum.|Information| +|KHR_MATERIALS_VOLUME_DOUBLE_SIDED|The volume extension should not be used with double-sided materials.|Warning| |KHR_MATERIALS_VOLUME_NO_TRANSMISSION|The volume extension needs to be combined with an extension that allows light to transmit through the surface.|Warning| |MATERIAL_ALPHA_CUTOFF_INVALID_MODE|Alpha cutoff is supported only for 'MASK' alpha mode.|Warning| |MESH_INVALID_WEIGHTS_COUNT|The length of weights array (`%1`) does not match the number of morph targets (`%2`).|Error| diff --git a/README.md b/README.md index 42abb6d5..3cf7ac0b 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ NuGet package [Third-party contribution]: https://www.nuget.org/packages/GltfVal - KHR_materials_clearcoat - KHR_materials_emissive_strength - KHR_materials_ior + - KHR_materials_iridescence - KHR_materials_pbrSpecularGlossiness - KHR_materials_sheen - KHR_materials_specular diff --git a/lib/src/base/camera.dart b/lib/src/base/camera.dart index 5c898dd4..ccc5b12d 100644 --- a/lib/src/base/camera.dart +++ b/lib/src/base/camera.dart @@ -84,7 +84,7 @@ class CameraOrthographic extends GltfProperty { final znear = getFloat(map, ZNEAR, context, req: true, min: 0); if (context.validate) { - if (!zfar.isNaN && !znear.isNaN && zfar <= znear) { + if (zfar <= znear) { context.addIssue(SemanticError.cameraZfarLequalZnear); } @@ -128,14 +128,14 @@ class CameraPerspective extends GltfProperty { final yfov = getFloat(map, YFOV, context, req: true, exclMin: 0); - if (context.validate && !yfov.isNaN && yfov >= math.pi) { + if (context.validate && yfov >= math.pi) { context.addIssue(SemanticError.cameraYFovGequalPi); } final zfar = getFloat(map, ZFAR, context, exclMin: 0); final znear = getFloat(map, ZNEAR, context, req: true, exclMin: 0); - if (context.validate && !zfar.isNaN && !znear.isNaN && zfar <= znear) { + if (context.validate && zfar <= znear) { context.addIssue(SemanticError.cameraZfarLequalZnear); } diff --git a/lib/src/base/mesh.dart b/lib/src/base/mesh.dart index 2c43283a..95b12b4a 100644 --- a/lib/src/base/mesh.dart +++ b/lib/src/base/mesh.dart @@ -48,16 +48,17 @@ class Mesh extends GltfChildOfRootProperty { primitives = SafeList(primitivesMaps.length, PRIMITIVES); context.path.add(PRIMITIVES); - int targetsCount; + var targetCount = 0; for (var i = 0; i < primitivesMaps.length; i++) { context.path.add(i.toString()); final primitive = MeshPrimitive.fromMap(primitivesMaps[i], context); if (context.validate) { - if (targetsCount == null) { - targetsCount = primitive._targetsIndices?.length; - } else if (targetsCount != primitive._targetsIndices?.length) { + final primitiveTargetCount = primitive._targetsIndices?.length ?? 0; + if (i == 0) { + targetCount = primitiveTargetCount; + } else if (targetCount != primitiveTargetCount) { context.addIssue(SemanticError.meshPrimitivesUnequalTargetsCount, - name: TARGETS); + name: primitiveTargetCount > 0 ? TARGETS : null); } } primitives[i] = primitive; @@ -66,11 +67,10 @@ class Mesh extends GltfChildOfRootProperty { context.path.removeLast(); if (context.validate && - targetsCount != null && weights != null && - targetsCount != weights.length) { + targetCount != weights.length) { context.addIssue(SemanticError.meshInvalidWeightsCount, - name: WEIGHTS, args: [weights.length, targetsCount]); + name: WEIGHTS, args: [weights.length, targetCount]); } } diff --git a/lib/src/errors.dart b/lib/src/errors.dart index bf3b3b7e..4e575673 100644 --- a/lib/src/errors.dart +++ b/lib/src/errors.dart @@ -507,6 +507,32 @@ class SemanticError extends IssueType { 'that allows light to transmit through the surface.', Severity.Warning); + static final SemanticError khrMaterialsVolumeDoubleSided = SemanticError._( + 'KHR_MATERIALS_VOLUME_DOUBLE_SIDED', + (args) => 'The volume extension should not be used ' + 'with double-sided materials.', + Severity.Warning); + + static final SemanticError + khrMaterialsIridescenceThicknessRangeWithoutTexture = SemanticError._( + 'KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_WITHOUT_TEXTURE', + (args) => 'Thickness minimum has no effect ' + 'when a thickness texture is not defined.', + Severity.Information); + + static final SemanticError khrMaterialsIridescenceThicknessRangeInvalid = + SemanticError._( + 'KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_INVALID', + (args) => 'Thickness maximum must be greater than or ' + 'equal to the thickness minimum.'); + + static final SemanticError khrMaterialsIridescenceThicknessTextureUnused = + SemanticError._( + 'KHR_MATERIALS_IRIDESCENCE_THICKNESS_TEXTURE_UNUSED', + (args) => 'Thickness texture has no effect when the thickness ' + 'minimum is equal to the thickness maximum.', + Severity.Information); + SemanticError._(String type, ErrorFunction message, [Severity severity = Severity.Error]) : super(type, message, severity); diff --git a/lib/src/ext/KHR_lights_punctual/khr_lights_punctual.dart b/lib/src/ext/KHR_lights_punctual/khr_lights_punctual.dart index fb128462..3275b1e2 100644 --- a/lib/src/ext/KHR_lights_punctual/khr_lights_punctual.dart +++ b/lib/src/ext/KHR_lights_punctual/khr_lights_punctual.dart @@ -183,10 +183,7 @@ class KhrLightsPunctualLightSpot extends GltfProperty { final outerConeAngle = getFloat(map, OUTER_CONE_ANGLE, context, def: 0.7853981633974483, exclMin: 0, max: 1.5707963267948966); - if (context.validate && - !outerConeAngle.isNaN && - !innerConeAngle.isNaN && - outerConeAngle <= innerConeAngle) { + if (context.validate && outerConeAngle <= innerConeAngle) { context.addIssue(SemanticError.khrLightsPunctualLightSpotAngles, name: OUTER_CONE_ANGLE, args: [innerConeAngle, outerConeAngle]); } diff --git a/lib/src/ext/KHR_materials_iridescence/khr_materials_iridescence.dart b/lib/src/ext/KHR_materials_iridescence/khr_materials_iridescence.dart new file mode 100644 index 00000000..be2071eb --- /dev/null +++ b/lib/src/ext/KHR_materials_iridescence/khr_materials_iridescence.dart @@ -0,0 +1,131 @@ +// Copyright 2022 The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 + +library gltf.extensions.khr_materials_iridescence; + +import 'package:gltf/src/base/gltf_property.dart'; +import 'package:gltf/src/ext/extensions.dart'; + +const String KHR_MATERIALS_IRIDESCENCE = 'KHR_materials_iridescence'; + +const String IRIDESCENCE_FACTOR = 'iridescenceFactor'; +const String IRIDESCENCE_TEXTURE = 'iridescenceTexture'; +const String IRIDESCENCE_IOR = 'iridescenceIor'; +const String IRIDESCENCE_THICKNESS_MINIMUM = 'iridescenceThicknessMinimum'; +const String IRIDESCENCE_THICKNESS_MAXIMUM = 'iridescenceThicknessMaximum'; +const String IRIDESCENCE_THICKNESS_TEXTURE = 'iridescenceThicknessTexture'; + +const List KHR_MATERIALS_IRIDESCENCE_MEMBERS = [ + IRIDESCENCE_FACTOR, + IRIDESCENCE_TEXTURE, + IRIDESCENCE_IOR, + IRIDESCENCE_THICKNESS_MINIMUM, + IRIDESCENCE_THICKNESS_MAXIMUM, + IRIDESCENCE_THICKNESS_TEXTURE +]; + +class KhrMaterialsIridescence extends GltfProperty { + final double iridescenceFactor; + final TextureInfo iridescenceTexture; + + final double iridescenceIor; + final double iridescenceThicknessMinimum; + final double iridescenceThicknessMaximum; + final TextureInfo iridescenceThicknessTexture; + + KhrMaterialsIridescence._( + this.iridescenceFactor, + this.iridescenceTexture, + this.iridescenceIor, + this.iridescenceThicknessMinimum, + this.iridescenceThicknessMaximum, + this.iridescenceThicknessTexture, + Map extensions, + Object extras) + : super(extensions, extras); + + static KhrMaterialsIridescence fromMap( + Map map, Context context) { + if (context.validate) { + checkMembers(map, KHR_MATERIALS_IRIDESCENCE_MEMBERS, context); + } + + final iridescenceFactor = + getFloat(map, IRIDESCENCE_FACTOR, context, min: 0, max: 1, def: 0); + final iridescenceTexture = getObjectFromInnerMap( + map, IRIDESCENCE_TEXTURE, context, TextureInfo.fromMap); + final iridescenceIor = + getFloat(map, IRIDESCENCE_IOR, context, min: 1, def: 1.3); + final iridescenceThicknessMinimum = + getFloat(map, IRIDESCENCE_THICKNESS_MINIMUM, context, min: 0, def: 100); + final iridescenceThicknessMaximum = + getFloat(map, IRIDESCENCE_THICKNESS_MAXIMUM, context, min: 0, def: 400); + final iridescenceThicknessTexture = getObjectFromInnerMap( + map, IRIDESCENCE_THICKNESS_TEXTURE, context, TextureInfo.fromMap); + + if (context.validate) { + if (iridescenceThicknessMinimum > iridescenceThicknessMaximum) { + context.addIssue( + SemanticError.khrMaterialsIridescenceThicknessRangeInvalid, + name: map.containsKey(IRIDESCENCE_THICKNESS_MINIMUM) + ? IRIDESCENCE_THICKNESS_MINIMUM + : IRIDESCENCE_THICKNESS_MAXIMUM); + } + if (iridescenceThicknessTexture != null) { + if (iridescenceThicknessMinimum == iridescenceThicknessMaximum) { + context.addIssue( + SemanticError.khrMaterialsIridescenceThicknessTextureUnused, + name: IRIDESCENCE_THICKNESS_TEXTURE); + } + } else { + if (!iridescenceThicknessMinimum.isNaN && + map.containsKey(IRIDESCENCE_THICKNESS_MINIMUM)) { + context.addIssue( + SemanticError.khrMaterialsIridescenceThicknessRangeWithoutTexture, + name: IRIDESCENCE_THICKNESS_MINIMUM); + } + } + } + + final extensions = getExtensions(map, KhrMaterialsIridescence, context); + + final iridescence = KhrMaterialsIridescence._( + iridescenceFactor, + iridescenceTexture, + iridescenceIor, + iridescenceThicknessMinimum, + iridescenceThicknessMaximum, + iridescenceThicknessTexture, + extensions, + getExtras(map, context)); + + context.registerObjectsOwner(iridescence, [ + iridescenceTexture, + iridescenceThicknessTexture, + ...extensions.values + ]); + + return iridescence; + } + + @override + void link(Gltf gltf, Context context) { + if (iridescenceTexture != null) { + context.path.add(IRIDESCENCE_TEXTURE); + iridescenceTexture.link(gltf, context); + context.path.removeLast(); + } + + if (iridescenceThicknessTexture != null) { + context.path.add(IRIDESCENCE_THICKNESS_TEXTURE); + iridescenceThicknessTexture.link(gltf, context); + context.path.removeLast(); + } + } +} + +const Extension khrMaterialsIridescenceExtension = Extension( + KHR_MATERIALS_IRIDESCENCE, { + Material: ExtensionDescriptor(KhrMaterialsIridescence.fromMap) +}); diff --git a/lib/src/ext/KHR_materials_volume/khr_materials_volume.dart b/lib/src/ext/KHR_materials_volume/khr_materials_volume.dart index 771c56e5..ba7658d1 100644 --- a/lib/src/ext/KHR_materials_volume/khr_materials_volume.dart +++ b/lib/src/ext/KHR_materials_volume/khr_materials_volume.dart @@ -87,6 +87,10 @@ class KhrMaterialsVolume extends GltfProperty { !o.extensions.values.any((e) => e is Map)) { context.addIssue(SemanticError.khrMaterialsVolumeNoTransmission); } + + if (o.doubleSided && thicknessFactor > 0) { + context.addIssue(SemanticError.khrMaterialsVolumeDoubleSided); + } break; } } diff --git a/lib/src/ext/extensions.dart b/lib/src/ext/extensions.dart index 895ff076..96df5df7 100644 --- a/lib/src/ext/extensions.dart +++ b/lib/src/ext/extensions.dart @@ -22,6 +22,7 @@ import 'package:gltf/src/ext/KHR_lights_punctual/khr_lights_punctual.dart'; import 'package:gltf/src/ext/KHR_materials_clearcoat/khr_materials_clearcoat.dart'; import 'package:gltf/src/ext/KHR_materials_emissive_strength/khr_materials_emissive_strength.dart'; import 'package:gltf/src/ext/KHR_materials_ior/khr_materials_ior.dart'; +import 'package:gltf/src/ext/KHR_materials_iridescence/khr_materials_iridescence.dart'; import 'package:gltf/src/ext/KHR_materials_pbrSpecularGlossiness/khr_materials_pbr_specular_glossiness.dart'; import 'package:gltf/src/ext/KHR_materials_sheen/khr_materials_sheen.dart'; import 'package:gltf/src/ext/KHR_materials_specular/khr_materials_specular.dart'; @@ -39,6 +40,7 @@ export 'package:gltf/src/ext/KHR_lights_punctual/khr_lights_punctual.dart'; export 'package:gltf/src/ext/KHR_materials_clearcoat/khr_materials_clearcoat.dart'; export 'package:gltf/src/ext/KHR_materials_emissive_strength/khr_materials_emissive_strength.dart'; export 'package:gltf/src/ext/KHR_materials_ior/khr_materials_ior.dart'; +export 'package:gltf/src/ext/KHR_materials_iridescence/khr_materials_iridescence.dart'; export 'package:gltf/src/ext/KHR_materials_pbrSpecularGlossiness/khr_materials_pbr_specular_glossiness.dart'; export 'package:gltf/src/ext/KHR_materials_sheen/khr_materials_sheen.dart'; export 'package:gltf/src/ext/KHR_materials_specular/khr_materials_specular.dart' @@ -100,6 +102,7 @@ const List kDefaultExtensions = [ khrMaterialsClearcoatExtension, khrMaterialsEmissiveStrengthExtension, khrMaterialsIorExtension, + khrMaterialsIridescenceExtension, khrMaterialsPbrSpecularGlossinessExtension, khrMaterialsSheenExtension, khrMaterialsSpecularExtension, @@ -137,6 +140,7 @@ const Set kReservedPrefixes = { 'FOXIT', 'GOOGLE', 'GRIFFEL', + 'INTEL', 'KDAB', 'LLQ', 'MAXAR', @@ -144,6 +148,7 @@ const Set kReservedPrefixes = { 'MOZ', 'MPEG', 'MSFT', + 'MTTR', 'MX', 'NEEDLE', 'NV', diff --git a/lib/src/version.dart b/lib/src/version.dart index 270823ba..3e7aa91b 100644 --- a/lib/src/version.dart +++ b/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '2.0.0-dev.3.7'; +const packageVersion = '2.0.0-dev.3.8'; diff --git a/pubspec.yaml b/pubspec.yaml index cb4bf630..b5e7c5c9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: gltf -version: 2.0.0-dev.3.7 +version: 2.0.0-dev.3.8 description: Library for loading and validating glTF 2.0 assets homepage: https://github.com/KhronosGroup/glTF-Validator diff --git a/test/base/data/mesh/morph_unequal_targets_count.gltf b/test/base/data/mesh/morph_unequal_targets_count.gltf index 8cd28bf9..43e8cee1 100644 --- a/test/base/data/mesh/morph_unequal_targets_count.gltf +++ b/test/base/data/mesh/morph_unequal_targets_count.gltf @@ -27,6 +27,46 @@ "POSITION": 3 } ] + }, + { + "attributes": { + "POSITION": 2 + } + } + ] + }, + { + "primitives": [ + { + "attributes": { + "POSITION": 2 + } + }, + { + "attributes": { + "POSITION": 0 + }, + "targets": [ + { + "POSITION": 1 + }, + { + "POSITION": 1 + } + ] + }, + { + "attributes": { + "POSITION": 2 + }, + "targets": [ + { + "POSITION": 3 + }, + { + "POSITION": 3 + } + ] } ] } diff --git a/test/base/data/mesh/morph_unequal_targets_count.gltf.report.json b/test/base/data/mesh/morph_unequal_targets_count.gltf.report.json index bf0ec3e8..cb2f4b3c 100644 --- a/test/base/data/mesh/morph_unequal_targets_count.gltf.report.json +++ b/test/base/data/mesh/morph_unequal_targets_count.gltf.report.json @@ -1,11 +1,11 @@ { "uri": "test/base/data/mesh/morph_unequal_targets_count.gltf", "mimeType": "model/gltf+json", - "validatorVersion": "2.0.0-dev.3.0", + "validatorVersion": "2.0.0-dev.3.8", "issues": { - "numErrors": 1, + "numErrors": 4, "numWarnings": 0, - "numInfos": 1, + "numInfos": 2, "numHints": 0, "messages": [ { @@ -14,11 +14,35 @@ "severity": 0, "pointer": "/meshes/0/primitives/1/targets" }, + { + "code": "MESH_PRIMITIVES_UNEQUAL_TARGETS_COUNT", + "message": "All primitives must have the same number of morph targets.", + "severity": 0, + "pointer": "/meshes/0/primitives/2" + }, + { + "code": "MESH_PRIMITIVES_UNEQUAL_TARGETS_COUNT", + "message": "All primitives must have the same number of morph targets.", + "severity": 0, + "pointer": "/meshes/1/primitives/1/targets" + }, + { + "code": "MESH_PRIMITIVES_UNEQUAL_TARGETS_COUNT", + "message": "All primitives must have the same number of morph targets.", + "severity": 0, + "pointer": "/meshes/1/primitives/2/targets" + }, { "code": "UNUSED_OBJECT", "message": "This object may be unused.", "severity": 2, "pointer": "/meshes/0" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/meshes/1" } ], "truncated": false @@ -31,9 +55,9 @@ "hasSkins": false, "hasTextures": false, "hasDefaultScene": false, - "drawCallCount": 2, - "totalVertexCount": 6, - "totalTriangleCount": 2, + "drawCallCount": 6, + "totalVertexCount": 18, + "totalTriangleCount": 6, "maxUVs": 0, "maxInfluences": 0, "maxAttributes": 1 diff --git a/test/ext/KHR_materials_iridescence/assets.json b/test/ext/KHR_materials_iridescence/assets.json new file mode 100644 index 00000000..5bd0ad7c --- /dev/null +++ b/test/ext/KHR_materials_iridescence/assets.json @@ -0,0 +1,13 @@ +{ + "material": { + "name": "material.KHR_materials_iridescence", + "tests": { + "custom_property.gltf": "Custom property", + "unexpected_extension.gltf": "Unexpected extension object location", + "invalid_thickness_range.gltf": "Invalid thickness range", + "unused_thickness_texture.gltf": "Unused thickness texture", + "unused_thickness_minimum.gltf": "Unused thickness minimum", + "valid.gltf": "Valid" + } + } +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/custom_property.gltf b/test/ext/KHR_materials_iridescence/data/material/custom_property.gltf new file mode 100644 index 00000000..57708b71 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/custom_property.gltf @@ -0,0 +1,17 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "materials": [ + { + "extensions": { + "KHR_materials_iridescence": { + "customProperty": true + } + } + } + ] +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/custom_property.gltf.report.json b/test/ext/KHR_materials_iridescence/data/material/custom_property.gltf.report.json new file mode 100644 index 00000000..d4719373 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/custom_property.gltf.report.json @@ -0,0 +1,44 @@ +{ + "uri": "test/ext/KHR_materials_iridescence/data/material/custom_property.gltf", + "mimeType": "model/gltf+json", + "validatorVersion": "2.0.0-dev.3.8", + "issues": { + "numErrors": 0, + "numWarnings": 1, + "numInfos": 1, + "numHints": 0, + "messages": [ + { + "code": "UNEXPECTED_PROPERTY", + "message": "Unexpected property.", + "severity": 1, + "pointer": "/materials/0/extensions/KHR_materials_iridescence/customProperty" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/0" + } + ], + "truncated": false + }, + "info": { + "version": "2.0", + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "animationCount": 0, + "materialCount": 1, + "hasMorphTargets": false, + "hasSkins": false, + "hasTextures": false, + "hasDefaultScene": false, + "drawCallCount": 0, + "totalVertexCount": 0, + "totalTriangleCount": 0, + "maxUVs": 0, + "maxInfluences": 0, + "maxAttributes": 0 + } +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/invalid_thickness_range.gltf b/test/ext/KHR_materials_iridescence/data/material/invalid_thickness_range.gltf new file mode 100644 index 00000000..3f5bbcb3 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/invalid_thickness_range.gltf @@ -0,0 +1,47 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "materials": [ + { + "extensions": { + "KHR_materials_iridescence": { + "iridescenceFactor": 1, + "iridescenceThicknessMinimum": 500, + "iridescenceThicknessMaximum": 90, + "iridescenceThicknessTexture": { + "index": 0 + } + } + } + }, + { + "extensions": { + "KHR_materials_iridescence": { + "iridescenceFactor": 1, + "iridescenceThicknessMaximum": 90, + "iridescenceThicknessTexture": { + "index": 0 + } + } + } + }, + { + "extensions": { + "KHR_materials_iridescence": { + "iridescenceFactor": 1, + "iridescenceThicknessMinimum": 500, + "iridescenceThicknessTexture": { + "index": 0 + } + } + } + } + ], + "textures": [ + { } + ] +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/invalid_thickness_range.gltf.report.json b/test/ext/KHR_materials_iridescence/data/material/invalid_thickness_range.gltf.report.json new file mode 100644 index 00000000..9023c873 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/invalid_thickness_range.gltf.report.json @@ -0,0 +1,68 @@ +{ + "uri": "test/ext/KHR_materials_iridescence/data/material/invalid_thickness_range.gltf", + "mimeType": "model/gltf+json", + "validatorVersion": "2.0.0-dev.3.8", + "issues": { + "numErrors": 3, + "numWarnings": 0, + "numInfos": 3, + "numHints": 0, + "messages": [ + { + "code": "KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_INVALID", + "message": "Thickness maximum must be greater than or equal to the thickness minimum.", + "severity": 0, + "pointer": "/materials/0/extensions/KHR_materials_iridescence/iridescenceThicknessMinimum" + }, + { + "code": "KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_INVALID", + "message": "Thickness maximum must be greater than or equal to the thickness minimum.", + "severity": 0, + "pointer": "/materials/1/extensions/KHR_materials_iridescence/iridescenceThicknessMaximum" + }, + { + "code": "KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_INVALID", + "message": "Thickness maximum must be greater than or equal to the thickness minimum.", + "severity": 0, + "pointer": "/materials/2/extensions/KHR_materials_iridescence/iridescenceThicknessMinimum" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/0" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/1" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/2" + } + ], + "truncated": false + }, + "info": { + "version": "2.0", + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "animationCount": 0, + "materialCount": 3, + "hasMorphTargets": false, + "hasSkins": false, + "hasTextures": true, + "hasDefaultScene": false, + "drawCallCount": 0, + "totalVertexCount": 0, + "totalTriangleCount": 0, + "maxUVs": 0, + "maxInfluences": 0, + "maxAttributes": 0 + } +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/unexpected_extension.gltf b/test/ext/KHR_materials_iridescence/data/material/unexpected_extension.gltf new file mode 100644 index 00000000..9b9ff934 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/unexpected_extension.gltf @@ -0,0 +1,18 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "materials": [ + { + "pbrMetallicRoughness": { + "extensions": { + "KHR_materials_iridescence": { + } + } + } + } + ] +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/unexpected_extension.gltf.report.json b/test/ext/KHR_materials_iridescence/data/material/unexpected_extension.gltf.report.json new file mode 100644 index 00000000..3ae5ddfe --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/unexpected_extension.gltf.report.json @@ -0,0 +1,44 @@ +{ + "uri": "test/ext/KHR_materials_iridescence/data/material/unexpected_extension.gltf", + "mimeType": "model/gltf+json", + "validatorVersion": "2.0.0-dev.3.8", + "issues": { + "numErrors": 1, + "numWarnings": 0, + "numInfos": 1, + "numHints": 0, + "messages": [ + { + "code": "UNEXPECTED_EXTENSION_OBJECT", + "message": "Unexpected location for this extension.", + "severity": 0, + "pointer": "/materials/0/pbrMetallicRoughness/extensions/KHR_materials_iridescence" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/0" + } + ], + "truncated": false + }, + "info": { + "version": "2.0", + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "animationCount": 0, + "materialCount": 1, + "hasMorphTargets": false, + "hasSkins": false, + "hasTextures": false, + "hasDefaultScene": false, + "drawCallCount": 0, + "totalVertexCount": 0, + "totalTriangleCount": 0, + "maxUVs": 0, + "maxInfluences": 0, + "maxAttributes": 0 + } +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/unused_thickness_minimum.gltf b/test/ext/KHR_materials_iridescence/data/material/unused_thickness_minimum.gltf new file mode 100644 index 00000000..a8c01139 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/unused_thickness_minimum.gltf @@ -0,0 +1,18 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "materials": [ + { + "extensions": { + "KHR_materials_iridescence": { + "iridescenceFactor": 1, + "iridescenceThicknessMinimum": 150 + } + } + } + ] +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/unused_thickness_minimum.gltf.report.json b/test/ext/KHR_materials_iridescence/data/material/unused_thickness_minimum.gltf.report.json new file mode 100644 index 00000000..b7b681d1 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/unused_thickness_minimum.gltf.report.json @@ -0,0 +1,44 @@ +{ + "uri": "test/ext/KHR_materials_iridescence/data/material/unused_thickness_minimum.gltf", + "mimeType": "model/gltf+json", + "validatorVersion": "2.0.0-dev.3.8", + "issues": { + "numErrors": 0, + "numWarnings": 0, + "numInfos": 2, + "numHints": 0, + "messages": [ + { + "code": "KHR_MATERIALS_IRIDESCENCE_THICKNESS_RANGE_WITHOUT_TEXTURE", + "message": "Thickness minimum has no effect when a thickness texture is not defined.", + "severity": 2, + "pointer": "/materials/0/extensions/KHR_materials_iridescence/iridescenceThicknessMinimum" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/0" + } + ], + "truncated": false + }, + "info": { + "version": "2.0", + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "animationCount": 0, + "materialCount": 1, + "hasMorphTargets": false, + "hasSkins": false, + "hasTextures": false, + "hasDefaultScene": false, + "drawCallCount": 0, + "totalVertexCount": 0, + "totalTriangleCount": 0, + "maxUVs": 0, + "maxInfluences": 0, + "maxAttributes": 0 + } +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/unused_thickness_texture.gltf b/test/ext/KHR_materials_iridescence/data/material/unused_thickness_texture.gltf new file mode 100644 index 00000000..44aa339a --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/unused_thickness_texture.gltf @@ -0,0 +1,25 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "materials": [ + { + "extensions": { + "KHR_materials_iridescence": { + "iridescenceFactor": 1, + "iridescenceThicknessMinimum": 300, + "iridescenceThicknessMaximum": 300, + "iridescenceThicknessTexture": { + "index": 0 + } + } + } + } + ], + "textures": [ + { } + ] +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/unused_thickness_texture.gltf.report.json b/test/ext/KHR_materials_iridescence/data/material/unused_thickness_texture.gltf.report.json new file mode 100644 index 00000000..a5f3dcf3 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/unused_thickness_texture.gltf.report.json @@ -0,0 +1,44 @@ +{ + "uri": "test/ext/KHR_materials_iridescence/data/material/unused_thickness_texture.gltf", + "mimeType": "model/gltf+json", + "validatorVersion": "2.0.0-dev.3.8", + "issues": { + "numErrors": 0, + "numWarnings": 0, + "numInfos": 2, + "numHints": 0, + "messages": [ + { + "code": "KHR_MATERIALS_IRIDESCENCE_THICKNESS_TEXTURE_UNUSED", + "message": "Thickness texture has no effect when the thickness minimum is equal to the thickness maximum.", + "severity": 2, + "pointer": "/materials/0/extensions/KHR_materials_iridescence/iridescenceThicknessTexture" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/0" + } + ], + "truncated": false + }, + "info": { + "version": "2.0", + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "animationCount": 0, + "materialCount": 1, + "hasMorphTargets": false, + "hasSkins": false, + "hasTextures": true, + "hasDefaultScene": false, + "drawCallCount": 0, + "totalVertexCount": 0, + "totalTriangleCount": 0, + "maxUVs": 0, + "maxInfluences": 0, + "maxAttributes": 0 + } +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/valid.gltf b/test/ext/KHR_materials_iridescence/data/material/valid.gltf new file mode 100644 index 00000000..a6542104 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/valid.gltf @@ -0,0 +1,37 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "materials": [ + { + "extensions": { + "KHR_materials_iridescence": { + } + } + }, + { + "extensions": { + "KHR_materials_iridescence": { + "iridescenceFactor": 0.5, + "iridescenceTexture": { + "index": 0 + }, + "iridescenceIor": 2, + "iridescenceThicknessMinimum": 150, + "iridescenceThicknessMaximum": 450, + "iridescenceThicknessTexture": { + "index": 1 + } + } + } + } + ], + "textures": [ + { + }, { + } + ] +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/data/material/valid.gltf.report.json b/test/ext/KHR_materials_iridescence/data/material/valid.gltf.report.json new file mode 100644 index 00000000..ff4bd0b2 --- /dev/null +++ b/test/ext/KHR_materials_iridescence/data/material/valid.gltf.report.json @@ -0,0 +1,44 @@ +{ + "uri": "test/ext/KHR_materials_iridescence/data/material/valid.gltf", + "mimeType": "model/gltf+json", + "validatorVersion": "2.0.0-dev.3.8", + "issues": { + "numErrors": 0, + "numWarnings": 0, + "numInfos": 2, + "numHints": 0, + "messages": [ + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/0" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/1" + } + ], + "truncated": false + }, + "info": { + "version": "2.0", + "extensionsUsed": [ + "KHR_materials_iridescence" + ], + "animationCount": 0, + "materialCount": 2, + "hasMorphTargets": false, + "hasSkins": false, + "hasTextures": true, + "hasDefaultScene": false, + "drawCallCount": 0, + "totalVertexCount": 0, + "totalTriangleCount": 0, + "maxUVs": 0, + "maxInfluences": 0, + "maxAttributes": 0 + } +} \ No newline at end of file diff --git a/test/ext/KHR_materials_iridescence/khr_materials_iridescence_test.dart b/test/ext/KHR_materials_iridescence/khr_materials_iridescence_test.dart new file mode 100644 index 00000000..0bfce77c --- /dev/null +++ b/test/ext/KHR_materials_iridescence/khr_materials_iridescence_test.dart @@ -0,0 +1,48 @@ +// Copyright 2022 The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:async'; + +import 'package:gltf/gltf.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Future main() async { + await compareReports('test/ext/KHR_materials_iridescence'); + + group('Evaluate valid objects', () { + test('material.KHR_materials_iridescence', () async { + final gltf = (await read( + 'ext/KHR_materials_iridescence/data/material/valid.gltf', + ignoreUnused: true)) + .gltf; + + { + final iridescence = gltf.materials[0] + .extensions['KHR_materials_iridescence'] as KhrMaterialsIridescence; + expect(iridescence.iridescenceFactor, 0); + expect(iridescence.iridescenceTexture, isNull); + expect(iridescence.iridescenceIor, 1.3); + expect(iridescence.iridescenceThicknessMinimum, 100); + expect(iridescence.iridescenceThicknessMaximum, 400); + expect(iridescence.iridescenceThicknessTexture, isNull); + expect(iridescence.extensions, isEmpty); + } + + { + final iridescence = gltf.materials[1] + .extensions['KHR_materials_iridescence'] as KhrMaterialsIridescence; + expect(iridescence.iridescenceFactor, 0.5); + expect(iridescence.iridescenceTexture.texture, gltf.textures[0]); + expect(iridescence.iridescenceIor, 2); + expect(iridescence.iridescenceThicknessMinimum, 150); + expect(iridescence.iridescenceThicknessMaximum, 450); + expect( + iridescence.iridescenceThicknessTexture.texture, gltf.textures[1]); + expect(iridescence.extensions, isEmpty); + } + }); + }); +} diff --git a/test/ext/KHR_materials_volume/assets.json b/test/ext/KHR_materials_volume/assets.json index 496dda23..2ee950a9 100644 --- a/test/ext/KHR_materials_volume/assets.json +++ b/test/ext/KHR_materials_volume/assets.json @@ -3,6 +3,7 @@ "name": "material.KHR_materials_volume", "tests": { "custom_property.gltf": "Custom property", + "double_sided.gltf": "Double-sided material", "out_of_range.gltf": "Out of range values", "unexpected_extension.gltf": "Unexpected extension object location", "unknown_transmission.gltf": "Unknown transmission extension", diff --git a/test/ext/KHR_materials_volume/data/material/double_sided.gltf b/test/ext/KHR_materials_volume/data/material/double_sided.gltf new file mode 100644 index 00000000..07916934 --- /dev/null +++ b/test/ext/KHR_materials_volume/data/material/double_sided.gltf @@ -0,0 +1,26 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_materials_transmission", "KHR_materials_volume" + ], + "materials": [ + { + "doubleSided": true, + "extensions": { + "KHR_materials_transmission": { }, + "KHR_materials_volume": { } + } + }, + { + "doubleSided": true, + "extensions": { + "KHR_materials_transmission": { }, + "KHR_materials_volume": { + "thicknessFactor": 1 + } + } + } + ] +} \ No newline at end of file diff --git a/test/ext/KHR_materials_volume/data/material/double_sided.gltf.report.json b/test/ext/KHR_materials_volume/data/material/double_sided.gltf.report.json new file mode 100644 index 00000000..e804aa8a --- /dev/null +++ b/test/ext/KHR_materials_volume/data/material/double_sided.gltf.report.json @@ -0,0 +1,51 @@ +{ + "uri": "test/ext/KHR_materials_volume/data/material/double_sided.gltf", + "mimeType": "model/gltf+json", + "validatorVersion": "2.0.0-dev.3.8", + "issues": { + "numErrors": 0, + "numWarnings": 1, + "numInfos": 2, + "numHints": 0, + "messages": [ + { + "code": "KHR_MATERIALS_VOLUME_DOUBLE_SIDED", + "message": "The volume extension should not be used with double-sided materials.", + "severity": 1, + "pointer": "/materials/1/extensions/KHR_materials_volume" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/0" + }, + { + "code": "UNUSED_OBJECT", + "message": "This object may be unused.", + "severity": 2, + "pointer": "/materials/1" + } + ], + "truncated": false + }, + "info": { + "version": "2.0", + "extensionsUsed": [ + "KHR_materials_transmission", + "KHR_materials_volume" + ], + "animationCount": 0, + "materialCount": 2, + "hasMorphTargets": false, + "hasSkins": false, + "hasTextures": false, + "hasDefaultScene": false, + "drawCallCount": 0, + "totalVertexCount": 0, + "totalTriangleCount": 0, + "maxUVs": 0, + "maxInfluences": 0, + "maxAttributes": 0 + } +} \ No newline at end of file