From a1b29d179ae476fccc7a846b61ce59ed4c0bc735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vil=C3=A9m=20Duha?= Date: Mon, 9 Sep 2019 00:11:36 +0200 Subject: BlenderKit: replace asset command, present in right-click menu. --- blenderkit/__init__.py | 2 +- blenderkit/append_link.py | 24 +++++++++++++++----- blenderkit/download.py | 58 ++++++++++++++++++++++++++++++++++------------- blenderkit/ui_panels.py | 32 ++++++++++++++++++-------- blenderkit/utils.py | 17 ++++++++++++-- 5 files changed, 99 insertions(+), 34 deletions(-) diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index d7689a3c..f37c81c7 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -19,7 +19,7 @@ bl_info = { "name": "BlenderKit Asset Library", "author": "Vilem Duha, Petr Dlouhy", - "version": (1, 0, 27), + "version": (1, 0, 28), "blender": (2, 80, 0), "location": "View3D > Properties > BlenderKit", "description": "Online BlenderKit library (materials, models, brushes and more)", diff --git a/blenderkit/append_link.py b/blenderkit/append_link.py index ed14083f..24c8caa0 100644 --- a/blenderkit/append_link.py +++ b/blenderkit/append_link.py @@ -21,8 +21,9 @@ if "bpy" in locals(): from importlib import reload utils = reload(utils) + ui = reload(ui) else: - from blenderkit import utils + from blenderkit import utils, ui import bpy import uuid @@ -84,7 +85,7 @@ def append_scene(file_name, scenename=None, link=False, fake_user=False): return scene -def link_group(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): +def link_group(file_name, obnames=[], location=(0, 0, 0), link=False, parent = None, **kwargs): '''link an instanced group - model type asset''' sel = utils.selection_get() @@ -95,14 +96,17 @@ def link_group(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): if col == kwargs['name']: data_to.collections = [col] - rotation = (0,0,0) + 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) + 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' + + main_object.parent = 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) @@ -111,6 +115,7 @@ def link_group(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs): main_object.instance_collection = col break; + 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) @@ -176,6 +181,7 @@ def append_particle_system(file_name, obnames=[], location=(0, 0, 0), link=False 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: @@ -207,7 +213,6 @@ def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwar 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') @@ -216,7 +221,14 @@ def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwar 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 diff --git a/blenderkit/download.py b/blenderkit/download.py index cfda9b7b..bbb09c4c 100644 --- a/blenderkit/download.py +++ b/blenderkit/download.py @@ -343,14 +343,16 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None, location=downloader['location'], rotation=downloader['rotation'], link=link, - name=asset_data['name']) + name=asset_data['name'], + parent=kwargs.get('parent')) else: parent, newobs = append_link.append_objects(file_names[-1], location=downloader['location'], rotation=downloader['rotation'], link=link, - name=asset_data['name']) + name=asset_data['name'], + parent=kwargs.get('parent')) if parent.type == 'EMPTY' and link: bmin = asset_data['bbox_min'] bmax = asset_data['bbox_max'] @@ -363,12 +365,14 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None, location=kwargs['model_location'], rotation=kwargs['model_rotation'], link=link, - name=asset_data['name']) + name=asset_data['name'], + parent=kwargs.get('parent')) else: parent, newobs = append_link.append_objects(file_names[-1], location=kwargs['model_location'], rotation=kwargs['model_rotation'], - link=link) + link=link, + parent=kwargs.get('parent')) if parent.type == 'EMPTY' and link: bmin = asset_data['bbox_min'] bmax = asset_data['bbox_max'] @@ -839,13 +843,16 @@ class BlenderkitDownloadOperator(bpy.types.Operator): asset_index: IntProperty(name="Asset Index", description='asset index in search results', default=-1) target_object: StringProperty( - name="Material Target Object", - description="", + name="Target Object", + description="Material or object target for replacement", default="") + material_target_slot: IntProperty(name="Asset Index", description='asset index in search results', default=0) model_location: FloatVectorProperty(name='Asset Location', default=(0, 0, 0)) model_rotation: FloatVectorProperty(name='Asset Rotation', default=(0, 0, 0)) + replace: BoolProperty(name='Replace', description='replace selection with the asset', default=False) + cast_parent: StringProperty( name="Particles Target Object", description="", @@ -865,19 +872,38 @@ class BlenderkitDownloadOperator(bpy.types.Operator): s['assets used'] = {} if asset_data['asset_base_id'] in s.get('assets used'): asset_data = s['assets used'][asset_data['asset_base_id']].to_dict() + atype = asset_data['asset_type'] if bpy.context.mode != 'OBJECT' and ( atype == 'model' or atype == 'material') and bpy.context.active_object is not None: bpy.ops.object.mode_set(mode='OBJECT') - kwargs = { - 'cast_parent': self.cast_parent, - 'target_object': self.target_object, - 'material_target_slot': self.material_target_slot, - 'model_location': tuple(self.model_location), - 'model_rotation': tuple(self.model_rotation) - } - - start_download(asset_data, **kwargs) + + if self.replace: # cleanup first, assign later. + obs = utils.get_selected_models() + + for ob in obs: + kwargs = { + 'cast_parent': self.cast_parent, + 'target_object': ob.name, + 'material_target_slot': ob.active_material_index, + 'model_location': tuple(ob.matrix_world.translation), + 'model_rotation': tuple(ob.matrix_world.to_euler()), + 'replace': False, + 'parent': ob.parent + } + utils.delete_hierarchy(ob) + start_download(asset_data, **kwargs) + else: + kwargs = { + 'cast_parent': self.cast_parent, + 'target_object': self.target_object, + 'material_target_slot': self.material_target_slot, + 'model_location': tuple(self.model_location), + 'model_rotation': tuple(self.model_rotation), + 'replace': False + } + + start_download(asset_data, **kwargs) return {'FINISHED'} @@ -886,7 +912,7 @@ def register_download(): bpy.utils.register_class(BlenderkitKillDownloadOperator) bpy.app.handlers.load_post.append(scene_load) bpy.app.handlers.save_pre.append(scene_save) - bpy.app.timers.register(timer_update, persistent = True) + bpy.app.timers.register(timer_update, persistent=True) def unregister_download(): diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index 9339b80f..c97c3450 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -733,19 +733,34 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu): sr = bpy.context.scene['search results orig']['results'] asset_data = sr[ui_props.active_index] author_id = str(asset_data['author']['id']) - a = bpy.context.window_manager['bkit authors'].get(author_id) - if a is not None: - # utils.p('author:', a) - if a.get('aboutMeUrl') is not None: - op = layout.operator('wm.url_open', text="Open author's website") - op.url = a['aboutMeUrl'] - op = layout.operator('view3d.blenderkit_search', text='search assets by same author') - op.author_id = author_id + + wm = bpy.context.window_manager + if wm.get('bkit authors') is not None: + a = bpy.context.window_manager['bkit authors'].get(author_id) + if a is not None: + # utils.p('author:', a) + if a.get('aboutMeUrl') is not None: + op = layout.operator('wm.url_open', text="Open author's website") + op.url = a['aboutMeUrl'] + + op = layout.operator('view3d.blenderkit_search', text='search assets by same author') + op.author_id = author_id op = layout.operator('view3d.blenderkit_search', text='search similar') print(dir(asset_data)) op.keywords = asset_data['name'] + ' ' + asset_data['description'] + ' ' + ''.join(asset_data['tags']) + if bpy.context.active_object is not None and ui_props.asset_type == 'MODEL': + aob = bpy.context.active_object + op = layout.operator('scene.blenderkit_download', text='replace active ' + ui_props.asset_type.lower()) + op.asset_type = ui_props.asset_type + op.asset_index = ui_props.active_index + op.model_location = aob.location + op.model_rotation = aob.rotation_euler + op.target_object = aob.name + op.material_target_slot = aob.active_material_index + op.replace = True + wm = bpy.context.window_manager profile = wm.get('bkit profile') if profile is not None: @@ -808,7 +823,6 @@ def draw_panel_categories(self, context): # row.prop(ui_props, 'asset_type', expand=True, icon_only=True) layout.separator() - layout.label(text='Categories') wm = bpy.context.window_manager if wm.get('bkit_categories') == None: diff --git a/blenderkit/utils.py b/blenderkit/utils.py index 0b122192..eebdb078 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -65,14 +65,18 @@ def get_selected_models(): parents = [] for ob in obs: if ob not in done: - while ob.parent is not None and ob not in done: + while ob.parent is not None and ob not in done and ob.blenderkit.asset_base_id != '' and ob.instance_collection is not None: done[ob] = True ob = ob.parent if ob not in parents and ob not in done: - if ob.blenderkit.name != '': + if ob.blenderkit.name != '' or ob.instance_collection is not None: parents.append(ob) done[ob] = True + + #if no blenderkit - like objects were found, use the original selection. + if len(parents) == 0: + parents = obs return parents @@ -282,6 +286,15 @@ def get_hierarchy(ob): obs.append(o) return obs +def select_hierarchy(ob, state = True): + obs = get_hierarchy(ob) + for ob in obs: + ob.select_set(state) + return obs + +def delete_hierarchy(ob): + obs = get_hierarchy(ob) + bpy.ops.object.delete({"selected_objects": obs}) def get_bounds_snappable(obs, use_modifiers=False): # progress('getting bounds of object(s)') -- cgit v1.2.3