2
$\begingroup$

I need some help with a script to convert big CAD-files with 80+ collections. The collections need to be changed to a empties with sub-empties and objects. And they need to maintain the hierarchy. I'm not good in programming and I have no expierience in Blender-coding.

I spend 2 days for searching and stitching example codes together and I already can convert the collections with my script.

I'd like to:

  • make an instance from a collection
  • make the instance real
  • delete the collection

(all this from the last collection up to the fist, to maintain hierarchy)

The problem is that the instances are placed in the main-collection and not in the corresponding collection, and so the hierarchy is broken.

Can someone tell me how to tell blender to place the instance in the corresponding collection?

import bpy

print()
print()
print("---------START------------")


def traverse_tree(t):
    yield t
    for child in t.children:
        yield from traverse_tree(child)

# Recursivly transverse layer_collection for a particular name
def recurLayerCollection(layerColl, collName):
    found = None
    if (layerColl.name == collName):
        return layerColl
        
        
    for layer in layerColl.children:
        found = recurLayerCollection(layer, collName)
        if found:
           return found
           


coll = bpy.context.scene.collection # start @ top-collection

list =[]

for c in traverse_tree(coll):
    list.append(c.name)


# remove unwanted collections
list.remove('Collection') # Camera & Light
list.remove('Master Collection') # Master Collection
list.pop(0) # root collection from imported scene


# start from bottom to top
list.reverse()


for entity in list:
    print("Verarbeite: " + entity)
       
    source_collection = bpy.data.collections[entity]
    instance_obj = bpy.data.objects.new(name=entity, object_data=None)
    instance_obj.instance_collection = source_collection
    instance_obj.instance_type = 'COLLECTION'
    
    layer_collection = bpy.context.view_layer.layer_collection # start on top
    parent_collection = recurLayerCollection(layer_collection, entity)
    parent_collection = bpy.context.view_layer.layer_collection
    parent_collection.collection.objects.link(instance_obj)
           
    bpy.data.objects[entity].select_set(True) # select instance
    bpy.ops.object.duplicates_make_real(use_base_parent=True, use_hierarchy=True) # convert to object(meshes & emptys)
    
    bpy.data.collections.remove(source_collection) # delete original collection
   
    print()   

before script before the script

what i get what my script does

what i need what I like to have

The extensions on the names (.001) are not important, I filter them later.

$\endgroup$
1
  • $\begingroup$ First of all, this is a very nice question and could serve as an ideal example on how to ask on Stack Exchange. What I'm missing here, maybe due to my inexperience with importing CAD, is why you're making instances instead of manipulating objects directly? $\endgroup$ May 22 at 21:40
0
$\begingroup$

I could get it to work like I need it. I had to select the above parent-collection and found some example code to implement and now it works.

I use the STEP-importer Plugin STEPper from ambi to import CAD-data and I need the correct hierarchy in the exported GLB-File and collections are exported without hierarchy.

I try to animate and show assembly groups with babylon.js.

Here is the working code:

import bpy

print()
print()
print("---------START------------")
bpy.ops.object.select_all(action='DESELECT')

def traverse_tree(t):
    yield t
    for child in t.children:
        yield from traverse_tree(child)


def parent_lookup(coll):
    parent_lookup = {}
    for coll in traverse_tree(coll):
        for c in coll.children.keys():
            parent_lookup.setdefault(c, coll.name)
    return parent_lookup


#Recursivly transverse layer_collection for a particular name
def recurLayerCollection(layerColl, collName):
    found = None
    if (layerColl.name == collName):
        return layerColl
        
    for layer in layerColl.children:
        found = recurLayerCollection(layer, collName)
        if found:
           return found

C = bpy.context
coll_all = bpy.context.scene.collection
liste =[]
counter = 0

for c in traverse_tree(coll_all):
    liste.append(c.name)


liste.remove('Collection')
liste.remove('Master Collection')
#liste.pop(0)
#iste.pop(0)
liste.reverse()


for entity in liste:
    counter = counter +1
    print("Verarbeite: " + entity)
    
    source_collection = bpy.data.collections[entity]
    instance_obj = bpy.data.objects.new(name=entity, object_data=None)
    instance_obj.instance_collection = source_collection
    instance_obj.instance_type = 'COLLECTION'
#   print(instance_obj)

    # Get all collections of the scene and their parents in a dict
    coll_scene = C.scene.collection
    coll_parents = parent_lookup(coll_scene)

    # Get active collection reference
    active_coll = source_collection
#    print (coll_parents.get(active_coll.name))
    
    # Set parent collection as active
    layer_collection = bpy.context.view_layer.layer_collection
    layerColl = recurLayerCollection(layer_collection, coll_parents.get(active_coll.name))
    bpy.context.view_layer.active_layer_collection = layerColl
#    print(layerColl)
    
    # create / link instances
    parent_collection = bpy.context.view_layer.active_layer_collection
    parent_collection.collection.objects.link(instance_obj)
    
    # convert instances to real objects (with hierarchy)    
    bpy.data.objects[entity].select_set(True)
    bpy.ops.object.duplicates_make_real(use_base_parent=True, use_hierarchy=True)
    
    # delete original collection
    bpy.data.collections.remove(source_collection) #delete collection
   
    
print(counter,  " Collections verarbeitet")
print("------ ENDE--------")
$\endgroup$
3
  • $\begingroup$ You might want to use the Contact Us form to merge your accounts, so that you can edit your question and accept this answer. $\endgroup$
    – Glorfindel
    May 24 at 8:57
  • $\begingroup$ ok i merged the accounts.. how can i close this thread / or accept? $\endgroup$ May 24 at 9:08
  • $\begingroup$ You can accept your answer in a day or so, with the checkmark underneath the score. See blender.stackexchange.com/help/accepted-answer $\endgroup$
    – Glorfindel
    May 24 at 9:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.