Need Help to recursively import RDCs from a Folder and store each element into a Collection

As written in the title and kindly need help, my script is almost ready but I have some troubles because it stores only the first element on the collection under its named from file. I’m pretty new to python, however.enter image description here Using the MapsImporter Plugin for scraping Google Maps from RenderDOC into Blender.

Original Question: https://github.com/eliemichel/MapsModelsImporter/issues/128

import bpy
import os
import sys
import glob

directory_im = 'C:/LowPoly2/'
files = glob.glob(directory_im + ".rdc")
for f in files:
head, tail = os.path.split(f)
collection_name = tail.replace('.rdc', '')
bpy.ops.import_rdc.google_maps(filepath=(f), filter_glob=".rdc", max_blocks=-1)
myCol = bpy.data.collections.new(collection_name)
bpy.context.scene.collection.children.link(myCol)
for ob in bpy.context.selected_objects:
myCol.objects.link(ob)

Please always check the formatting when posting scripts, the indentations are critical for python.

As to your question, judging the screenshot on the GitHub page, you have to deselect all objects each time before you import new geometry. Otherwise, with each import, your selection grows, and thus you simply assign all previously imported plus the currently imported objects to the current collection.

1 Like

Thanks for your answer, I’m new to python and maybe need more information about doing this routine.
Could you please elaborate how to do that?

There is two ways to do it. One is the simple, more beginner-friendly version in which you simply use Blenders own Operator to deselect stuff (tested this with Blender 2.92):

import bpy
import os
import sys
import glob

directory_im = 'C:/LowPoly2/'
files = glob.glob(directory_im + ".rdc")

for f in files:
	head, tail = os.path.split(f)
	collection_name = tail.replace('.rdc', '')
	
	# you can use Blender native select operator to deselect all objects
	# however, if you plan to create an own operator instead of a simple script,
	# you might want to use more low-level functions, see other example
	bpy.ops.object.select_all(action = 'DESELECT')
	bpy.ops.import_rdc.google_maps(filepath=(f), filter_glob=".rdc", max_blocks=-1)
	
	myCol = bpy.data.collections.new(collection_name)
	bpy.context.scene.collection.children.link(myCol)
	
	for ob in bpy.context.selected_objects:
		myCol.objects.link(ob)

However, this will cause some performance loss if used within an own Operator. in such a case, I’d rather recommend using the more low-level functionality on the objects themselves:

import bpy
import os
import sys
import glob

directory_im = 'C:/LowPoly2/'
files = glob.glob(directory_im + ".rdc")

for f in files:
	head, tail = os.path.split(f)
	collection_name = tail.replace('.rdc', '')
	
	# iterate over currently selected objects and deselect them
	for o in bpy.context.selected_objects:
		o.select_set(state = False)
	
	bpy.ops.import_rdc.google_maps(filepath=(f), filter_glob=".rdc", max_blocks=-1)
	
	myCol = bpy.data.collections.new(collection_name)
	bpy.context.scene.collection.children.link(myCol)
	
	for ob in bpy.context.selected_objects:
		myCol.objects.link(ob)
1 Like

please also note that this is a question which would be better suited for one of the community sites, i. e. Blender StackExchange

1 Like

Thanks for your precious help, tested on 2.92, however it still generates correct iteration only for one element of the file imported I have only two files into the folder at the moment.

I think it can help also for other types of files, but at the moment i need to use on RDC.
I also published on GIThub and StackExchange, I will link cross post to help future needs.

Test Files: https://gofile.io/d/bx9Cjs

The problem is that the Maps Importer only selects the last imported object, and deselects the rest right after import. So now there is no way for you to figure out what objects have been brought in. In my opinion the Add-on does not follow the design principles of Blender, where newly imported geometry should always be selected. As a result, retrieving the selection using bpy.context.selected_objects becomes useless, it only gives you the last object that was imported, not all of them.

1 Like

You could however work around this by creating a Master collection first, and making it active before you run an import. will work on this soon

1 Like

OK, so this code works with the test data on my rig:

import bpy
import os
import sys
import glob

directory_im = 'C:\\LowPoly2\\'
files = glob.glob(directory_im + "*.rdc")

# helper method to create a new LayerCollection
# also setting it to the active LayerCollection
# the Google Maps importer then puts the objects into that LayerCollection automatically
def create_coll(parent_layer_collection, collection_name):
	new_col = bpy.data.collections.new(collection_name)
	parent_layer_collection.collection.children.link(new_col)
	new_child_layer_coll = parent_layer_collection.children.get(new_col.name)
	
	bpy.context.view_layer.active_layer_collection = new_child_layer_coll
	
	return new_child_layer_coll
	

# create a master collection to batch import the files to, or re-use the currently active collection in the scene - up to you
master_collection =  bpy.context.view_layer.active_layer_collection

# iterate over files
for f in files:
	head, tail = os.path.split(f)
	collection_name = tail.replace('.rdc', '')
	
	# create a new LayerCollection to import the objects to
	# I am storing the reference to it here in case you need to run further actions on it
	# e.g. changing color etc etc
	myCol = create_coll(master_collection, collection_name)

	# run the importer, it will work within the new sub-collection
	bpy.ops.import_rdc.google_maps(filepath=(f), filter_glob=".rdc", max_blocks=-1)

It becomes rather tricky because you need to deal with both Collections and LayerCollections, to be able to set an active layer collection. The first function creates just that, and returns a LayerCollection to be used, which is also set as active collection on the way. By doing that, the importer automatically places its objects in there “for free”.

1 Like

Fantastic!
Works like a charm! Thanks for helping me and the community :slight_smile:

1 Like

Hi,
I’m focusing on a multiple obj import and need to strenghten a bit the routine you published.
The idea is:

Import OBJ recursively scanning on multiple subfolders, ONE by ONE
Apply Lily Texture Packer Plugin for each object imported and link to newly created material
Delete any other unused material
Save Lily Textured file .png in the same folder
Export a new FBX into the native folder

(I saw that the tiles imported are shrinking from 500mb to 60mb, doing by hand, and it would be useful for massive import, i’m on 200 tiles at the moment).

import bpy
import os
import sys
from bpy_extras.io_utils import ImportHelper
from bpy.props import (BoolProperty,
                       FloatProperty,
                       StringProperty,
                       EnumProperty,
                       CollectionProperty
                       )
import glob



bpy.ops.outliner.orphans_purge()
directory_im = './3042726071604147-20-894/'
files = glob.glob(directory_im + "*.obj")


# helper method to create a new LayerCollection
# also setting it to the active LayerCollection
# the Google Maps importer then puts the objects into that LayerCollection automatically

def create_coll(parent_layer_collection, collection_name):
    new_col = bpy.data.collections.new(collection_name)
    parent_layer_collection.collection.children.link(new_col)
    new_child_layer_coll = parent_layer_collection.children[new_col.name]

    bpy.context.view_layer.active_layer_collection = new_child_layer_coll
    return new_child_layer_coll
    
# create a master collection to batch import the files to, or re-use the currently active collection in the 
scene - up to you

master_collection =  bpy.context.view_layer.active_layer_collection

# iterate over files

for f in files:
    head, tail = os.path.split(f)
    collection_name = tail.replace('.obj', '')
    
    # create a new LayerCollection to import the objects to
    # I am toring the reference to it here in case you need to run further actions on it
    # e.g. changing color etc etc

    myCol = create_coll(master_collection, collection_name)

    # run the importer, it will work within the new sub-collection
    
    #bpy.ops.import_rdc.google_maps(filepath=(f), filter_glob=".rdc", max_blocks=-1)
    bpy.ops.import_scene.obj(filepath=f, filter_glob="*.obj;*.mtl", use_image_search=True, axis_forward='-Z', axis_up='Y')
    
    
bpy.ops.object.lily_texture_packer(spacing=0)  
obj_object = bpy.context.selected_objects[0] ####<--Fix

#for SlcObj in obj_select:
#    bpy.ops.object.material_slot_select(mat)
#    bpy.ops.object.make_links_data(type='Material')
    
    
ob = bpy.context.active_object

# Get material
mat = bpy.data.materials.get("Material")
if mat is None:
    # create material
    mat = bpy.data.materials.new(name="Material")

# Assign it to object
if ob.data.materials:
    # assign to 1st material slot
    ob.data.materials[0] = mat
else:
    # no slots
    ob.data.materials.append(mat)
    
    
print('Imported Collection: ', obj_object.name)
    
    # bpy.ops.export_scene.fbx(bpy.ops.export_scene.fbx(filepath=...)