I’ve got a plane (modeled in 3dsMax and exported to obj) where each vertex corresponds to a probe in real life. Actual measurements of a vehicle are taken and each measurement is then applied to its corresponding vertex. This results in a deformed plane which fits the probed vehicle.
I use the vertex id’s to match the real-life measurement with the vertex. In 3dsMax this works great. However, in three.js, when using the OBJLoader2 (or FBXLoader for that matter) I can’t find any data which gives me access to the original index and order of vertices. Could somebody point me in the right direction?
I’ve tried using
mergeVertices() on a
THREE.Geometry derived form the imported
BufferGeometry but that changed my vertex order.
When loading with the
FBXLoader quite a bit of processing of vertices happens before they end up in the
BufferGeometry. Quads are split into triangles for example, since three.js doesn’t support quads.
So if your geometry in 3D max was modelled with quads then the order will certainly change, as will the number of vertices. The simplest way to ensure that you only have tris is to apply a “Turn to Poly” modifier in Max before you export and limit polygon size to 3.
Once you’ve done this, it should be much easier to work out which vertices match to the original 3ds max vertices. Try exporting a single triangle or plane made of two triangles using this method and you should see what’s happening.
Hi @klaasnienhuis, welcome to the forum!
I would try using GLTF loader instead if possible. You might see better results.
As a general note - relying on vertex ID might not be a good idea, there are many ways why you might want to change vertex index, here are a few:
- Mesh simplification (LOD for example, or removal of duplicate vertices)
- GPU cache optimization
- Splitting a large mesh into several fragments for performance reasons
Hi @looeee and @Usnul, thanks for your prompt replies. I’m testing now mainly with obj and OBJLoader2, just because it’s easier to inspect the obj file in notepad and comparing it to the output in my console. But fbx and gltf gave me the same results.
I’ve made sure to only export triangles and I’ve followed @looeee’s advice to export a simple plane, made of 2 triangles. In my obj file, I’ve got 4 verts and two triangles.
0 0 0 5 0 0 0 0 -10 5 0 -10
The imported obj has a buffergeometry with 6 verts (3 for each face, where two pairs of verts overlap)
0 0 -10 0 0 0 5 0 -10 5 0 0 5 0 -10 0 0 0
When I convert the buffergeometry into geometry and call
mergeVertices() I end up with 4 verts again
0 0 -10 0 0 0 5 0 -10 5 0 0
As you can see, these merged verts have a different order than the input file.
The considerations of @Usnul against using vertex ID’s are all valid. However, my use case relies on them. I’ve got about 30 verts, and each vert has a position which corresponds to the position of a measurement of a physical object. I get a list of indexed measurements, and each measurement neatly matches with a vert. Using vertex ID’s seemed to be the obvious choice.
If there’s another way to match verts from my source file to verts in three’js I’m all ears.
I’m testing now mainly with obj
What about exporting ASCII FBX? You can check that easily in a text editor too.
I’ve now tested with ascii fbx and gltf as well. The results of these tests is, the same. The only difference between the formats is how they deal with switching certain axes.
It boils down to the following:
- The source file contains faces which share vertices
- The source file stores a shared vert only once, mirroring the source geometry in 3ds Max exactly
- The order of vertices in the source file matches the vert id’s in 3ds Max (checked with obj and ascii fbx)
- Importing in three.js produces buffergeometry which separates the faces from each other
- This duplicates the shared verts and inserts them somewhere in the positions list. The vertex ID’s are now lost
mergeVertices()on derived geometry brings back the original number of verts, but understandably can’t reproduce the original order of them
loader.setUseIndices(true) with the OBJLoader2 does give me the right amount of verts from the start, but their order is garbled.
Even when I have only separated triangles in my obj file, the loading procedure shuffles the order.
The culprit is the automatic “conversion” to buffergeometry upon import. That messes with the vertex order. I’ve read a lot about the advantages of buffergeometry, but this is a clear disadvantage for me.
I would suggest making your own loader of the ascii format. That way you keep control, and it is not that complicated.
I don’t doubt that your usecase is valid. The tooling is generally not geared towards that though, it’s mostly about the look and not the underlying data. Which make what you are doing kind of hard. I would lean on what @yombo is saying, if you can dump the data into JSON or something equally easy to parse and then just load it yourself - it might save you a great deal of trouble.
@yombo, @Usnul, that’s what I’m doing right now. And like Yombo says, it’s not that hard in the end. I would have saved myself some time if I just went with that from the beginning.
Question: I’ve done a similar project with clara.io: loading an fbx, finding verts by ID. With clara.io it works. Clara.io is built on top of three.js. Does anybody know if they have a particularly sophisticated geometry importer or is it because they don’t use the latest three version?
I think it would be possible to patch the FBXLoader so that it keeps the vertex ordering, although I agree that writing a custom loader is going to be the simpest solution here.
FBX format allows multiple indexes (i.e. one index for faces, one of UVs, another for skin weights and so on). However, in WebGL we are limited to a single index. If we have an indexed geo then all attributes use that single index.
The simplest approach was to just remove all indices and output a non-index geometry. When doing this, the order of the vertices is getting messed up, since it’s not something I paid attention to when writing that part of the loader.
But it should be possible to refactor the loader to keep vertex ordering. My memory of this is a bit rusty since it’s quite a while since I looked at that part of the code, but I think that there are only two vertex orderings that worked, and I must have picked the wrong one. If that’s the case, sorry about that!
Does anybody know if they have a particularly sophisticated geometry importer or is it because they don’t use the latest three version?
As far as I know, they use their own custom loader.