How to load a GTLF file with unique Mesh, not with InstancedMesh

When I load a GLTF file it creates meshes of type Mesh and InstancedMesh. Problem is that I can not change the color of the InstancedMesh, because I can not assign a new material to it.

Is there a way to load a gltf file that does not create InstancedMesh but only unique Meshes?

Thanks

Super lame your having this much trouble with this topic. GTLF is a pain sometimes it seemsā€¦

Have you tried just grabbing the buffer data and initializing it manually in a clean AbstractMesh just as a work around for now?

Pinging @bghgary. I guess we can introduce a flag for that.

In the meantime, you can replace the instanceMesh by a clone of instanceMesh.sourceMesh

Seems linked to this other topic: How to replace InstancedMesh with a Mesh

Please refrain from posting several topic on same subject

1 Like

Yup, I can add a flag for that easily.

Thanks. I will. I kind of though they were two different topics. On is GLTF related and the other is not, but they could both solve a current scenario I have.

What would be really powerful is to be able to plug into the load and decide for my case if the mesh should be instancedmesh or not.

On my scene meshes are responding to a point of the mouse and there are about 500-1000 InstancedMesh(s). When the user points at one I must highlight 18 of them, then when he points at a second I must highlight a group of 743 of them and when he points a third I must highlight about 200 of them.

So it would be useful to be able to ā€œconfigureā€ which meshes are instanced and which are not. Of course this might prove unneeded If I manage to get the buffers working.

But I would really like to use the HighlightLayer for this and for the HighlightLayer I am not sure what the approach should be.

Are these group of instanced meshes static? It seems like the glTF can be authored such that the instances are created properly if you point each group of nodes to the same mesh and then duplicate the mesh for other groups.

No. They are not static. There are animations attached to them.

I tried duplicating all the InstancedMesh with a clone of the source original Mesh. But when there is an animation using the InstancedMesh, the animation is not animating the new cloned Mesh

Thatā€™s not what I mean by static. My question is whether the grouping of the meshes are static (i.e. the instanced meshes donā€™t need to change each time you load the glTF).

Assuming the grouping is static, you should be able to change the source glTF file and make the instancing grouped in a way that works.

Yes they are static in that sence. They do not need to change each time for the same docuemnt. They should be the same each time.

But gltfs are coming in from different sources and different exporters and different authors.

How do you decide how to group meshes? Maybe you can explain your scenario a bit more.

BTW, Iā€™ve added a flag to the loader that allows you to disable instancing.
https://github.com/BabylonJS/Babylon.js/blob/master/loaders/src/glTF/glTFFileLoader.ts#L210-L213

Thanks for the option. I will try it.

I donā€™t decide. The content creator decides and there are many of them.

I just receive a gltf and when the gltf(that could be exported from many different exporters) is displayed on the scene the user should click with the mouse and select the mesh. This selection means - highlight, blink, renderOverlay, renderOutline and many other things that are not supported by InstancedMesh.

So i donā€™t know which one is instanced and which is not. But we should be able to select a mesh.

Thinking about it today, the content creators might have created instances or might have not. So it will be a good feature when a GLTF is received to be able to decide how to group them to optimize the scene.

I donā€™t see how having the ability to decide how to group the instances on load helps with your scenario. Can you explain this part?

Bolts. Threaded bolts

We recently had to load a scene with a bunch of bolts. And because of the details of the threads they are taking a lot of meshes. 3 billion triangles. And they come with a gltf that has no instances. About 700MB. Why, I donā€™t know. But I could optimize them. If one rotation of the bolt is created as a mesh and the others are instancedmesh probably there would be some importance improvements. (Although I am skeptical since I have not found data that compare the performance of mesh to instancedmesh to further understand the scenario)

Are you saying you will optimize the glTF before loading it or optimize it after/during loading? As you pointed out, once you use instances, the highlight layer wonā€™t work.

I understand you have unknown / possibly non-optimal input sources. How will you decide how to group the instances if the scenario is that users need to select arbitrary meshes? How does doing this on load help you? Iā€™m just trying to understand the scenario.

I decided not to use highlight layer because of the instancedMesh. I am trying to highlight by drawing a new lines mesh around the object and enabling edges rendering.

But for the optimization.

As users are uploading arbitrary gltfs my options are:
0. leave it to the users to optimize them, which they may or may not do.

  1. try to optimize them on the server with some python gltf library,
  2. try to optimize them in browser and then save the optimized copy to be delivered to the next clients.
    Ideally I would prefer to have one code base, and since I already have a viewer in the browser, probably I could do the optimization in the browser.

A threaded bolt is a repeating pattern. Each cycle repeats for about 20 times. And each cycle could consists of hundreds of thousands of vertexes. Even millions. Who needs this level of detail - nobody. But content creators often lack the tools to optimize the gltfs or have legacy project which when converted to gltf produce this results. We all agree they should be removed, but they should not be removed by hand, but rather automatically.

Theoretically I could have a few vertexes that describe 1 degree of the cycle and this could be repeated 360 times. Given that there are about 40-50 bolts on the scene if I have 1 mesh for the 1 degree of the cycle of the threaded bolt and InstancedMesh for the other 359 than it is ā€˜20x360x50 times optimizedā€™

How exactly am I going to find the pattern I still donā€™t know, but I can handle the math. What I probably need in this case from a GLTF.Loader is to get the opportunity to run a check on a ā€˜raw geometry nodeā€™, before it is created as a mesh and decided if this ā€˜raw geometry nodeā€™ should be in one large mesh, or one mesh and a lot of instancedmesh. In this way when there is a 20MB node to be loaded that is a threaded bolt I could load only one degree mesh in the memory and hundreds of thousands of instancedmesh that are offset by position and rotation. This, as far as I understood Babylon InstancedMesh in the last two days should take a lot less memory and should render a lot faster.

While writing this I was looking at GLTFLoader - Babylon.js Documentation. And also at Use the glTF File Loader Plugin - Babylon.js Documentation

I think the onMeshLoaded could do be used for this. Load the whole Mesh and then create many InstancedMeshes and dispose of the unneeded Mesh. Would this work?

The last scene I received contained about 40 bolts and was about 700 MB.

Optimizing your glTF assets should be done before loading the model, on the server or client like you say. The glTF loader in Babylon is intended to load the asset into a renderable state as quickly as possible. It is not intended to do these kinds of optimizations on the fly.

Possibly, but I donā€™t recommend doing this.

How is the option supposed to be passed .The documentation at Load from any file type - glTF, OBJ, STL, etc. - Babylon.js Documentation says

var loader = BABYLON.SceneLoader.Load("./", "duck.gltf", engine, function (scene) {
    // do something with the scene
});

// do something with the loader
// loader.<option1> = <...>
// loader.<option2> = <...>
// loader.dispose();

So I am doing:

var loader = BABYLON.SceneLoader.Load("/assets/", "map.gltf", engine, function (scene) {
 ... do something with the scene
});
loader.createInstances = false;// how is this here passed after the creation?
loader.dispose();

Is this the way the option should be passed?

Yes, this is correct. The loading process is asynchronous, so setting options afterwards will still work. I agree, it is strange looking.

EDIT: Donā€™t dispose the loader. It will dispose itself when the loading is complete.

EDIT2: Iā€™ll update the docs.