MergeDocument under a selected Null
-
Hey,
i use
c4d.documents.MergeDocument(doc , f, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS | c4d.SCENEFILTER_MERGESCENE)
now i would like to group this new scene under a NULL. if i do the whole thing via obj.InsertUnder(null) i miss the materials.
which is totally logical but unfortunately not what i have in mind.So one idea would be to insert the materials separately into the scene by checking the tags. The problem is that I can't be 100% sure that all the materials that are needed will be migrated.
Another approach would be to check which objects are already in the scene and then simply move the newly loaded ones under the zero.
So what is the best way to extend the functionality of MergeDocument to be able to specify a null object as root?
-
Hey @pyr,
Thank you for reaching out to us. The sentence 'if i do the whole thing via obj.InsertUnder(null) i miss the material' is a bit ambiguous, how do you mean that? I assume you mean that when you load two documents A and B and then start copying objects over by either cloning them or removing them from A and inserting them into B, that you then miss material references. Because the call you show us will load both objects and materials found at
f
intodoc
.A straightforward way to do what you want to do, parent everything that has been imported to a null, is to track the state of the top-level objects before and after the import. The difference between the states then tells you what to move where. In practice, there are some technical hoops to jump through, primarily the problem that you might run into dead references when you try to store objects references over the import process.
Cheers,
FerdinandResult:
Code:
"""Demonstrates how to parent the objects merged into a document to a null object. Must be run as a script manager script and will import the contents of #FILE into the active document. """ import c4d doc: c4d.documents.BaseDocument # The active document. FILE: str = r"file:///e:/test.c4d" # The document to import. def main() -> None: """ """ # Get the UUID markers of all top level objects. We get the markers and not the object # references because importing a document bears a good chance that these references will be # dead (C4DAtom.IsAlive() == False) when we access them again. uuidCollection: list[bytes] = [] op: c4d.BaseObject = doc.GetFirstObject() while op: uuidCollection.append(bytes(op.FindUniqueID(c4d.MAXON_CREATOR_ID))) op = op.GetNext() # Now we import our document. c4d.documents.MergeDocument(doc, FILE, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS | c4d.SCENEFILTER_MERGESCENE) # We create our null object to parent the imported stuff to. We also add its UUID to # #uuidCollection, so that we do not attempt to parent #null to itself ;) null: c4d.BaseObject = c4d.BaseObject(c4d.Onull) null.SetName(FILE) doc.InsertObject(null) c4d.EventAdd() uuidCollection.append(bytes(null.FindUniqueID(c4d.MAXON_CREATOR_ID))) # Now we iterate again over all top level objects and parent everything that does not appear in # #uuidCollection to #null. op: c4d.BaseObject = doc.GetFirstObject() # We have to do this on two steps, because when we would already move #op in the first step # where we find the things to move, we would sabotage our own loop here (because as soon as # we move the first op to the null, op.GetNext() would be None). move: list[c4d.BaseObject] = [] while op: if bytes(op.FindUniqueID(c4d.MAXON_CREATOR_ID)) not in uuidCollection: move.append(op) op = op.GetNext() # Actually move the items. for op in move: op.InsertUnderLast(null) c4d.EventAdd() if __name__ == "__main__": main()