Find objects within GLTF-file by name and attach them to the scene.
-
Hi!
For a python plugin I need to use some GLTF files as "asset library" files. For example, I have a gltf with hundreds of meshes in it. Ideally I would be able to scan the gltf for specific meshes by name and attach these to the scene without having to load the complete gltf in memory.
Coming mostly from Blender plugin development, this is my first C4D plugin, so please forgive me that I am not quite fluent in C4D python yet and may have some stupid assumptions.
As far as I can see I need to use c4d.documents.LoadDocument and made some quick tests. I didn't run into anything major as far as I can tell, but I am not sure if I will run into a dead end with this approach.
Here, the first quick tryout:
import c4d def findChildByName(mom, name, recursive = True): """Naive function to find a child object by name. Can produce only one child and is therefore not very sexy.""" if hasattr(mom, 'GetObjects'): for child in mom.GetObjects(): if child.GetName() == name: return child elif recursive: c = findChildByName(child, name) if c: return c if hasattr(mom, 'GetChildren'): for child in mom.GetChildren(): if child.GetName() == name: return child elif recursive: c = findChildByName(child, name) if c: return c return None filepath = "C:/path/to/file.glb" f = c4d.documents.LoadDocument(filepath, c4d.SCENEFILTER_OBJECTS) doc = c4d.documents.GetActiveDocument() eberhardt = findChildByName(f, "Eberhardt") if eberhardt != None: doc.InsertObject(eberhardt.GetClone(c4d.COPYFLAGS_0))
Of course the whole glb file is loaded into memory, but otherwise it works. How would I go about without loading the whole file into memory? Do I need to adjust the gltf importer settings similar to the obj importer example somehow? I saw the
c4d.SCENEFILTER_IDENTIFY_ONLY
flag... is this one leading to the road of glory?Is it even possible to load files only partially, or do I need to write my own gltf importer?
I'd be super happy if someone could point me in the right direction!
-
Hello @uogygiuol,
Welcome to the Maxon developers forum and its community, it is great to have you with us!
Getting Started
Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.
- Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
- Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
- Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.
It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.
About your First Question
You can search for objects with c4d.documents.BaseDocument.SearchObject.
doc: c4d.documents.BaseDocument = c4d.documents.GetActiveDocument() target: c4d.BaseObject | None = doc.SearchObject("Eberhardt") if target is None: raise RuntimeError("Could not find target.")
Apart from the fact that names are a poor way to identify objects, you can also not find multiple objects with the same name in this manner. With release 2025 we added abstracted scene iteration.
doc: c4d.documents.BaseDocument = c4d.documents.GetActiveDocument() op: c4d.BaseObject = doc.GetFirstObject() # Walk the obejct tree and look for objects with a given name. for node in mxutils.IterateTree(op, True, True, True): if node.GetName() == "Eberhardt": pass # There is also abstract scene iteration now, here we look for any node named "Eberhardt" in #doc. for node in mxutils.RecurseGraph(doc, yieldBranches=True, yieldHierarchy=True): if node.GetName() == "Eberhardt": pass # Or for objects and tags named "Eberhardt". Check the docs on #RecurseGraph, there are a lot of # options for finetuning the scene traversal. for node in mxutils.RecurseGraph(doc, yieldBranches=True, yieldHierarchy=True, nodeFilter=[c4d.Obase, c4d.Tbase]): if node.GetName() == "Eberhardt": pass
Last but not least, what you are doing in your example code, recursion (at least unbound recursion) should be avoided, as this can quite easily lead to stack overflows. See this thread for how to do scene traversal manually.
Cheers,
Ferdinand