From 8575c4843caf7074dbdc5376076d4ee805e2fb7b Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 14 Nov 2023 02:25:42 +0100 Subject: [PATCH] Fix storing instance and context data correctly, fix removing instances + refactor instance nodes --- openpype/hosts/blender/api/ops.py | 8 ++ openpype/hosts/blender/api/pipeline.py | 7 +- openpype/hosts/blender/api/plugin.py | 89 ++++++++++--------- .../blender/plugins/create/create_action.py | 9 +- .../plugins/create/create_animation.py | 2 +- .../plugins/create/create_blendScene.py | 39 ++------ .../blender/plugins/create/create_camera.py | 41 ++------- .../blender/plugins/create/create_layout.py | 37 ++------ .../blender/plugins/create/create_model.py | 40 ++------- .../plugins/create/create_pointcache.py | 2 +- .../blender/plugins/create/create_review.py | 3 +- .../blender/plugins/create/create_rig.py | 39 ++------ .../blender/plugins/create/create_workfile.py | 52 ++++++----- .../hosts/blender/plugins/load/load_blend.py | 1 + .../blender/plugins/load/load_layout_json.py | 1 + .../blender/plugins/publish/collect_render.py | 5 +- .../blender/plugins/publish/collect_review.py | 4 +- .../publish/validate_instance_empty.py | 2 +- 18 files changed, 140 insertions(+), 241 deletions(-) diff --git a/openpype/hosts/blender/api/ops.py b/openpype/hosts/blender/api/ops.py index 22c590d4bd..c617144b6f 100644 --- a/openpype/hosts/blender/api/ops.py +++ b/openpype/hosts/blender/api/ops.py @@ -31,6 +31,14 @@ PREVIEW_COLLECTIONS: Dict = dict() TIMER_INTERVAL: float = 0.01 if platform.system() == "Windows" else 0.1 +def execute_function_in_main_thread(f): + """Decorator to move a function call into main thread items""" + def wrapper(*args, **kwargs): + mti = MainThreadItem(f, *args, **kwargs) + execute_in_main_thread(mti) + return wrapper + + class BlenderApplication(QtWidgets.QApplication): _instance = None blender_windows = {} diff --git a/openpype/hosts/blender/api/pipeline.py b/openpype/hosts/blender/api/pipeline.py index c3f8f06694..9ac59f5620 100644 --- a/openpype/hosts/blender/api/pipeline.py +++ b/openpype/hosts/blender/api/pipeline.py @@ -138,7 +138,10 @@ class BlenderHost(HostBase, IWorkfileHost, IPublishHost): Returns: dict: Context data stored using 'update_context_data'. """ - return bpy.context.scene.openpype_context + property = bpy.context.scene.get(AVALON_PROPERTY) + if property: + return property.to_dict() + return {} def update_context_data(self, data: dict, changes: dict): """Override abstract method from IPublishHost. @@ -149,7 +152,7 @@ class BlenderHost(HostBase, IWorkfileHost, IPublishHost): changes (dict): Only data that has been changed. Each value has tuple with '(, )' value. """ - bpy.context.scene.openpype_context.update(data) + bpy.context.scene[AVALON_PROPERTY] = data def pype_excepthook_handler(*args): diff --git a/openpype/hosts/blender/api/plugin.py b/openpype/hosts/blender/api/plugin.py index 0399bf2e50..d1cefe0a62 100644 --- a/openpype/hosts/blender/api/plugin.py +++ b/openpype/hosts/blender/api/plugin.py @@ -12,6 +12,8 @@ from openpype.pipeline import ( LoaderPlugin, get_current_task_name, ) +from openpype.lib import BoolDef + from .pipeline import ( AVALON_CONTAINERS, AVALON_INSTANCES, @@ -149,6 +151,8 @@ class BaseCreator(Creator): """Base class for Blender Creator plug-ins.""" defaults = ['Main'] + create_as_asset_group = False + @staticmethod def cache_subsets(shared_data): """Cache instances for Creators shared data. @@ -190,12 +194,12 @@ class BaseCreator(Creator): creator_id = avalon_prop.get('creator_identifier') if creator_id: # Creator instance - cache.setdefault(creator_id, []).append(avalon_prop) + cache.setdefault(creator_id, []).append(obj_or_col) else: family = avalon_prop.get('family') if family: # Legacy creator instance - cache_legacy.setdefault(family, []).append(avalon_prop) + cache_legacy.setdefault(family, []).append(obj_or_col) shared_data["blender_cached_subsets"] = cache shared_data["blender_cached_legacy_subsets"] = cache_legacy @@ -220,27 +224,29 @@ class BaseCreator(Creator): instances = bpy.data.collections.new(name=AVALON_INSTANCES) bpy.context.scene.collection.children.link(instances) - # Create instance collection - collection = bpy.data.collections.new( - name=asset_name(instance_data["asset"], subset_name) + # Create asset group + name = asset_name(instance_data["asset"], subset_name) + if self.create_as_asset_group: + # Create instance as empty + instance_node = bpy.data.objects.new(name=name, object_data=None) + instance_node.empty_display_type = 'SINGLE_ARROW' + instances.objects.link(instance_node) + else: + # Create instance collection + instance_node = bpy.data.collections.new(name=name) + instances.children.link(instance_node) + + self.set_instance_data(subset_name, instance_data) + + instance = CreatedInstance( + self.family, subset_name, instance_data, self ) - instances.children.link(collection) + instance.transient_data["instance_node"] = instance_node + self._add_instance_to_context(instance) - collection[AVALON_PROPERTY] = instance_node = { - "name": collection.name, - } + imprint(instance_node, instance_data) - self.set_instance_data(subset_name, instance_data, instance_node) - - self._add_instance_to_context( - CreatedInstance( - self.family, subset_name, instance_data, self - ) - ) - - imprint(collection, instance_data) - - return collection + return instance_node def collect_instances(self): """Override abstract method from BaseCreator. @@ -257,12 +263,14 @@ class BaseCreator(Creator): return # Process only instances that were created by this creator - for instance_data in cached_subsets.get(self.identifier, []): + for instance_node in cached_subsets.get(self.identifier, []): + property = instance_node.get(AVALON_PROPERTY) # Create instance object from existing data instance = CreatedInstance.from_existing( - instance_data=instance_data.to_dict(), + instance_data=property.to_dict(), creator=self ) + instance.transient_data["instance_node"] = instance_node # Add instance to create context self._add_instance_to_context(instance) @@ -276,41 +284,32 @@ class BaseCreator(Creator): and their changes, as a list of tuples.""" for created_instance, _changes in update_list: data = created_instance.data_to_store() - - imprint(data.get("instance_node", {}), data) + node = created_instance.transient_data["instance_node"] + if node: + imprint(node, data) def remove_instances(self, instances: List[CreatedInstance]): - """Override abstract method from BaseCreator. - Method called when instances are removed. - Args: - instance(List[CreatedInstance]): Instance objects to remove. - """ for instance in instances: - outliner_entity = instance.data.get("instance_node", {}).get( - "datablock" - ) - if not outliner_entity: - continue + node = instance.transient_data["instance_node"] - if isinstance(outliner_entity, bpy.types.Collection): - for children in outliner_entity.children_recursive: + if isinstance(node, bpy.types.Collection): + for children in node.children_recursive: if isinstance(children, bpy.types.Collection): bpy.data.collections.remove(children) else: bpy.data.objects.remove(children) - bpy.data.collections.remove(outliner_entity) - elif isinstance(outliner_entity, bpy.types.Object): - bpy.data.objects.remove(outliner_entity) + bpy.data.collections.remove(node) + elif isinstance(node, bpy.types.Object): + bpy.data.objects.remove(node) self._remove_instance_from_context(instance) def set_instance_data( self, subset_name: str, - instance_data: dict, - instance_node: bpy.types.ID, + instance_data: dict ): """Fill instance data with required items. @@ -329,10 +328,16 @@ class BaseCreator(Creator): "label": subset_name, "task": get_current_task_name(), "subset": subset_name, - "instance_node": instance_node, } ) + def get_pre_create_attr_defs(self): + return [ + BoolDef("use_selection", + label="Use selection", + default=True) + ] + class Loader(LoaderPlugin): """Base class for Loader plug-ins.""" diff --git a/openpype/hosts/blender/plugins/create/create_action.py b/openpype/hosts/blender/plugins/create/create_action.py index ac425dff74..f14023639f 100644 --- a/openpype/hosts/blender/plugins/create/create_action.py +++ b/openpype/hosts/blender/plugins/create/create_action.py @@ -2,11 +2,10 @@ import bpy -from openpype.hosts.blender.api.plugin import BaseCreator, asset_name -from openpype.hosts.blender.api import lib +from openpype.hosts.blender.api import lib, plugin -class CreateAction(BaseCreator): +class CreateAction(plugin.BaseCreator): """Action output for character rigs.""" identifier = "io.openpype.creators.blender.action" @@ -24,9 +23,9 @@ class CreateAction(BaseCreator): ) # Get instance name - name = asset_name(instance_data["asset"], subset_name) + name = plugin.asset_name(instance_data["asset"], subset_name) - if pre_create_data.get("useSelection"): + if pre_create_data.get("use_selection"): for obj in lib.get_selection(): if (obj.animation_data is not None and obj.animation_data.action is not None): diff --git a/openpype/hosts/blender/plugins/create/create_animation.py b/openpype/hosts/blender/plugins/create/create_animation.py index f7cb9f88aa..6f0cabb259 100644 --- a/openpype/hosts/blender/plugins/create/create_animation.py +++ b/openpype/hosts/blender/plugins/create/create_animation.py @@ -21,7 +21,7 @@ class CreateAnimation(plugin.BaseCreator): subset_name, instance_data, pre_create_data ) - if pre_create_data.get("useSelection"): + if pre_create_data.get("use_selection"): selected = lib.get_selection() for obj in selected: collection.objects.link(obj) diff --git a/openpype/hosts/blender/plugins/create/create_blendScene.py b/openpype/hosts/blender/plugins/create/create_blendScene.py index 1dc8f44a63..f1090ae397 100644 --- a/openpype/hosts/blender/plugins/create/create_blendScene.py +++ b/openpype/hosts/blender/plugins/create/create_blendScene.py @@ -23,42 +23,17 @@ class CreateBlendScene(plugin.Creator): def create( self, subset_name: str, instance_data: dict, pre_create_data: dict ): - """Run the creator on Blender main thread.""" - mti = ops.MainThreadItem( - self._process, subset_name, instance_data, pre_create_data - ) - ops.execute_in_main_thread(mti) - def _process( - self, subset_name: str, instance_data: dict, pre_create_data: dict - ): - # Get Instance Container or create it if it does not exist - instances = bpy.data.collections.get(AVALON_INSTANCES) - if not instances: - instances = bpy.data.collections.new(name=AVALON_INSTANCES) - bpy.context.scene.collection.children.link(instances) + instance_node = super().create(subset_name, + instance_data, + pre_create_data) - # Create instance object - asset = instance_data.get("asset") - name = plugin.asset_name(asset, subset_name) - - # Create the new asset group as collection - asset_group = bpy.data.collections.new(name=name) - instances.children.link(asset_group) - asset_group[AVALON_PROPERTY] = instance_node = { - "name": asset_group.name - } - - self.set_instance_data(subset_name, instance_data, instance_node) - lib.imprint(asset_group, instance_data) - - if (self.options or {}).get("useSelection"): + if pre_create_data.get("use_selection"): selection = lib.get_selection(include_collections=True) - for data in selection: if isinstance(data, bpy.types.Collection): - asset_group.children.link(data) + instance_node.children.link(data) elif isinstance(data, bpy.types.Object): - asset_group.objects.link(data) + instance_node.objects.link(data) - return asset_group + return instance_node diff --git a/openpype/hosts/blender/plugins/create/create_camera.py b/openpype/hosts/blender/plugins/create/create_camera.py index 8dbba229a9..d30c60ba21 100644 --- a/openpype/hosts/blender/plugins/create/create_camera.py +++ b/openpype/hosts/blender/plugins/create/create_camera.py @@ -2,7 +2,7 @@ import bpy -from openpype.pipeline import get_current_task_name, CreatedInstance +from openpype.pipeline import CreatedInstance from openpype.hosts.blender.api import plugin, lib, ops from openpype.hosts.blender.api.pipeline import ( AVALON_INSTANCES, @@ -19,43 +19,19 @@ class CreateCamera(plugin.BaseCreator): family = "camera" icon = "video-camera" + create_as_asset_group = True + + @ops.execute_function_in_main_thread def create( self, subset_name: str, instance_data: dict, pre_create_data: dict ): """Run the creator on Blender main thread.""" - self._add_instance_to_context( - CreatedInstance(self.family, subset_name, instance_data, self) - ) - mti = ops.MainThreadItem( - self._process, subset_name, instance_data, pre_create_data - ) - ops.execute_in_main_thread(mti) + asset_group = super().create(subset_name, + instance_data, + pre_create_data) - def _process( - self, subset_name: str, instance_data: dict, pre_create_data: dict - ): - # Get Instance Container or create it if it does not exist - instances = bpy.data.collections.get(AVALON_INSTANCES) - if not instances: - instances = bpy.data.collections.new(name=AVALON_INSTANCES) - bpy.context.scene.collection.children.link(instances) - - # Create instance object - name = plugin.asset_name(instance_data["asset"], subset_name) - - asset_group = bpy.data.objects.new(name=name, object_data=None) - asset_group.empty_display_type = 'SINGLE_ARROW' - instances.objects.link(asset_group) - - asset_group[AVALON_PROPERTY] = instance_node = { - "name": asset_group.name, - } - - self.set_instance_data(subset_name, instance_data, instance_node) - lib.imprint(asset_group, instance_data) - - if pre_create_data.get("useSelection"): + if pre_create_data.get("use_selection"): bpy.context.view_layer.objects.active = asset_group selected = lib.get_selection() for obj in selected: @@ -67,6 +43,7 @@ class CreateCamera(plugin.BaseCreator): camera = bpy.data.cameras.new(subset_name) camera_obj = bpy.data.objects.new(subset_name, camera) + instances = bpy.data.collections.get(AVALON_INSTANCES) instances.objects.link(camera_obj) camera_obj.select_set(True) diff --git a/openpype/hosts/blender/plugins/create/create_layout.py b/openpype/hosts/blender/plugins/create/create_layout.py index a9bf115ea9..f569a81c29 100644 --- a/openpype/hosts/blender/plugins/create/create_layout.py +++ b/openpype/hosts/blender/plugins/create/create_layout.py @@ -19,43 +19,18 @@ class CreateLayout(plugin.BaseCreator): family = "layout" icon = "cubes" + create_as_asset_group = True + def create( self, subset_name: str, instance_data: dict, pre_create_data: dict ): - """Run the creator on Blender main thread.""" - self._add_instance_to_context( - CreatedInstance(self.family, subset_name, instance_data, self) - ) - mti = ops.MainThreadItem( - self._process, subset_name, instance_data, pre_create_data - ) - ops.execute_in_main_thread(mti) - - def _process( - self, subset_name: str, instance_data: dict, pre_create_data: dict - ): - # Get Instance Container or create it if it does not exist - instances = bpy.data.collections.get(AVALON_INSTANCES) - if not instances: - instances = bpy.data.collections.new(name=AVALON_INSTANCES) - bpy.context.scene.collection.children.link(instances) - - # Create instance object - name = plugin.asset_name(instance_data["asset"], subset_name) - asset_group = bpy.data.objects.new(name=name, object_data=None) - asset_group.empty_display_type = 'SINGLE_ARROW' - instances.objects.link(asset_group) - - asset_group[AVALON_PROPERTY] = instance_node = { - "name": asset_group.name, - } - - self.set_instance_data(subset_name, instance_data, instance_node) - lib.imprint(asset_group, instance_data) + asset_group = super().create(subset_name, + instance_data, + pre_create_data) # Add selected objects to instance - if pre_create_data.get("useSelection"): + if pre_create_data.get("use_selection"): bpy.context.view_layer.objects.active = asset_group selected = lib.get_selection() for obj in selected: diff --git a/openpype/hosts/blender/plugins/create/create_model.py b/openpype/hosts/blender/plugins/create/create_model.py index 3501071e8f..9774d4bec3 100644 --- a/openpype/hosts/blender/plugins/create/create_model.py +++ b/openpype/hosts/blender/plugins/create/create_model.py @@ -19,48 +19,24 @@ class CreateModel(plugin.BaseCreator): family = "model" icon = "cube" + create_as_asset_group = True + + @ops.execute_function_in_main_thread def create( self, subset_name: str, instance_data: dict, pre_create_data: dict ): - """Run the creator on Blender main thread.""" - self._add_instance_to_context( - CreatedInstance(self.family, subset_name, instance_data, self) - ) - - mti = ops.MainThreadItem( - self._process, subset_name, instance_data, pre_create_data - ) - ops.execute_in_main_thread(mti) - - def _process( - self, subset_name: str, instance_data: dict, pre_create_data: dict - ): - # Get Instance Container or create it if it does not exist - instances = bpy.data.collections.get(AVALON_INSTANCES) - if not instances: - instances = bpy.data.collections.new(name=AVALON_INSTANCES) - bpy.context.scene.collection.children.link(instances) - - # Create instance object - name = plugin.asset_name(instance_data["asset"], subset_name) - asset_group = bpy.data.objects.new(name=name, object_data=None) - asset_group.empty_display_type = 'SINGLE_ARROW' - instances.objects.link(asset_group) - - asset_group[AVALON_PROPERTY] = instance_node = { - "name": asset_group.name, - } - - self.set_instance_data(subset_name, instance_data, instance_node) - lib.imprint(asset_group, instance_data) + asset_group = super().create(subset_name, + instance_data, + pre_create_data) # Add selected objects to instance - if pre_create_data.get("useSelection"): + if pre_create_data.get("use_selection"): bpy.context.view_layer.objects.active = asset_group selected = lib.get_selection() for obj in selected: obj.select_set(True) selected.append(asset_group) + bpy.ops.object.parent_set(keep_transform=True) return asset_group diff --git a/openpype/hosts/blender/plugins/create/create_pointcache.py b/openpype/hosts/blender/plugins/create/create_pointcache.py index d05b3adb04..d80a1b07f0 100644 --- a/openpype/hosts/blender/plugins/create/create_pointcache.py +++ b/openpype/hosts/blender/plugins/create/create_pointcache.py @@ -20,7 +20,7 @@ class CreatePointcache(plugin.BaseCreator): subset_name, instance_data, pre_create_data ) - if pre_create_data.get("useSelection"): + if pre_create_data.get("use_selection"): objects = lib.get_selection() for obj in objects: collection.objects.link(obj) diff --git a/openpype/hosts/blender/plugins/create/create_review.py b/openpype/hosts/blender/plugins/create/create_review.py index 91333b7741..2d521c4255 100644 --- a/openpype/hosts/blender/plugins/create/create_review.py +++ b/openpype/hosts/blender/plugins/create/create_review.py @@ -21,11 +21,12 @@ class CreateReview(plugin.BaseCreator): subset_name, instance_data, pre_create_data ) - if pre_create_data.get("useSelection"): + if pre_create_data.get("use_selection"): selected = lib.get_selection() for obj in selected: collection.objects.link(obj) elif pre_create_data.get("asset_group"): + # TODO: What is the intended behavior for this? obj = (self.options or {}).get("asset_group") collection.objects.link(obj) diff --git a/openpype/hosts/blender/plugins/create/create_rig.py b/openpype/hosts/blender/plugins/create/create_rig.py index b5b61b3971..87f0124164 100644 --- a/openpype/hosts/blender/plugins/create/create_rig.py +++ b/openpype/hosts/blender/plugins/create/create_rig.py @@ -19,43 +19,18 @@ class CreateRig(plugin.BaseCreator): family = "rig" icon = "wheelchair" + create_as_asset_group = True + + @ops.execute_function_in_main_thread def create( self, subset_name: str, instance_data: dict, pre_create_data: dict ): - """Run the creator on Blender main thread.""" - self._add_instance_to_context( - CreatedInstance(self.family, subset_name, instance_data, self) - ) - - mti = ops.MainThreadItem( - self._process, subset_name, instance_data, pre_create_data - ) - ops.execute_in_main_thread(mti) - - def _process( - self, subset_name: str, instance_data: dict, pre_create_data: dict - ): - # Get Instance Container or create it if it does not exist - instances = bpy.data.collections.get(AVALON_INSTANCES) - if not instances: - instances = bpy.data.collections.new(name=AVALON_INSTANCES) - bpy.context.scene.collection.children.link(instances) - - # Create instance object - name = plugin.asset_name(instance_data["asset"], subset_name) - asset_group = bpy.data.objects.new(name=name, object_data=None) - asset_group.empty_display_type = 'SINGLE_ARROW' - instances.objects.link(asset_group) - - asset_group[AVALON_PROPERTY] = instance_node = { - "name": asset_group.name, - } - - self.set_instance_data(subset_name, instance_data, instance_node) - lib.imprint(asset_group, instance_data) + asset_group = super().create(subset_name, + instance_data, + pre_create_data) # Add selected objects to instance - if pre_create_data.get("useSelection"): + if pre_create_data.get("use_selection"): bpy.context.view_layer.objects.active = asset_group selected = lib.get_selection() for obj in selected: diff --git a/openpype/hosts/blender/plugins/create/create_workfile.py b/openpype/hosts/blender/plugins/create/create_workfile.py index d1529f75f6..8f5adb5583 100644 --- a/openpype/hosts/blender/plugins/create/create_workfile.py +++ b/openpype/hosts/blender/plugins/create/create_workfile.py @@ -3,8 +3,10 @@ import bpy from openpype.pipeline import CreatedInstance, AutoCreator from openpype.client import get_asset_by_name from openpype.hosts.blender.api.plugin import BaseCreator -from openpype.hosts.blender.api.lib import imprint -from openpype.hosts.blender.api.pipeline import AVALON_PROPERTY +from openpype.hosts.blender.api.pipeline import ( + AVALON_PROPERTY, + AVALON_CONTAINERS +) class CreateWorkfile(BaseCreator, AutoCreator): @@ -53,6 +55,8 @@ class CreateWorkfile(BaseCreator, AutoCreator): current_instance = CreatedInstance( self.family, subset_name, data, self ) + instance_node = bpy.data.collections.get(AVALON_CONTAINERS, {}) + current_instance.transient_data["instance_node"] = instance_node self._add_instance_to_context(current_instance) elif ( current_instance["asset"] != asset_name @@ -73,28 +77,30 @@ class CreateWorkfile(BaseCreator, AutoCreator): ) def collect_instances(self): - """Collect workfile instances.""" - self.cache_subsets(self.collection_shared_data) - cached_subsets = self.collection_shared_data["blender_cached_subsets"] - for node in cached_subsets.get(self.identifier, []): - created_instance = CreatedInstance.from_existing( - self.read_instance_node(node), self - ) - self._add_instance_to_context(created_instance) - def update_instances(self, update_list): - """Update workfile instances.""" - for created_inst, _changes in update_list: - data = created_inst.data_to_store() - node = data.get("instance_node") - if not node: - task_name = self.create_context.get_current_task_name() + print("Collecting!") + instance_node = bpy.data.collections.get(AVALON_CONTAINERS) + if not instance_node: + return + print(instance_node) + property = instance_node.get(AVALON_PROPERTY) + if not property: + return + print(property) - bpy.context.scene[AVALON_PROPERTY] = node = { - "name": f"workfile{task_name}" - } + # Create instance object from existing data + instance = CreatedInstance.from_existing( + instance_data=property.to_dict(), + creator=self + ) + instance.transient_data["instance_node"] = instance_node - created_inst["instance_node"] = node - data = created_inst.data_to_store() + # Add instance to create context + self._add_instance_to_context(instance) - imprint(node, data) + def remove_instances(self, instances): + for instance in instances: + node = instance.transient_data["instance_node"] + del node[AVALON_PROPERTY] + + self._remove_instance_from_context(instance) diff --git a/openpype/hosts/blender/plugins/load/load_blend.py b/openpype/hosts/blender/plugins/load/load_blend.py index f7bbc630de..1804de29b6 100644 --- a/openpype/hosts/blender/plugins/load/load_blend.py +++ b/openpype/hosts/blender/plugins/load/load_blend.py @@ -60,6 +60,7 @@ class BlendLoader(plugin.AssetLoader): for rig in rigs: creator_plugin = get_legacy_creator_by_name("CreateAnimation") + # TODO: Refactor legacy create usage to new style creators legacy_create( creator_plugin, name=rig.name.split(':')[-1] + "_animation", diff --git a/openpype/hosts/blender/plugins/load/load_layout_json.py b/openpype/hosts/blender/plugins/load/load_layout_json.py index 81683b8de8..a941c77a8e 100644 --- a/openpype/hosts/blender/plugins/load/load_layout_json.py +++ b/openpype/hosts/blender/plugins/load/load_layout_json.py @@ -123,6 +123,7 @@ class JsonLayoutLoader(plugin.AssetLoader): # raise ValueError("Creator plugin \"CreateCamera\" was " # "not found.") + # TODO: Refactor legacy create usage to new style creators # legacy_create( # creator_plugin, # name="camera", diff --git a/openpype/hosts/blender/plugins/publish/collect_render.py b/openpype/hosts/blender/plugins/publish/collect_render.py index 48b03256ae..00faf85aed 100644 --- a/openpype/hosts/blender/plugins/publish/collect_render.py +++ b/openpype/hosts/blender/plugins/publish/collect_render.py @@ -73,9 +73,8 @@ class CollectBlenderRender(pyblish.api.InstancePlugin): def process(self, instance): context = instance.context - render_data = bpy.data.collections[ - instance.data["instance_node"]["name"] - ].get("render_data") + instance_node = instance.data["transientData"]["instance_node"] + render_data = instance_node.get("render_data") assert render_data, "No render data found." diff --git a/openpype/hosts/blender/plugins/publish/collect_review.py b/openpype/hosts/blender/plugins/publish/collect_review.py index 4889c66be3..2c077398da 100644 --- a/openpype/hosts/blender/plugins/publish/collect_review.py +++ b/openpype/hosts/blender/plugins/publish/collect_review.py @@ -16,9 +16,7 @@ class CollectReview(pyblish.api.InstancePlugin): self.log.debug(f"instance: {instance}") - datablock = bpy.data.collections.get( - instance.data.get("instance_node", {}).get("name", "") - ) + datablock = instance.data["transientData"]["instance_node"] # get cameras cameras = [ diff --git a/openpype/hosts/blender/plugins/publish/validate_instance_empty.py b/openpype/hosts/blender/plugins/publish/validate_instance_empty.py index 7669d76943..6845c29b37 100644 --- a/openpype/hosts/blender/plugins/publish/validate_instance_empty.py +++ b/openpype/hosts/blender/plugins/publish/validate_instance_empty.py @@ -13,7 +13,7 @@ class ValidateInstanceEmpty(pyblish.api.InstancePlugin): optional = False def process(self, instance): - asset_group = instance.data["instance_node"] + asset_group = instance.data["transientData"]["instance_node"] if isinstance(asset_group, bpy.types.Collection): if not (asset_group.objects or asset_group.children):