vpenades / SharpGLTF

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

Hello there! Is there an API interface for successfully merging multiple gltf or glb files into one file? #79

Closed lz852153492 closed 3 years ago

lz852153492 commented 3 years ago

Hello there! Is there an API interface for successfully merging multiple gltf or glb files into one file? I have tried to convert to MODEL and then merge, but unfortunately it failed

vpenades commented 3 years ago

try this code and let me know if it works for you:

var terrain = SceneBuilder.Load("terrain.glb");
var boat = SceneBuilder.Load("boat.glb");

var merged = new SceneBuilder();
merged.AddScene(terrain, Matrix4x4.Identity);
merged.AddScene(boat, Matrix4x4.CreateFromTranslation(50,30,0) );

merged.ToGltf2().Save("merged.glb");
lz852153492 commented 3 years ago

Sorry, this code is not suitable, MATRIX4X4.CreateFromTranslation was not found.

lz852153492 commented 3 years ago

I can’t find MATRIX4X4.CreateFromTranslation in the latest code base. Is there an update in the code base?

vpenades commented 3 years ago

Matrix4x4 is System.Numerics.Matrix4x4

lz852153492 commented 3 years ago

Sorry, I mean there is no MATRIX4X4.CreateFromTranslation method, I think you might want to use the MATRIX4X4.CreateTranslation method, right?

lz852153492 commented 3 years ago

Thank you, but your code is still not suitable, ToSchema2 needs to provide corresponding actual parameters

vpenades commented 3 years ago

Sorry, the example is from an older version:

Use to ToGltf2 instead of ToSchema2

lz852153492 commented 3 years ago

Hello there! Using the modified code, you can merge but there are some errors, such as the position of some pictures changed

lz852153492 commented 3 years ago

Can I add my own attribute values to extensions under Meshes? I tried to add and found that it seems to be read-only

vpenades commented 3 years ago

by Attributes, you mean, vertex attributes? it is not possible to add a new vertex attribute to an existing mesh, but it is possible to create a new one, and copy the data from the previous mesh to the new mesh,

lz852153492 commented 3 years ago

Sorry, I did not express it clearly, I mean I want to add our custom attributes to the "extensions" under "Meshes", the final structure may be: "meshes" : [{ "name" : "test", "primitives" : [{ "attributes" : { "indices" : 0, "material" : 0 } } ], "extensions" : { “digihail” : { "id" : "C5A80287", "children" : [{}], "isCatingShadow" : false } } } ] "extensions" is our custom.

vpenades commented 3 years ago

Ah, a custom extension...

Short answer:

Right now custom (user) extensions are not supported.

Long answer:

Extensions need to be registered into SharpGLTF library before loading/saving a model:

namespace SharpGLTF.Schema2
{
    static class ExtensionsFactory
    {
        public static void RegisterExtension<TParent, TExtension>(string persistentName);
    }
}

Notice that this is a PRIVATE method that is meant to be used internally by the library. Public extensions support is something that I need to review extensively before making it public, and I don't plan to support it any time soon.

The reason is because in practice most extensions require additional work around the library and it's not enough to simply register them.

If you are in a hurry, or you absolutely need this feature, there's a number of options you have:

Writing your own extension and registering it is unsupported and undocumented, you'll have to dig into the code and see how other extensions are registered and used.

If your extension just stores data and it doesn't affect the document in any way, an alternative is to use the Extras field.

lz852153492 commented 3 years ago

Thank you, we adopted your suggestion. Use the "Extras" field to store data. Now we need to add our data after the "Extras" field has data. Any suggestions?

vpenades commented 3 years ago

As a matter of fact, I've been refactoring how to add custom content to Extras, so from Alpha20 to Alpha21 there will be a breaking change. So depending if you're using the latest development branch or the Alpha20 nuget, the way of writing Extras is different.

Both version boil down to creating a Dictionary<string,Object> and assigning it to the Extras properties. In what they differ is in the way of adding the dictionary to the extras.

The breaking change is required because in future versions I would like to add direct object serialization support... but that's still WIP... so for now the safest approach is to use Dictionaries and Lists.

lz852153492 commented 3 years ago

Our needs have been perfectly solved, thank you very much! Congratulations on your results getting better and better.

lz852153492 commented 3 years ago

Hello there! We want to take out the relevant data of a "name: Test" from the "Mashes" in a glb file, this data includes other attributes such as: "Nodes", etc., and then add it to another glb file, in order to achieve , I may need to traverse all the relevant data of "name: Test", then take it out, and assign it to the matching attribute of another glb file. Is there a better solution or interface implementation, such as automatically extracting all of the specified name in the glb file Attribute data

vpenades commented 3 years ago

if you want to add only a part of a model to another model, with the current API, I would do this:

var terrain = SceneBuilder.Load("terrain.glb");
var boat = SceneBuilder.Load("boat.glb");

// filter out the parts you don't want
foreach(var instance in boat.Instances.ToArray())
{
    if (instance.Name.StartsWith("Test")) instance.Remove();  // remove this instance from the boat scene.
}

var merged = new SceneBuilder();
merged.AddScene(terrain, Matrix4x4.Identity);
merged.AddScene(boat, Matrix4x4.CreateFromTranslation(50,30,0) );

merged.ToGltf2().Save("merged.glb");

Or, you can look at the "AddScene" and see how it works, so you can write a custom version of it.

lz852153492 commented 3 years ago

Hello there! Is there a way to increase the running speed of SceneBuilder.Load? For 8M files, it takes more than 1 minute to run once

vpenades commented 3 years ago

Most of the load time is expended in model validation. If you trust the model is correct, you can disable validation on load.

var model = ModelRoot.Load(f, SharpGLTF.Validation.ValidationMode.Skip);
lz852153492 commented 3 years ago

GLB files are merged using SceneBuilder.Load, can it be achieved by replacing it with ModelRoot.Load?

vpenades commented 3 years ago

GLB files are merged using SceneBuilder.Load, can it be achieved by replacing it with ModelRoot.Load?

Yes, ValidationMode implicitly converts to settings.

lz852153492 commented 3 years ago

Sorry, I didn’t understand what you mean, this is the code I replaced, but it’s wrong `var terrain = ModelRoot.Load("terrain.glb"); var boat = ModelRoot.Load("boat.glb");

var merged = new SceneBuilder(); merged.AddScene(terrain, Matrix4x4.Identity); merged.AddScene(boat, Matrix4x4.CreateFromTranslation(50,30,0) );

merged.ToGltf2().Save("merged.glb");`

vpenades commented 3 years ago

ModelRoot.Load("terrain.glb", SharpGLTF.Validation.ValidationMode.Skip);

SceneBuilder's Load also works in the same way.

lz852153492 commented 3 years ago

` var terrain = ModelRoot.Load("terrain.glb", SharpGLTF.Validation.ValidationMode.Skip); var boat = ModelRoot.Load("boat.glb", SharpGLTF.Validation.ValidationMode.Skip);

var merged = new SceneBuilder(); merged.AddScene(terrain, Matrix4x4.Identity); merged.AddScene(boat, Matrix4x4.CreateFromTranslation(50,30,0) );

merged.ToGltf2().Save("merged.glb"); ` At merged.AddScene(terrain, Matrix4x4.Identity), an error is prompted, and the error content is as follows: Cannot convert from "SharpGLTF.Schema2.ModelRoot" to "SharpGLTF.Scenes.SceneBuilder" ;

I tried before: SceneBuilder sceneBuilder = terrain.DefaultScene.ToSceneBuilder(); But this piece of code does not increase the speed, and the running time is still more than 1 minute.

vpenades commented 3 years ago

you can also apply the skip when saving:

merged.ToGltf2().Save("merged.glb", SharpGLTF.Validation.ValidationMode.Skip);

Also, keep in mind that all the steps involved are computationally expensive:

Except validation, all these steps are needed, and depending on the complexity of the model, it can take its time.