[SOLVED] Getting the names of objects (not meshes) into jME

I’m using Blender to make my game world and then use gltf to export my world for usage inside jME. In Blender all my objects have names but it seems that I can’t find a way to actually get those names in jME. The mesh names are fine. Those are properly loaded but not the object names.

For now the only solution I found is to manually use custom data in Blender and then use an ExtrasLoader implementation to fetch those and assign them to my game objects. But that requires me to set custom data in Blender which is annoying. It would be much easier if I could use the blender object name automatically.

Is there a way to make this easier? Thanks

2 Likes

Hi,

Afaik mesh has no name in JME, so the plugin assign mesh names to Geometry. Object in blender has no equivalent in JME/Gltf (?) so it ignores the object name.

Edit:
By the way, this is a restriction on the Blender Gltf plugin so we probably can not do much about it in JME.

1 Like

Actually the object names ARE in the gltf. Here is an example:

    {
        "extras" : {
            "logic" : "doorInside"
        },
        "mesh" : 18,
        "name" : "D10_sto",
        "rotation" : [
            0,
            0.7071067094802856,
            0,
            -0.7071068286895752
        ],
        "translation" : [
            -18.39000129699707,
            0,
            38.20000076293945
        ]
    },

The D10_sto is the name I’d like to get in jME. It’s really unfortunate that jME doesn’t allow objects to have names because that’s something that’s so useful for game objects. But anyway, since the data is in the gltf it should be able to get it out but I haven’t been able to figure out how

1 Like

Oh actually. I found the name. In the ExtrasLoader I can go to the parent (which is a node) and in that parent the desired object name can be found. It’s just not used by the loader but I can extract it from there and store it in my own datastructure. So problem solved

3 Likes

Glad you solved it. :slightly_smiling_face:

Marked the thread as solved.

2 Likes

Sorry to necro the thread, but I’ve also ran into this issue. I would argue it makes more sense to name the Geometry the same as the gltf “node” rather than the mesh. Gltf nodes and Jmonkey Geometries have a direct relationship in that they both represent unique objects in the scenegraph. Multiple gltf nodes can share a single mesh, which makes the resulting geometries all have the same name.

This can be changed easily by replacing the line

spatial.setName(readMeshName(meshIndex));

with

spatial.setName(nodes.get("name").getAsString());
*edit* This ^ is wrong.  Oops!  Actually it should be:
spatial.setName(getAsString(nodeData, "name"));

in GltfLoader.readNode(int nodeIndex)

I can make a pull request if there’s interest. Would be a potentially breaking change for some people’s code though.

Otherwise, for anyone else looking for a solution, I just subclassed GltfLoader.

public class FixedGltfLoader extends GltfLoader
{
	private Field nodesField;

	private JsonArray getNodesFromSuperclass()
	{
		if(nodesField == null)
		{
			try
			{
				nodesField = GltfLoader.class.getDeclaredField("nodes");
				nodesField.setAccessible(true);
			} catch(NoSuchFieldException e)
			{
				Console.log("NoSuchFieldException in FixedGltfLoader", Console.LogType.ERROR);
				System.exit(99);
			}
		}

		try
		{
			return (JsonArray) nodesField.get(this);
		} catch(IllegalAccessException e)
		{
			Console.log("IllegalAccessException in FixedGltfLoader");
			System.exit(99);
			return null;	//obviously will never run, but to keep the compiler happy...
		}
	}

	@Override
	public Object readNode(int nodeIndex) throws IOException
	{
		Object o = super.readNode(nodeIndex);

		if(!(o instanceof Geometry))
			return o;

		JsonObject nodeData = getNodesFromSuperclass().get(nodeIndex).getAsJsonObject();

		((Geometry) o).setName(nodeData.get("name").getAsString());

		return o;
	}
}

And replaced the default one in the AssetManager with

assetManager.unregisterLoader(GltfLoader.class);
assetManager.registerLoader(FixedGltfLoader.class, "gltf");

For glb files, I just copy-pasted GlbLoader.java and changed “extends GltfLoader” to “extends FixedGltfLoader”

This seems to be working all through my game, but I just wrote it, so I’ll update this post if I find any problems down the line.

4 Likes

Yes, makes sense to me. Would you like to submit a PR?

I made a sample gltf file in Blender, would be nice if you could try it in JME and let us know how the naming looks before and after your change.

Both Cube-Object-1 and Cube-Object-2 share the same mesh.

Here is the gltf file content:

{
    "asset" : {
        "generator" : "Khronos glTF Blender I/O v3.4.50",
        "version" : "2.0"
    },
    "scene" : 0,
    "scenes" : [
        {
            "name" : "Scene",
            "nodes" : [
                2
            ]
        }
    ],
    "nodes" : [
        {
            "mesh" : 0,
            "name" : "Cube-Object-1",
            "translation" : [
                2.0781643390655518,
                1.3325393199920654,
                0
            ]
        },
        {
            "mesh" : 0,
            "name" : "Cube-Object-2",
            "translation" : [
                2.0781643390655518,
                -2.543614625930786,
                0
            ]
        },
        {
            "children" : [
                0,
                1
            ],
            "name" : "Cube-Node",
            "translation" : [
                -2.0781643390655518,
                0,
                0
            ]
        }
    ],
    "meshes" : [
        {
            "name" : "Cube-Mesh",
            "primitives" : [
                {
                    "attributes" : {
                        "POSITION" : 0,
                        "TEXCOORD_0" : 1,
                        "NORMAL" : 2
                    },
                    "indices" : 3
                }
            ]
        }
    ],
    "accessors" : [
        {
            "bufferView" : 0,
            "componentType" : 5126,
            "count" : 24,
            "max" : [
                1,
                1,
                1
            ],
            "min" : [
                -1,
                -1,
                -1
            ],
            "type" : "VEC3"
        },
        {
            "bufferView" : 1,
            "componentType" : 5126,
            "count" : 24,
            "type" : "VEC2"
        },
        {
            "bufferView" : 2,
            "componentType" : 5126,
            "count" : 24,
            "type" : "VEC3"
        },
        {
            "bufferView" : 3,
            "componentType" : 5123,
            "count" : 36,
            "type" : "SCALAR"
        }
    ],
    "bufferViews" : [
        {
            "buffer" : 0,
            "byteLength" : 288,
            "byteOffset" : 0,
            "target" : 34962
        },
        {
            "buffer" : 0,
            "byteLength" : 192,
            "byteOffset" : 288,
            "target" : 34962
        },
        {
            "buffer" : 0,
            "byteLength" : 288,
            "byteOffset" : 480,
            "target" : 34962
        },
        {
            "buffer" : 0,
            "byteLength" : 72,
            "byteOffset" : 768,
            "target" : 34963
        }
    ],
    "buffers" : [
        {
            "byteLength" : 840,
            "uri" : "data:application/octet-stream;base64,AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AAAAPgAAgD4AAMA+AAAAAAAAwD4AAIA/AAAgPwAAAAAAACA/AACAPwAAYD8AAIA+AAAAPgAAAD8AAMA+AABAPwAAwD4AAEA/AAAgPwAAQD8AACA/AABAPwAAYD8AAAA/AADAPgAAgD4AAMA+AACAPgAAwD4AAIA+AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AADAPgAAAD8AAMA+AAAAPwAAwD4AAAA/AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAvwAAAAAAAACAAAAAAAAAAAAAAIA/AACAvwAAAAAAAACAAAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAPwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAgAEAAkAAgAJAAcACAAKABUACAAVABMAFAAXABEAFAARAA4ADQAPAAMADQADAAEABgASAAwABgAMAAAAFgALAAUAFgAFABAA"
        }
    ]
}

1 Like

Sure! Here’s a little test

Node testScene = (Node) assetManager.loadModel("Models/test.gltf");
		for(Spatial child : testScene.descendantMatches(Geometry.class))
			System.out.println(child.getName());

With the current implementation, it prints

Cube-Mesh
Cube-Mesh
BUILD SUCCESSFUL (total time: 0 seconds)

And after the change it prints

Cube-Object-1
Cube-Object-2
BUILD SUCCESSFUL (total time: 0 seconds)

Here’s the PR

5 Likes

Thanks, the new result looks correct to me.

3 Likes