def duplicate_asset(source, **kwargs): '''Duplicate asset when it's already appended in the scene, so that blender's append doesn't create duplicated data.''' # we need to save selection sel = utils.selection_get() bpy.ops.object.select_all(action='DESELECT') # check visibility obs = utils.get_hierarchy(source) if not check_all_visible(obs): return None # check selectability and select in one run if not check_selectible(obs): return None # duplicate the asset objects bpy.ops.object.duplicate(linked=True) nobs = bpy.context.selected_objects[:] #get parent for ob in nobs: if ob.parent not in nobs: parent = ob break # restore original selection utils.selection_set(sel) return parent, nobs
def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): '''append objects into scene individually''' with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to): sobs = [] for ob in data_from.objects: if ob in obnames or obnames == []: sobs.append(ob) data_to.objects = sobs # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")] # link them to scene scene = bpy.context.scene sel = utils.selection_get() bpy.ops.object.select_all(action='DESELECT') return_obs = [ ] # this might not be needed, but better be sure to rewrite the list. main_object = None hidden_objects = [] # for obj in data_to.objects: if obj is not None: # if obj.name not in scene.objects: scene.collection.objects.link(obj) if obj.parent is None: obj.location = location main_object = obj obj.select_set(True) # we need to unhide object so make_local op can use those too. if link == True: if obj.hide_viewport: hidden_objects.append(obj) obj.hide_viewport = False return_obs.append(obj) # Only after all objects are in scene! Otherwise gets broken relationships if link == True: bpy.ops.object.make_local(type='SELECT_OBJECT') for ob in hidden_objects: ob.hide_viewport = True if kwargs.get('rotation') is not None: main_object.rotation_euler = kwargs['rotation'] if kwargs.get('parent') is not None: main_object.parent = bpy.data.objects[kwargs['parent']] main_object.matrix_world.translation = location bpy.ops.object.select_all(action='DESELECT') utils.selection_set(sel) return main_object, return_obs
def link_collection(file_name, obnames=[], location=(0, 0, 0), link=False, parent=None, **kwargs): '''link an instanced group - model type asset''' sel = utils.selection_get() with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to): scols = [] for col in data_from.collections: if col == kwargs['name']: data_to.collections = [col] rotation = (0, 0, 0) if kwargs.get('rotation') is not None: rotation = kwargs['rotation'] bpy.ops.object.empty_add(type='PLAIN_AXES', location=location, rotation=rotation) main_object = bpy.context.view_layer.objects.active main_object.instance_type = 'COLLECTION' if parent is not None: main_object.parent = bpy.data.objects.get(parent) main_object.matrix_world.translation = location for col in bpy.data.collections: if col.library is not None: fp = bpy.path.abspath(col.library.filepath) fp1 = bpy.path.abspath(file_name) if fp == fp1: main_object.instance_collection = col break #sometimes, the lib might already be without the actual link. if not main_object.instance_collection and kwargs['name']: col = bpy.data.collections.get(kwargs['name']) if col: main_object.instance_collection = col main_object.name = main_object.instance_collection.name # bpy.ops.wm.link(directory=file_name + "/Collection/", filename=kwargs['name'], link=link, instance_collections=True, # autoselect=True) # main_object = bpy.context.view_layer.objects.active # if kwargs.get('rotation') is not None: # main_object.rotation_euler = kwargs['rotation'] # main_object.location = location utils.selection_set(sel) return main_object, []
def append_particle_system(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): '''link an instanced group - model type asset''' pss = [] with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to): for ps in data_from.particles: pss.append(ps) data_to.particles = pss s = bpy.context.scene sel = utils.selection_get() target_object = bpy.context.scene.objects.get(kwargs['target_object']) if target_object is not None and target_object.type == 'MESH': target_object.select_set(True) bpy.context.view_layer.objects.active = target_object for ps in pss: # now let's tune this ps to the particular objects area: totarea = 0 for p in target_object.data.polygons: totarea += p.area count = int(ps.count * totarea) if ps.child_type in ('INTERPOLATED', 'SIMPLE'): total_count = count * ps.rendered_child_count disp_count = count * ps.child_nbr else: total_count = count threshold = 2000 total_max_threshold = 50000 # emitting too many parent particles just kills blender now: if count > total_max_threshold: ratio = round(count / total_max_threshold) if ps.child_type in ('INTERPOLATED', 'SIMPLE'): ps.rendered_child_count *= ratio else: ps.child_type = 'INTERPOLATED' ps.rendered_child_count = ratio count = max(2, int(count / ratio)) ps.display_percentage = min( ps.display_percentage, max(1, int(100 * threshold / total_count))) ps.count = count bpy.ops.object.particle_system_add() target_object.particle_systems[-1].settings = ps target_object.select_set(False) utils.selection_set(sel) return target_object, []
def link_group(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): '''link an instanced group - model type asset''' sel = utils.selection_get() bpy.ops.wm.link(directory=file_name + "/Collection/", filename=kwargs['name'], link=link, instance_collections=True, autoselect=True) main_object = bpy.context.active_object if kwargs.get('rotation') is not None: main_object.rotation_euler = kwargs['rotation'] main_object.location = location utils.selection_set(sel) return main_object, []
def append_particle_system(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): '''link an instanced group - model type asset''' pss = [] with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to): for ps in data_from.particles: pss.append(ps) data_to.particles = pss s = bpy.context.scene sel = utils.selection_get() target_object = bpy.context.scene.objects.get(kwargs['target_object']) if target_object is not None and target_object.type == 'MESH': target_object.select_set(True) bpy.context.view_layer.objects.active = target_object for ps in pss: # now let's tune this ps to the particular objects area: totarea = 0 for p in target_object.data.polygons: totarea += p.area count = int(ps.count * totarea) if ps.child_type in ('INTERPOLATED', 'SIMPLE'): total_count = count * ps.rendered_child_count disp_count = count * ps.child_nbr else: total_count = count threshold = 2000 total_max_threshold = 50000 # emitting too many parent particles just kills blender now: if count > total_max_threshold: ratio = round(count / total_max_threshold) if ps.child_type in ('INTERPOLATED', 'SIMPLE'): ps.rendered_child_count *= ratio else: ps.child_type = 'INTERPOLATED' ps.rendered_child_count = ratio count = max(2, int(count / ratio)) ps.display_percentage = min(ps.display_percentage, max(1, int(100 * threshold / total_count))) ps.count = count bpy.ops.object.particle_system_add() target_object.particle_systems[-1].settings = ps target_object.select_set(False) utils.selection_set(sel) return target_object, []
def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): '''append objects into scene individually''' with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to): sobs = [] for ob in data_from.objects: if ob in obnames or obnames == []: sobs.append(ob) data_to.objects = sobs # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")] # link them to scene scene = bpy.context.scene sel = utils.selection_get() bpy.ops.object.select_all(action='DESELECT') return_obs = [] # this might not be needed, but better be sure to rewrite the list. main_object = None hidden_objects = [] # for obj in data_to.objects: if obj is not None: # if obj.name not in scene.objects: scene.collection.objects.link(obj) if obj.parent is None: obj.location = location main_object = obj obj.select_set(True) # we need to unhide object so make_local op can use those too. if link == True: if obj.hide_viewport: hidden_objects.append(obj) obj.hide_viewport = False return_obs.append(obj) # Only after all objects are in scene! Otherwise gets broken relationships if link == True: bpy.ops.object.make_local(type='SELECT_OBJECT') for ob in hidden_objects: ob.hide_viewport = True if kwargs.get('rotation') is not None: main_object.rotation_euler = kwargs['rotation'] bpy.ops.object.select_all(action='DESELECT') utils.selection_set(sel) return main_object, return_obs
def append_particle_system(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): '''link an instanced group - model type asset''' pss = [] with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to): for ps in data_from.particles: pss.append(ps) data_to.particles = pss s = bpy.context.scene sel = utils.selection_get() target_object = bpy.context.scene.objects.get(kwargs['target_object']) if target_object is not None and target_object.type == 'MESH': target_object.select_set(True) bpy.context.view_layer.objects.active = target_object for ps in pss: # now let's tune this ps to the particular objects area: totarea = 0 for p in target_object.data.polygons: totarea += p.area count = int(ps.count * totarea) if ps.child_type in ('INTERPOLATED', 'SIMPLE'): total_count = count * ps.rendered_child_count disp_count = count * ps.child_nbr else: total_count = count bbox_threshold = 25000 display_threshold = 200000 total_max_threshold = 2000000 # emitting too many parent particles just kills blender now. #this part tuned child count, we'll leave children to artists only. # if count > total_max_threshold: # ratio = round(count / total_max_threshold) # # if ps.child_type in ('INTERPOLATED', 'SIMPLE'): # ps.rendered_child_count *= ratio # else: # ps.child_type = 'INTERPOLATED' # ps.rendered_child_count = ratio # count = max(2, int(count / ratio)) #1st level of optimizaton - switch t bounding boxes. if total_count > bbox_threshold: target_object.display_type = 'BOUNDS' # 2nd level of optimization - reduce percentage of displayed particles. ps.display_percentage = min( ps.display_percentage, max(1, int(100 * display_threshold / total_count))) #here we can also tune down number of children displayed. #set the count ps.count = count #add the modifier bpy.ops.object.particle_system_add() # 3rd level - hide particle system from viewport - is done on the modifier.. if total_count > total_max_threshold: target_object.modifiers[-1].show_viewport = False target_object.particle_systems[-1].settings = ps target_object.select_set(False) utils.selection_set(sel) return target_object, []
def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): '''append objects into scene individually''' #simplified version of append if kwargs.get('name'): # by now used for appending into scene scene = bpy.context.scene sel = utils.selection_get() bpy.ops.object.select_all(action='DESELECT') path = file_name + "\\Collection\\" collection_name = kwargs.get('name') fc = utils.get_fake_context(bpy.context, area_type='VIEW_3D') bpy.ops.wm.append(fc, filename=collection_name, directory=path) return_obs = [] to_hidden_collection = [] collection = None for ob in bpy.context.scene.objects: if ob.select_get(): return_obs.append(ob) if not ob.parent: main_object = ob ob.location = location # check for object that should be hidden if ob.users_collection[0].name == collection_name: collection = ob.users_collection[0] else: to_hidden_collection.append(ob) if kwargs.get('rotation'): main_object.rotation_euler = kwargs['rotation'] if kwargs.get('parent') is not None: main_object.parent = bpy.data.objects[kwargs['parent']] main_object.matrix_world.translation = location #move objects that should be hidden to a sub collection if len(to_hidden_collection) > 0 and collection is not None: hidden_collection_name = collection_name + '_hidden' h_col = bpy.data.collections.new(name=hidden_collection_name) collection.children.link(h_col) for ob in to_hidden_collection: ob.users_collection[0].objects.unlink(ob) h_col.objects.link(ob) utils.exclude_collection(hidden_collection_name) bpy.ops.object.select_all(action='DESELECT') utils.selection_set(sel) return main_object, return_obs #this is used for uploads: with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to): sobs = [] # for col in data_from.collections: # if col == kwargs.get('name'): for ob in data_from.objects: if ob in obnames or obnames == []: sobs.append(ob) data_to.objects = sobs # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")] # link them to scene scene = bpy.context.scene sel = utils.selection_get() bpy.ops.object.select_all(action='DESELECT') return_obs = [ ] # this might not be needed, but better be sure to rewrite the list. main_object = None hidden_objects = [] # for obj in data_to.objects: if obj is not None: # if obj.name not in scene.objects: scene.collection.objects.link(obj) if obj.parent is None: obj.location = location main_object = obj obj.select_set(True) # we need to unhide object so make_local op can use those too. if link == True: if obj.hide_viewport: hidden_objects.append(obj) obj.hide_viewport = False return_obs.append(obj) # Only after all objects are in scene! Otherwise gets broken relationships if link == True: bpy.ops.object.make_local(type='SELECT_OBJECT') for ob in hidden_objects: ob.hide_viewport = True if kwargs.get('rotation') is not None: main_object.rotation_euler = kwargs['rotation'] if kwargs.get('parent') is not None: main_object.parent = bpy.data.objects[kwargs['parent']] main_object.matrix_world.translation = location bpy.ops.object.select_all(action='DESELECT') utils.selection_set(sel) return main_object, return_obs