Today I installed JME 3.7 and tried to fire up UngaMunga. But it broke on loading the model I use for the globe complaining about not able to cast a child within to model to Geometry - in 3.6 that child was a Geometry.
It looks like the gltf/glb loader has changed the way it reads models.
Why is it doing this? I must say it has always been a mystery to me how to predict the model structure turns out when exporting glb’s from Blender. I was blaming Blender, because I had the same problem with JS Three and other platforms.
There is a limit to what you can do without any knowledge of the model. With the Blender conversion it is even unsure what names will be given to children of the model. The null_0 is absolutely random to me.
What I could do is write a function that iterates a model just to find the geometry-child I need. But this would work for single geometry models. But for loading performance I work a lot with models that hold different sub models that I need to pick out. If I can not trust them to have the same names as I gave them in Blender, I am bound to mess up.
Yes, the latest version of the engine has changed the gltf/glb file loading parser. It now introduces two parent nodes for each geometry and changes their names by adding a numeric suffix preceded by an underscore (e.g., from Cube to Cube_0).
This change could potentially break several previous applications.
I wasn’t very pleased with this update and suggested highlighting this new behavior in the release notes, but unfortunately, that didn’t happen.
Why does this happen with the geometries/nodes? Is it intentional or a bug? Seems completely pointless and as you said, may break applications. I’m still on 3.6 at the moment and now this makes me question whether I should update or not
The reason that you should not rely on the actual graph layout is that you are depending on 3 intermediate processes, 2 of them being 3rd party.
Blender (if you export your model with a different app, results might be different)
Blender Exporter (if the maintainer decides to change the exporting behavior)
Jme3 importer (As already happend)
At the point you want to store controls within your model you are going to use .j3o anyways, so might be good to make the swap as soon as possible. Write a robust importer that converts the model, makes the necessary changes, additions, tangents/binormals whatever, and save the model in jme’s format
Ah… I do use 3Jo in most cases. But only because people told me it is better. I would be very interested in learning more about the format and the conversion.
Between 3.6.1 and 3.7, a couple dozen changes were made to JME’s glTF importer. Most of these were attempts to solve known issues. At least one bugfix affected the structure of imported models. (I know because it affected Minie’s “candy dish” model.) Fixing bugs takes priority over preserving the importer’s outputs.
I wonder if this could be mitigating by making it easier to get a (recursive) child by name? That might make people less likely to rely on the graph structure in the future
Why are we adding _0 though? That seems unhelpful (I assume it’s for deduping but we could supress the 0th suffix)
I believe Node.getChild(String name) searches all children and not just immediate descendants. Also, there is SceneGraphIterator, which just got added.
If it does create unnecessary double nodes it sounds indeed strange. @capdevon stated it does, while @Fedor_van_Eldijk stated it does not. It would be helpful to have a screenshot from blender and a dump or whatever from jme so that we all can see what we are actually talking about
I agree the ‘_0’ suffix is unnecessary and it could be a major cause of backward compatibility problems.
Here is a possible solution for a frequent use case that I am sure many people will have used in their code:
replace this statement:
Node model = (Node) assetManager.loadModel("Models/YBot.gltf");
// v3.6.1-stable -> Alpha_Surface
Geometry body = (Geometry) model.getChild("Alpha_Surface");
with this statement:
Spatial model = assetManager.loadModel("Models/YBot.gltf");
// v3.7.0-stable -> Alpha_Surface_0
Geometry body = findGeom(model, "Alpha_Surface");
/**
* Recursively searches for a Geometry object within a Spatial hierarchy.
*
* @param spatial The root Spatial object to search.
* @param name The name or partial name of the Geometry to find.
* @return The found Geometry object, or null if not found.
*/
private Geometry findGeom(Spatial spatial, String name) {
if (spatial instanceof Node) {
for (Spatial child : ((Node) spatial).getChildren()){
Geometry result = findGeom(child, name);
if (result != null) {
return result;
}
}
} else if (spatial instanceof Geometry) {
if (spatial.getName().startsWith(name)) {
return (Geometry) spatial;
}
}
return null;
}