vpenades / SharpGLTF

glTF reader and writer for .NET Standard
MIT License
470 stars 75 forks source link

Make error message more explicit ? #31

Closed courgeon closed 4 years ago

courgeon commented 4 years ago

Hello, First, thank you for this library which is great. I have run into an error that I don't know how to tackle :

I'm building a "complicated" scene and exporting it to GLTF/GLB. Most of the time it works great, but some scene will generate a SemanticException:

SharpGLTF.Validation.SemanticException: Mesh[78] Count
SharpGLTF.IO.ReadContext._ReadFromDictionary(String fileName) in \\SharpGLTF.Core\\IO\\ReadContext.cs:line 147
SharpGLTF.IO.WriteContext._PreprocessSchema2(ModelRoot model, Boolean imagesAsBufferViews, Boolean mergeBuffers) in SharpGLTF.Core\\IO\\WriteContext.cs:line 229
SharpGLTF.IO.WriteContext.WriteBinarySchema2(String baseName, ModelRoot model) in SharpGLTF.Core\\IO\\WriteContext.cs:line 181

I cannot figure out what is wrong in my scene, and the exception message is really not helping.

FYI, I recompiled the library with .Net Framework 4.7.2 (needed for my project) It does work in most case, so I'm not sure that it matters.

M.

courgeon commented 4 years ago

Ha, I figured it out

I generated a mesh with no primitive, the validation process fails because of the morph target check :


protected override void OnValidate(Validation.ValidationContext result)
        {
            base.OnValidate(result);

            foreach (var p in this.Primitives) p.Validate(result);

            var morphTargetsCount = this.Primitives
                .Select(item => item.MorphTargetsCount)
                .Distinct();

            if (**morphTargetsCount.Count()** != 1) result.AddSemanticError("Count", "All primitives must have the same number of morph targets.");

            if (_weights.Count != 0 && morphTargetsCount.First() != _weights.Count) result.AddSemanticError("Weights", $"The length of weights array ({_weights.Count}) does not match the number of morph targets({morphTargetsCount.First()}).");
        }
vpenades commented 4 years ago

Hi, I'm glad you like the library.

The library should work fine in .Net 4.7.2 as well as Net Core, since it targets NetStandard 2.0.

Which version of the library are you using?

To build you scene, are you using the Toolkit SceneBuilder and MeshBuilder? or are you using the Core library? ... I always recomend using the Toolkit because it automatically optimizes the model.

Indeed, I think a mesh with no primitives is considered an error (it's basically a waste of resources), but it should provide better errors.

courgeon commented 4 years ago

Hey, I think I'm using the low level Core API : basically, i'm doing this. I also use materials, but you get the idea.

var model = ModelRoot.CreateModel();
var scene = model.UseScene("Scene");
var root = scene.CreateNode();
var mesh = model.CreateMesh(name);
var prim = mesh.CreatePrimitive();
prim.DrawPrimitiveType = primitive.type;
prim.WithVertexAccessor("POSITION", vertices);
prim.WithIndicesAccessor(primitive.type, indices);
model.SaveGLB(output);
vpenades commented 4 years ago

It is fine to use the Core API, since, after all, it generates valid glTF files.

The alternate way of filling a glTF file is by using the Toolkit, and its MeshBuilder and SceneBuilder components. The advantage of using these components is that it can pre-optimize the data before writing it to glTF.

Among other things, it will merge all compatible buffers, which reduces the number of drawing render states.

But in the end, it's just two different ways of doing things.

courgeon commented 4 years ago

I can give it a try. I'm always looking for optimisation. Do you have a sample code somewhere ?

If you are interrested, I could write a small tutorial on how to generate GTLF files with your API using the two methods.

vpenades commented 4 years ago

The unit test file is full of examples, and it also servers as a tutorial of sorts.

You can see an example of creating a triangle with meshbuilder/scene builder here:

https://github.com/vpenades/SharpGLTF/blob/cf494d835ea767d8da80f734a53490feeaab8ccd/tests/SharpGLTF.Tests/Scenes/SceneBuilderTests.cs#L41