Giter Site home page Giter Site logo

gltf-validator's Introduction

glTF-Validator

Build Status

Tool to validate glTF assets.

Validation is performed against glTF 2.0 specification.

Validator writes a validation report (in JSON-format) with all found issues and asset stats.

Live drag-n-drop tool: https://github.khronos.org/glTF-Validator

NPM package: https://www.npmjs.com/package/gltf-validator

NuGet package [Third-party contribution]: https://www.nuget.org/packages/GltfValidator/

Implemented features

  • JSON syntax check and GLBv2 file format correctness.
  • Asset description validation
    • All properties and their types from JSON-Schemas (including implicit limitations on valid values).
    • Validity and compatibility of internal references.
    • Correctness of Data URI encoding.
  • Binary buffers validation
    • Forbidden or incorrect accessor values (e.g., NaN, invalid quaternions, indecomposable matrices, etc).
    • accessor.min and accessor.max values.
    • Sparse accessors encoding.
    • Animation inputs and outputs.
  • Images validation
    • Warning on non-power-of-two dimensions.
    • Warning on unsupported image features (like animations or custom color spaces).
  • Extensions validation
    • EXT_texture_webp
    • KHR_lights_punctual
    • KHR_materials_clearcoat
    • KHR_materials_emissive_strength
    • KHR_materials_ior
    • KHR_materials_iridescence
    • KHR_materials_pbrSpecularGlossiness
    • KHR_materials_sheen
    • KHR_materials_specular
    • KHR_materials_transmission
    • KHR_materials_unlit
    • KHR_materials_variants
    • KHR_materials_volume
    • KHR_mesh_quantization
    • KHR_texture_transform
  • Full list of detectable issues.

Usage

You can use hosted web front-end tool. It works completely in the browser without any server-side processing.

Command Line Tool Usage

Usage: gltf_validator [<options>] <input>

Validation report will be written to `<asset_filename>.report.json`.
If <input> is a directory, validation reports will be recursively created for each *.gltf or *.glb asset.

Validation log will be printed to stderr.

Shell return code will be non-zero if at least one error was found.
-o, --[no-]stdout                Print JSON report to stdout instead of writing it to a file. This option cannot be used with directory input.
-r, --[no-]validate-resources    Validate contents of embedded and/or referenced resources (buffers, images).
                                 (defaults to on)
-t, --[no-]write-timestamp       Write UTC timestamp to the validation report.
-p, --[no-]absolute-path         Write absolute asset path to the validation report.
-m, --[no-]messages              Print issue messages to stderr. Otherwise, only total number of issues will be printed.
-a, --[no-]all                   Print all issue messages to stderr. Otherwise, only errors will be printed. Implies --messages.
-c, --config                     YAML configuration file with validation options. See docs/config-example.yaml for details.
-h, --threads                    The number of threads for directory validation. Set to 0 (default) for auto selection.

Building

Prerequisites

  1. Download and install Dart SDK for your platform.
  2. Add Dart SDK bin folder to your PATH.
  3. From the repository root folder, run dart pub get to get dependencies.

Fetching dependencies from behind a corporate firewall

dart pub get downloads dependencies from Google's pub.dev server over HTTPS. If you need to specify a proxy, follow these steps:

  1. Set https_proxy or HTTPS_PROXY environment variable in form hostname:port.
  2. If the proxy requires credentials, use this syntax: username:password@hostname:port.

dart pub get validates server's SSL certificate. If your corporate network interferes with SSL connections, follow these steps to get it running.

  1. Save your corporate self-signed root certificate as X.509 file.
  2. (Linux only) Try to add your cert to /etc/pki/tls/certs/ca-bundle.crt or /etc/ssl/certs.
  3. If that doesn't work or if you're on Windows, add environment variable DART_VM_OPTIONS with value --root-certs-file=<cert_file>.

After doing this, dart pub get should be able to download dependencies successfully.

Drag-n-Drop Web Tool

To build a drag-n-drop online validation tool (as hosted here), follow these steps after installation:

  1. Run dart run grinder web.
  2. All needed files will be written to build/web directory.

CLI tool

  1. Run dart run grinder exe.
  2. Native executable file will be written to build/bin/gltf_validator or build/bin/gltf_validator.exe.

NPM Package

To build an npm package for use in Node.js environment, follow these steps after installation:

  1. Run dart run grinder npm.
  2. gltf-validator npm package will be written to build/node.

Refer to the npm package documentation for additional information.

Publishing

To publish an npm package, follow these steps after installation:

  1. Run dart run grinder npm-publish.
  2. gltf-validator npm package will be built to build/node and published to npm registry using npm publish.

Validation Issues List

To generate ISSUES.md, follow these steps after installation:

  1. Run dart run grinder issues.
  2. ISSUES.md file will be written to the repo root.

gltf-validator's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gltf-validator's Issues

Unknown primitive semantics crash validator

For example, the glTF:

{
  "meshes": {
    "mesh": {
      "primitives": [
        {
          "attributes": {
            "UNKNOWN_SEMANTIC": "accessor"
          }
        }
      ]
    }
  }
}

Creates the following error:

Uncaught Error: Converting object to an encodable object failed.(…) validator.dart.js:782

This will also happen if you use TEXCOORD instead of TEXCOORD_# which is how I discovered this in the first place. This should throw a more verbose error.

Unresolved references reported for animation.sampler.input and output

While validating the "minimal examples" for the tutorial with the current web-front-end tool at http://github.khronos.org/glTF-Validator/ , I noticed that the validator reported the following errors

    "errors": [
        {
            "type": "UNRESOLVED_REFERENCE",
            "path": "/animations/animation0/samplers/rotationSampler/input",
            "message": "Unresolved reference: `timeAccessor`"
        },
        {
            "type": "UNRESOLVED_REFERENCE",
            "path": "/animations/animation0/samplers/rotationSampler/output",
            "message": "Unresolved reference: `rotationAccessor`"
        }
    ],

for the following input file

{
  "scenes" : {
    "scene0" : {
      "nodes" : [ "node0" ]
    }
  },
  "nodes" : {
    "node0" : {
      "meshes" : [ "mesh0" ],
      "rotation" : [ 0.0, 0.0, 0.0, 1.0 ]
    }
  },
  "meshes" : {
    "mesh0" : {
      "primitives" : [ {
        "attributes" : {
          "POSITION" : "positionsAccessor"
        },
        "indices" : "indicesAccessor"
      } ]
    }
  },

  "animations" : {
    "animation0" : {
      "samplers" : {
        "rotationSampler" : {
          "input" : "timeAccessor",
          "interpolation" : "LINEAR",
          "output" : "rotationAccessor"
        }
      },
      "channels" : [ {
        "sampler" : "rotationSampler",
        "target" : {
          "id" : "node0",
          "path" : "rotation"
        }
      } ]
    }
  },

  "buffers" : {
    "buffer0" : {
      "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAA",
      "byteLength" : 42
    },
    "buffer1" : {
      "uri" : "data:application/octet-stream;base64,AAAAAAAAgD4AAAA/AABAPwAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAPT9ND/0/TS/AAAAAAAAAAAAAAAAAACAPw==",
      "byteLength" : 100
    }
  },
  "bufferViews" : {
    "indicesBufferView" : {
      "buffer" : "buffer0",
      "byteOffset" : 0,
      "byteLength" : 6,
      "target" : 34963
    },
    "positionsBufferView" : {
      "buffer" : "buffer0",
      "byteOffset" : 6,
      "byteLength" : 36,
      "target" : 34962
    },
    "animationsBufferView" : {
      "buffer" : "buffer1",
      "byteOffset" : 0,
      "byteLength" : 100
    }
  },
  "accessors" : {
    "indicesAccessor" : {
      "bufferView" : "indicesBufferView",
      "byteOffset" : 0,
      "componentType" : 5123,
      "count" : 3,
      "type" : "SCALAR",
      "max" : [ 2.0 ],
      "min" : [ 0.0 ]
    },
    "positionsAccessor" : {
      "bufferView" : "positionsBufferView",
      "byteOffset" : 0,
      "componentType" : 5126,
      "count" : 3,
      "type" : "VEC3",
      "max" : [ 1.0, 1.0, 0.0 ],
      "min" : [ 0.0, 0.0, 0.0 ]
    },
    "timeAccessor" : {
      "bufferView" : "animationsBufferView",
      "byteOffset" : 0,
      "componentType" : 5126,
      "count" : 5,
      "type" : "SCALAR",
      "max" : [ 1.0 ],
      "min" : [ 0.0 ]
    },
    "rotationAccessor" : {
      "bufferView" : "animationsBufferView",
      "byteOffset" : 20,
      "componentType" : 5126,
      "count" : 5,
      "type" : "VEC4",
      "max" : [ 0.0, 0.0, 1.0, 1.0 ],
      "min" : [ 0.0, 0.0, 0.0, -0.707 ]
    }
  },
  
  "asset" : {
    "version" : "1.1"
  }
  
}

This file is supposed to be a complete (embedded, and thus standalone) example, and if I'm not misinterpreting something here, then the references should be valid: The animation.sampler.input and output directly refer to the accessors, without the detour through the animation.parameters.

I tried to take a look at a commit that is likely related: 689fd5b , but before diving deeper into this (setting up Dart SDK and examining this) :

  • Was the online tool created from a version before this commit?
  • Can you confirm that the file should be valid?

Validator and friends versioning policy

At the moment, we have glTF spec version 1.0.1, with WebGL 1.0.3 profile (this also implies GLSL ES 1.0).

First release version of Validator will obviously have version 1.0. However numbering future versions could become a mess, because it's unclear should Validator's version be aligned with spec or not.

Some possible strategies:

  • fork validation code each time;
  • incorporate a version check into every validation function;
  • drop support for old spec versions, or make something like a sliding window (like GPU drivers handle old hardware).

Ideas?

Formalize expected numerical thresholds

Currently, certain validation checks rely on inconsistent and arbitrary-chosen thresholds. We should harmonize them, and optionally add notes to the main spec.

Unit length of certain vectors

Rotation quaternions stored in JSON (node.rotation)

  • Validator treats those JSON numbers as single-precision floats.
  • Current rule for triggering error is abs(1.0 - sqrt(x * x + y * y + z * z + w * w)) > 0.000005.

Attribute data with NORMAL and TANGENT semantics; animated rotation quaternions

  • Current rule for triggering error is abs(1.0 - (x * x + y * y + z * z)) > 0.0005.

Questions

  • What threshold should we have for unit vectors?
  • Should it be the same for Vec3 and Quaternions?
  • Could we rely on length ^ 2 to avoid sqrt?
  • Should we have two thresholds with Error and Warning validation severities?

Matrices decomposability

Checks

TRS Matrices stored in JSON (node.transform)

  • Validator treats those JSON numbers as single-precision floats.
  • See validation process below.

IBM Matrices (skin.inverseBindMatrices)

  • See validation process below.

Procedures

Matrix validation process

  1. Decompose matrix M into Vector3 translation, Quaternion rotation, and Vector3 scale (see below).
  2. Compose transformation matrix M' from translation, rotation, and scale (see below).
  3. Let N and N' be infinity norms of M and M' respectively.
  4. If abs(N - N') < 0.00005, matrix M is valid.

Matrix decompose process

  1. Let M[16] be input matrix written in column-major order.
  2. If M[3] != 0.0 || M[7] != 0.0 || M[11] != 0.0 || M[15] != 1.0,
    • matrix is indecomposable, exit.
  3. If determinant(M) equals 0.0,
    • matrix is indecomposable, exit.
  4. Let translation be Vector3(M[12], M[13], M[14]).
  5. Let
    • sx = sqrt(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]);
    • sy = sqrt(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]);
    • sz = sqrt(M[8] * M[8] + M[9] * M[9] + M[10] * M[10]).
  6. If determinant(M) < 0
    • sx = -sx.
  7. Let scale be Vector3(sx, sy, sz).
  8. Let:
    • invSx = 1.0 / sx;
    • invSy = 1.0 / sy;
    • invSz = 1.0 / sz.
  9. Let r[9] be rotation matrix:
    • r[0] = M[0] * invSx;
    • r[1] = M[1] * invSx;
    • r[2] = M[2] * invSx;
    • r[3] = M[4] * invSy;
    • r[4] = M[5] * invSy;
    • r[5] = M[6] * invSy;
    • r[6] = M[8] * invSz;
    • r[7] = M[9] * invSz;
    • r[8] = M[10] * invSz.
  10. Let rotation be quaternion with rotation from matrix r.

Matrix compose process

  1. Let Vector3 translation, Quaternion rotation, and Vector3 scale be input transforms, and M[16] be output composed matrix written in column-major order.
  2. Let
    • x = rotation.x;
    • y = rotation.y;
    • z = rotation.z;
    • w = rotation.w;
    • x2 = x + x;
    • y2 = y + y;
    • z2 = z + z;
    • xx = x * x2;
    • xy = x * y2;
    • xz = x * z2;
    • yy = y * y2;
    • yz = y * z2;
    • zz = z * z2;
    • wx = w * x2;
    • wy = w * y2;
    • wz = w * z2;
  3. Let
    • M[0] = (1.0 - (yy + zz)) * scale.x;
    • M[1] = (xy + wz) * scale.x;
    • M[2] = (xz - wy) * scale.x;
    • M[3] = 0.0;
    • M[4] = (xy - wz) * scale.y;
    • M[5] = (1.0 - (xx + zz)) * scale.y;
    • M[6] = (yz + wx) * scale.y;
    • M[7] = 0.0;
    • M[8] = (xz + wy) * scale.z;
    • M[9] = (yz - wx) * scale.z;
    • M[10] = (1.0 - (xx + yy)) * scale.z;
    • M[11] = 0.0;
    • M[12] = translation.x;
    • M[13] = translation.y;
    • M[14] = translation.z;
    • M[15] = 1.0.

Questions

  • Should we separate obviously broken matrices (invalid last row or zero determinant) into a separate validation error?
  • Is infinity norm an appropriate metric to compare matrices for this use case?
  • What threshold should we have for it?

/cc @pjcozzi @javagl @bghgary @zellski @emackey @donmccurdy

Additional restrictions on alpha modes usage

From BabylonJS/Babylon.js#3155

shouldn't the 1.0 alpha in baseColor (absent either diffuse texture or vertex colour) essentially make BLEND meaningless?

Let's specify all valid combinations of material.alphaMode and alpha channel in

  • material.pbrMetallicRoughness.baseColorFactor
  • material.pbrMetallicRoughness.baseColorTexture
  • KHR_materials_pbrSpecularGlossiness.diffuseFactor
  • KHR_materials_pbrSpecularGlossiness.diffuseTexture

Proposal

  • OPAQUE: Texture shouldn't contain alpha channel and factor's alpha value should be 1.0.
  • MASK & BLEND: Texture should contain alpha channel or factor's alpha value shouldn't be 1.0.

Questions

  • When reporting on invalid assets, what should issue's pointer be? Whole material, material.alphaMode, or specific textures/factors?
  • What if MR material is OK, but SG isn't (or vice-versa)?
  • What about vertex color's alpha channel?

/cc @bghgary @zellski @sebavan

Accessor alignment should refer to the type, not only the componentType

The alignment constraints for accessors say

The offset of an accessor into a bufferView (i.e., accessor.byteOffset) and the offset of an accessor into a buffer (i.e., accessor.byteOffset + bufferView.byteOffset) must be a multiple of the size of the accessor's attribute type.

where "attribute type" is defined to be the size of the full type, e.g. for a 3D float vector, it's 3*4 bytes.

The error message that I just received was

"type": "ACCESSOR_TOTAL_MULTIPLE_COMPONENT_TYPE",
"path": "/accessors/positionsAccessor/byteOffset",
"message": "Accessor's total byteOffset `6` isn't a multiple of a componentType length `4`."

indicating that it only checks for the componentType.

(Maybe this could also be made clearer by rephrasing the statement about the "data type" in https://github.com/KhronosGroup/glTF/blob/master/specification/1.0/schema/accessor.schema.json#L19 , e.g. by replacing it with "attribute size" or any other more detailed description. I'll consider a PR for that, if this is OK)


Context: While validating the tutorial sample models for KhronosGroup/glTF-Sample-Models#16 , I noticed that some of them do not obey the constraints. I'm currently fixing them.

Fold similar issues

From #19 (comment)

It's just a case of potentially many errors being generated for a "tiny" mistake (i.e. a wrong max value). A single message like "There is a value of 5.5 at index 45, which is greater than the maximum of 1.0, and there are 48343 more values exceeding the maximum" could alleviate this.

Errors beget more errors

I think this is a common problem for compilers and such. Once a "real" error sends parsing off the rails, additional follow-on errors may not be on-target.

One example:

https://github.com/KhronosGroup/glTF-Sample-Models/blob/e6c0057a26f58c4f72cfa3b264ee0df281cc1a7b/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf#L29

Change "VEC3" to "VEC3x" and run the validator:

Invalid value 'VEC3x'. Valid values are...

Correct!

Invalid accessor format '{null, FLOAT}' for this attribute semantic. Must be one of ('{VEC3, FLOAT}').

Well, yes, this POSITION is invalid in that it references an invalid accessor, so, I guess this is OK, but it's not where the problem is.

accessor.min and accessor.max must be defined for POSITION attribute accessor.

No, min and max are certainly defined for this accessor.

Let's try another example:

https://github.com/KhronosGroup/glTF-Sample-Models/blob/e6c0057a26f58c4f72cfa3b264ee0df281cc1a7b/2.0/NormalTangentTest/glTF/NormalTangentTest.gltf#L22

Change "mesh": 0 to "mesh": 50.

Unresolved reference: 50.

Correct!

Empty node encountered.

No, the node contains only an invalid reference, but it's certainly not empty.

Experimenting with GLTF as a dependency - Error building release dart2js

Hello,

I'm learning to build a 'webgl' project of my own and use 'GLTF' as a dependency.
My project build correctly in debug with dartdevc but not in release with dart2js.

The base project 'gltf' project build correctly both in release with dartdevc and build with dart2j !!

Dart VM version: 2.0.0-dev.30.0 (Thu Feb 22 14:08:47 2018 +0100) on "windows_x64"

As said in dart-lang/sdk#32334

But after removing all aspects of mirrors in my project, I still have the problem, I definitively don't understand the real problem.

Here is my puspec.yaml:

name: 'webgl'
version: 0.0.5
description: Building a webgl API

environment:
  sdk: '>=2.0.0-dev.30.0 <2.0.0'

dependencies:
  browser: '^0.10.0+2'
  dart_to_js_script_rewriter: '^1.0.3'
  vector_math: '^2.0.5'
  gltf:
    path: ../gltf
#    git: git://github.com/KhronosGroup/glTF-Validator.git
  datgui: "^0.2.0+1"
  logging: "^0.11.3+1"
  stack_trace: "^1.8.2"

dev_dependencies:
  test: '>=0.12.0 <0.13.0'

transformers:
 - dart_to_js_script_rewriter
 - $dart2js:
     commandLineOptions: [--trust-primitives, --trust-type-annotations]

web:
  compiler:
    debug: dartdevc

and the error log:

C:\tools\dart-sdk\bin\pub.bat build --mode=release --output=build
Loading source assets...
Loading dart_to_js_script_rewriter transformers...
Building webgl...
[Info from Dart2JS]:
Compiling webgl|web/gltf/main.dart...
[Error from Dart2JS on webgl|web/gltf/main.dart]:
web\packages\gltf\src\base\gltf.dart:94:3:
Runtime type information not available for type_variable_local(toSafeList.T) in (parameter(fromMap#map), parameter(fromMap#context), BoxLocal(_box_0), ..., variable(fromMap#extensionsUsed), variable(fromMap#extensionsRequired)) for factory_constructor(Gltf#fromMap).
  factory Gltf.fromMap(Map<String, Object> map, Context context) {
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The compiler is broken.

When compiling the above element, the compiler crashed. It is not
possible to tell if this is caused by a problem in your program or
not. Regardless, the compiler should not crash.

The Dart team would greatly appreciate if you would take a moment to
report this problem at http://dartbug.com/new.

Please include the following information:

* the name and version of your operating system,

* the Dart SDK build number (build number could not be determined), and

* the entire message you see here (including the full stack trace
  below as well as the source location above).

Build error:
Transform Dart2JS on webgl|web/gltf/main.dart threw error: Assertion failure: Runtime type information not available for type_variable_local(toSafeList.T) in (parameter(fromMap#map), parameter(fromMap#context), BoxLocal(_box_0), ..., variable(fromMap#extensionsUsed), variable(fromMap#extensionsRequired)) for factory_constructor(Gltf#fromMap).
package:compiler_unsupported/src/diagnostics/invariant.dart 55            failedAt
package:compiler_unsupported/src/ssa/locals_handler.dart 328              LocalsHandler.readLocal
package:compiler_unsupported/src/ssa/builder.dart 1922                    SsaAstGraphBuilder.visitFunctionExpression.<fn>
package:compiler_unsupported/src/elements/common.dart 388                 ElementX&AstElementMixin&AnalyzableElementX&ClassElementCommon.forEachInstanceField.fieldFilter
package:compiler_unsupported/src/elements/common.dart 356                 ElementX&AstElementMixin&AnalyzableElementX&ClassElementCommon.forEachMember.<fn>
package:front_end/src/fasta/util/link_implementation.dart 124             LinkEntry.forEach
package:compiler_unsupported/src/elements/modelx.dart 2985                ClassElementX.forEachLocalMember
package:compiler_unsupported/src/elements/common.dart 356                 ElementX&AstElementMixin&AnalyzableElementX&ClassElementCommon.forEachMember
package:compiler_unsupported/src/elements/common.dart 392                 ElementX&AstElementMixin&AnalyzableElementX&ClassElementCommon.forEachInstanceField
package:compiler_unsupported/src/universe/codegen_world_builder.dart 605  ElementCodegenWorldBuilderImpl.forEachInstanceField
package:compiler_unsupported/src/ssa/builder.dart 1919                    SsaAstGraphBuilder.visitFunctionExpression
package:compiler_unsupported/src/tree/nodes.dart 1209                     FunctionExpression.accept
package:compiler_unsupported/src/ssa/builder.dart 1624                    SsaAstGraphBuilder.visit
package:compiler_unsupported/src/ssa/builder.dart 1933                    SsaAstGraphBuilder.visitFunctionDeclaration
package:compiler_unsupported/src/tree/nodes.dart 1127                     FunctionDeclaration.accept
package:compiler_unsupported/src/ssa/builder.dart 1624                    SsaAstGraphBuilder.visit
package:compiler_unsupported/src/ssa/builder.dart 1670                    SsaAstGraphBuilder.visitBlock
package:compiler_unsupported/src/tree/nodes.dart 980                      Block.accept
package:compiler_unsupported/src/ssa/builder.dart 769                     SsaAstGraphBuilder.buildMethod
package:compiler_unsupported/src/ssa/builder.dart 319                     SsaAstGraphBuilder.build
package:compiler_unsupported/src/ssa/builder.dart 114                     SsaAstBuilder.build.<fn>.<fn>
package:compiler_unsupported/src/compiler.dart 1156                       CompilerDiagnosticReporter.withCurrentElement
package:compiler_unsupported/src/ssa/builder.dart 105                     SsaAstBuilder.build.<fn>
package:compiler_unsupported/src/common/tasks.dart 63                     CompilerTask.measure
package:compiler_unsupported/src/ssa/builder.dart 99                      SsaAstBuilder.build
package:compiler_unsupported/src/ssa/ssa.dart 91                          SsaBuilderTask.build
package:compiler_unsupported/src/ssa/ssa.dart 43                          SsaFunctionCompiler.compile
package:compiler_unsupported/src/js_backend/backend.dart 846              JavaScriptBackend.codegen
package:compiler_unsupported/src/js_backend/element_strategy.dart 176     ElementCodegenWorkItem.run
package:compiler_unsupported/src/compiler.dart 784                        Compiler.emptyQueue.<fn>.<fn>.<fn>.<fn>.<fn>
package:compiler_unsupported/src/common/tasks.dart 178                    CompilerTask.measureSubtask
package:compiler_unsupported/src/compiler.dart 784                        Compiler.emptyQueue.<fn>.<fn>.<fn>.<fn>
package:compiler_unsupported/src/common/tasks.dart 178                    CompilerTask.measureSubtask
package:compiler_unsupported/src/compiler.dart 782                        Compiler.emptyQueue.<fn>.<fn>.<fn>
package:compiler_unsupported/src/compiler.dart 1156                       CompilerDiagnosticReporter.withCurrentElement
package:compiler_unsupported/src/compiler.dart 780                        Compiler.emptyQueue.<fn>.<fn>
package:compiler_unsupported/src/enqueue.dart 511                         EnqueuerStrategy.processWorkItem
package:compiler_unsupported/src/js_backend/enqueuer.dart 224             CodegenEnqueuer.forEach
package:compiler_unsupported/src/compiler.dart 776                        Compiler.emptyQueue.<fn>
package:compiler_unsupported/src/common/tasks.dart 178                    CompilerTask.measureSubtask
package:compiler_unsupported/src/compiler.dart 775                        Compiler.emptyQueue
package:compiler_unsupported/src/compiler.dart 797                        Compiler.processQueue.<fn>
package:compiler_unsupported/src/common/tasks.dart 178                    CompilerTask.measureSubtask
package:compiler_unsupported/src/compiler.dart 794                        Compiler.processQueue
package:compiler_unsupported/src/compiler.dart 640                        Compiler.compileLoadedLibraries.<fn>
package:compiler_unsupported/src/common/tasks.dart 178                    CompilerTask.measureSubtask
package:compiler_unsupported/src/compiler.dart 534                        Compiler.compileLoadedLibraries
package:compiler_unsupported/src/compiler.dart 488                        Compiler.runInternal
===== asynchronous gap ===========================
package:compiler_unsupported/src/compiler.dart 313                        Compiler.run.<fn>.<fn>
dart:async                                                                new Future.sync
package:compiler_unsupported/src/compiler.dart 313                        Compiler.run.<fn>
package:compiler_unsupported/src/common/tasks.dart 178                    CompilerTask.measureSubtask
package:compiler_unsupported/src/compiler.dart 310                        Compiler.run
package:compiler_unsupported/src/apiimpl.dart 265                         CompilerImpl.run.<fn>.<fn>
Build failed.

Thank you

TypeError in Firefox

In Firefox v56, before calling any methods on glTF-Validator, I see the following error:

TypeError: 'get window' called on an object that does not implement interface Window.

Validator is not initialized after that.

Code otherwise working as expected in Chrome and Safari.

Accessor min/max array element type does not have to match accessor component type

For an accessor that has int, short or byte components, which contains min/max elements with floating point numbers like

  "max" : [ 3.0 ],
  "min" : [ 0.0 ]

the validator currently emits an error:

        "type": "ARRAY_TYPE_MISMATCH",
        "path": "/accessors/indicesAccessor/min",
        "message": "Type mismatch. Array member `0.0` isn't a `integer`" 

Conceptually, this makes sense, of course.

But according to the spec ( https://github.com/KhronosGroup/glTF/blob/1.0.1/specification/schema/accessor.schema.json#L65 ), the element type is only a number (and not necessarily integer).

The gltf_detailedDescription and the spec text at https://github.com/KhronosGroup/glTF/tree/1.0.1/specification#accessormax-white_check_mark say something about floating point values, but not about integers. And in fact, I think it's impossible to define the "right" type here in the JSON schema.

Any ideas of how to resolve this?

(I'd suggest to downgrade this to a "warning", unless the type can be specified more strictly)

Catch explicit "null" values

Broken_Lantern.zip

The JSON inside this GLB file contains a snippet that says "byteOffset":null instead of "byteOffset":0 (due to a bug in conversion).

Can the validator be updated to catch this kind of mistake?

Errors when running in browser.

Steps to reproduce:

  1. Build a test script using validator:
// index.js
const validator = require('gltf-validator');
console.log(validator);
  1. Compile:
browserify index.js -o bundle.js
  1. Include in webpage:
<!DOCTYPE html>
<script src="bundle.js"></script>
  1. Error:
bundle.js:189 Uncaught ReferenceError: setImmediate is not defined
    at Object.<anonymous> (bundle.js:189)
    at Object.2._process (bundle.js:10039)
    at s (bundle.js:1)
    at bundle.js:1
    at Object.3../gltf_validator.dart.js (bundle.js:10057)
    at s (bundle.js:1)
    at bundle.js:1
    at Object.4.gltf-validator (bundle.js:10094)
    at s (bundle.js:1)
    at e (bundle.js:1)

Not sure what assumptions go into Dart's compilation process, but setImmediate is a function available to Node.js but not the browser.

Skins data validation

From the offline discussion, all skinning-related checks:

Scene Description Issues

  • Joints must have one or more common roots.
  • skeleton property, if used, must point to a common root.
  • When a node with a skinned mesh belongs to a scene, the joint tree must be available in the same scene.
  • Local and parent transforms on a node with a skinned mesh are ignored.

Data Issues:

  • IBM matrices don't have to be TRS-decomposable.
  • Joint indices must be valid (zeros allowed for zero-weight influences).
  • Linear sum of weights per vertex is 1.0 (across all influences).

Exception thrown from converted code

What's the best way to track down exceptions thrown from compiled Dart?

validationexception

In the above example, I've called validateBytes on a model (glTF/NormalTangentTest.gltf) that is known to validate correctly on the web-based validator. This is the 2.0.0-dev.1 npm version.

The variables a and z are undefined above. J is a catalog of minified functions.

spectacularly screwed-up glTF JSON yields validator stack trace

This is not urgent, but I'm throwing a lot of really terrible glTF at the validator, and it turns out if your JSON includes:

{
  "materials": [[ ]],
}

then the validator just breaks down and weeps:

Unhandled exception:
NoSuchMethodError: The method 'link' was called on null.
Receiver: null
Tried calling: link(Instance of 'Gltf', Instance of 'Context')
#0      Object.noSuchMethod (dart:core-patch/dart:core/object_patch.dart:46)
#1      new Gltf.fromMap.linkCollection.<anonymous closure> (package:gltf/src/base/gltf.dart:242:14)
#2      SafeList.forEachWithIndices (package:gltf/src/utils.dart:675:13)
#3      new Gltf.fromMap.linkCollection (package:gltf/src/base/gltf.dart:240:12)
#4      new Gltf.fromMap (package:gltf/src/base/gltf.dart:267:19)
#5      GltfJsonReader.read.<anonymous closure> (package:gltf/src/gltf_reader.dart:120:28)
#6      _SimpleCallbackSink.close (dart:convert/chunked_conversion.dart:58)
#7      _JsonUtf8DecoderSink.close (dart:convert-patch/dart:convert/convert_patch.dart:1817)
#8      GltfJsonReader._onDone (package:gltf/src/gltf_reader.dart:156:17)
#9      _RootZone.runGuarded (dart:async/zone.dart:1304)
#10     _BufferingStreamSubscription._sendDone.sendDone (dart:async/stream_impl.dart:383)
#11     _BufferingStreamSubscription._sendDone (dart:async/stream_impl.dart:393)
#12     _DelayedDone.perform (dart:async/stream_impl.dart:597)
#13     _StreamImplEvents.handleNext (dart:async/stream_impl.dart:694)
#14     _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:654)
#15     _microtaskLoop (dart:async/schedule_microtask.dart:41)
#16     _startMicrotaskLoop (dart:async/schedule_microtask.dart:50)
#17     _runPendingImmediateCallback (dart:isolate-patch/dart:isolate/isolate_patch.dart:112)
#18     _RawReceivePortImpl._handleMessage (dart:isolate-patch/dart:isolate/isolate_patch.dart:165)

Add API for "max number of returned messages"

Would be nice to have a limiting number passed into the API to provide an upper bound on the number of messages returned. If the app passes in 100 for example, and the validator discovers more than 100 combined errors and warnings, it can halt validation early and return the set it has so far, along with an additional validation message explaining that validation was halted and why.

Max issues throws exception

Just trying this in VSCode, looks like if the validator reaches the maxIssues it throws an internal exception now.

How to validate 2.0?

According to the glTF readme, this project supports validation of glTF 2.0. However, when I use master it looks like it is validating against version 1.0. For example, I get errors about lists not being objects and a count of programs used in the file. Also, as #13 points out, the readme for this project does not mention anything about 2.0.

I have used a branch called dev in the past that seemed to support 2.0, but I can no longer find it on this repository. Looking over the commits, it does not look like it was merged into master before disappearing.

This all leads me to my question of how can I use this tool to validate glTF 2.0 output?

Validation report more than 1,000,000+ issues and my browser cannot open it.

The size of validation reports has gotten way too large.

The validator reports every single normal that is not normalized for instance. I'm not sure what else is in the report yet since I cannot open it in my browser.

Instead the validator should say something like "accessor X has non-normalized normals. Found at index 0 (x,x,x), index 1(x,x,x) index 2(x,x,x) and 51,203 other indices."

I imagine there are some other types of checks that need their fat culled in too.

Publish to npm

Creating an issue from discussion elsewhere, can we publish transpiled JS for glTF validator to npm, so that pure-JS projects can depend on it?

"Animation channel cannot target TRS properties of node with defined matrix." Question

Hi Khronos team,

If glTF file with an animated node is used in glTF previewers that don't support animation that node will be rendered in the default scene position.
Assuming this limitation was added to optimize glTF file size, is there a design strategy in glTF development for file size and corner cases kinds of tradeoffs?

Thanks,
Miloš

Images data validation

Right now, Validator checks only that image dimensions are powers-of-two.

Next checks:

  • Detect when number of channels doesn't seem to match material usage (e.g., pure grayscale image used for Metal-Roughness texture).
  • Detect when image defines custom colorspace/gamma/intent.
  • Detect when image uses non-square pixels.
  • Detect EXIF Orientation flag in JPEG images.

Thoughts?

Can "MESH_PRIMITIVE_TOO_FEW_TEXCOORDS" not be treated as an error?

Hello!
I recently came across a model that was converted to glTF from BabylonJS. The model is able to render in BabylonJS and ThreeJS, but the glTF validator yields the MESH_PRIMITIVE_TOO_FEW_TEXCOORDS error when the model shares a material across multiple mesh primitives, but one does not actually use the textures:

i.e.

{
      "name": "material name",
      "doubleSided": true,
      "pbrMetallicRoughness": {
        "baseColorFactor": [
          0.5,
          0.5,
          0.5,
          1
        ],
        "metallicFactor": 0.1,
        "roughnessFactor": 0.4,
        "baseColorTexture": {
          "index": 0
        }
      }
    }
{
    "code": "MESH_PRIMITIVE_TOO_FEW_TEXCOORDS",
    "message": "Material is incompatible with mesh primitive: Texture binding '/materials/1/pbrMetallicRoughness/baseColorTexture' needs 'TEXCOORD_0' attribute.",
    "severity": 0,
    "pointer": "/meshes/99/primitives/0/material"
},

Is it possible to have this not treated as an error? It may cause false negatives for some models and could cause extra material duplication just to try to get rid of the errors.

Thanks!

Publishing issues

Had some trouble publishing this. From PowerShell:

PS D:\Git\glTF-Validator> pub run grinder npm-publish
grinder running [issues] [npm] [npm-publish]

[issues]
  Total number of issues: 116

[npm]
  E:\Downloads\Dart\dart-sdk\bin\dart2js.bat --no-source-maps --trust-type-annotations --trust-primitives --minify -obuild/npm/gltf_validator.dart.js tool/npm_template\node_wrapper.dart
  Compiled 4,512,080 characters Dart to 324,840 characters JavaScript in 4.99 seconds
  Dart file (tool\npm_template\node_wrapper.dart) compiled to JavaScript: build/npm/gltf_validator.dart.js
  deleting build/npm/gltf_validator.dart.js.deps
  copying package.json to build/npm/
  copying tool/npm_template\index.js to build/npm/
  copying tool/npm_template\README.md to build/npm/
  copying ISSUES.md to build/npm/
  copying LICENSE to build/npm/
  copying 3RD_PARTY to build/npm/
  copying docs\validation.schema.json to build/npm/

[npm-publish]
  npm publish

ProcessException: The system cannot find the file specified.

  Command: npm publish
#0      _ProcessImpl._runAndWait (dart:io-patch/process_patch.dart:473)
#1      _runNonInteractiveProcessSync (dart:io-patch/process_patch.dart:619)
#2      Process.runSync (dart:io-patch/process_patch.dart:66)
#3      run (package:grinder/src/run.dart:29:34)
#4      npmPublish (file:///D:/Git/glTF-Validator/tool/grind.dart:169:7)

After this I tried cd build/npm and then npm publish. That worked, but published the version number as 2.0.0-dev.1 which I don't think is correct.

https://www.npmjs.com/package/gltf-validator

Mesh data validation

Validator should be able to detect technical issues with mesh data such as degenerate or incomplete primitives. As of 55a9605, only degenerate triangles are reported.

Next possible features (in no particular order):

  • Index-based detection of degenerate primitives (all types except POINTS).
  • Index-based detection of duplicate primitives. It must be clockwise-aware.
  • Positions-based detection of duplicate/degenerate primitives. Must be optional because such validation could be slow and generate false positives (e.g., for meshes intended for further runtime processing).
  • Detection of duplicate vertices (i.e., exactly same values across all attributes).
  • Normals and tangents "correctness" (how to rigorously define this for all meshes?).

Thoughts?
@pjcozzi @bghgary @emackey @javagl @UX3D-nopper

Technique parameters with node specified fail validation if they are not FLOAT_MAT4

For example:
BoxSemantics.gltf.txt

nodeModelInverseTransposeMatrix is supposed to be FLOAT_MAT3 because it is MODELINVERSETRANSPOSE. I don't think this is expressly forbidden in the spec, but @lexaknyazev, you'd probably know better than I would.

On the other side of that, there's also nodeViewportMatrix which is VIEWPORT and a VEC4, which I'd say the validator is correct and that shouldn't be allowed.

Edit: I'm also not sure if this is a validator issue or something we shouldn't be doing that needs to be/is already being tightened up in the spec

Accessor Offset error message wrong?

While I'm not great at arithmetic, my calculator is pretty awesome: 7170 / 4 = 1792? Or is that not what this error message means?

{ "code": "ACCESSOR_TOTAL_OFFSET_ALIGNMENT", "message": "Accessor's total byteOffset 7170 isn't a multiple of componentType length 4.", "severity": 0, "pointer": "/accessors/1/byteOffset" },

glTF 2.0: Please remove warning for empty node.

First at all, thx a lot for this. The validator did help me to remove some errors and warnings. So back to this issue:

An empty node is valid in glTF 2.0. It is even mentioned on the specification site:
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes

At first, I wanted to suggest to convert this output from a warning to an optimization but I think even empty nodes do make sense, e.g. having an empty node, where in the 3D game engine a dynamic object like a weapon can be placed.

So, as it is valid, it should not cause any warnings.

"warnings": {
            "NODE_EMPTY": [
                {
                    "type": "NODE_EMPTY",
                    "path": "#/nodes/3",
                    "message": "Empty node encountered."
                }
            ]
        },

Consider making parts of API optional for easier adoption

The current usage example:

const fs = require("fs");
const path = require("path");
const validator = require('./index.js');

const filename = __dirname + '/Box.gltf';
const asset = fs.readFileSync(filename);

validator.validateBytes(filename, new Uint8Array(asset), (uri) =>
    new Promise((resolve, reject) => {
        uri = path.resolve(path.dirname(filename), uri);
        console.info("Loading external file: " + uri);
        fs.readFile(uri, (err, data) => {
            if (err) {
                console.error(err.toString());
                reject(err.toString());
                return;
            }
            resolve(data);
        });
    }),
    { 
        maxIssues: 10, // limit max number of output issues to 10
        ignoredIssues: [ 'UNSUPPORTED_EXTENSION' ], // mute UNSUPPORTED_EXTENSION issue
        severityOverrides: { 'ACCESSOR_INDEX_TRIANGLE_DEGENERATE': 0 } // treat degenerate triangles as errors 
    }
).then((result) => {
    // [result] will contain validation report in object form.
    // You can convert it to JSON to see its internal structure. 
    console.log(JSON.stringify(result, null, '  '));
}, (result) => {
    // Promise rejection means that validator was unable 
    // to detect file format (glTF or GLB) or has encountered an internal error. 
    // [result] will contain exception object.
    console.error(result.toString());
});

This feels a little verbose, and parts of it (especially the loadExternalResourceCallback function) will require some work for web developers to set up (multi-file drag and drop is painful on the web...). Is it still possible for the validator to run without additional resources? Also, is the filename required alongside the asset body? If so, I'd consider making some arguments optional, and simplifying the API as follows:

// Basic validation
validator.validateBytes(asset)
  .then((report) => console.log(report))
  .catch((error) => console.error(error));

// Validate with options
validator.validateBytes(asset, {maxIssues: 10})
  .then((report) => console.log(report))
  .catch((error) => console.error(error));

// Validate with options, including external resources
validator.validateBytes(asset, {
    maxIssues: 10,
    externalResourceCallback: (url) => {
      return new Promise((resolve, reject) => { ... });
    }
  })
  .then((report) => console.log(report))
  .catch((error) => console.error(error));

Validating asset source and saving validation state

To avoid full asset validation on each load and ensure asset's origin, we can use industry-standard PKI approaches.

Possible solution:
Binary glTF file (.glb) could be easily extended with PKI signature. Such signature could be added by trustworthy authority (e.g., Khronos-hosted web service) only if an asset passes the validation.

Runtimes could then check asset's signature instead of performing full data analysis.

Possible false positive?

This model came out of Paint 3D and was converted from GLB to glTF by the VSCode extension.

Bulldozer.zip

The validator reports an error on mesh_id7 NORMAL and POSITION saying:

bufferView.byteStride must be defined when two or more accessors use the same buffer view.

It flags accessors 3 and 5. But, those two accessors don't seem to use the same bufferView.

Is the model wrong, or the validator?

Inconsistent behavior of JS API

Buffers and images could be stored in JSON (base64), GLB, or in external files. As of 2.0.0-dev.1.4, when options.externalResourceFunction is not provided, the validator doesn't validate even GLB-BIN or base64 data. Otherwise, it validates as much as it can.

What do you think would be the best option here:

  • Always validate available binary data (so lack of that callback should affect only externally-stored resources).
  • Add a new flag to options to explicitly toggle binary data validation (false or true by default?).

/cc @emackey @donmccurdy @zellski

Spurious "MESH_PRIMITIVE_ACCESSOR_WITHOUT_BYTESTRIDE"?

Take Triangle.gltf and duplicate the mesh (producing this), then run it through the online validator. You get an error with the message

bufferView.byteStride must be defined when two or more accessors use the same buffer view.

But there are not two or more accessors which use the same buffer view.

Animation data validation

Right now, only a couple animation binary data checks are performed (in addition to accessor.count, type, and componentType):

  • Non-negative, strictly increasing input values.
  • Rotation quaternions must have unit length.

Next possible features:

  • Detect when interpolation between consequential quaternions may produce zero-length quaternion.
  • Detect that Catmull-Rom samplers have uniformly spaced input data.
  • Opinionated (maybe even mutually-exclusive) spacing issues, e.g.:
    • constant framerate violation;
    • unneeded frames (that could be removed without affecting interpolated values).

Thoughts?
@pjcozzi @bghgary @emackey @javagl @UX3D-nopper @donmccurdy

Upload button on online validator

I could really use an upload button on the online tool since I don't usually use a file browser with drag and drop support. As far as I know, I cannot currently use the online validator without installing another program. I understand that my configuration is uncommon, but I would really appreciate an upload button.

any plans for gcc?

Dart is not very common nowadays, I wonder if we plan to develop a gcc version of the validator, which will be easier to be ported at scale.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.