Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
kalisp committed Aug 25, 2021
2 parents c7c45ec + 23e5bd1 commit f4e0b52
Show file tree
Hide file tree
Showing 115 changed files with 7,101 additions and 1,936 deletions.
2 changes: 1 addition & 1 deletion igniter/bootstrap_repos.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ def _create_openpype_zip(self, zip_path: Path, openpype_path: Path) -> None:
processed_path = file
self._print(f"- processing {processed_path}")

zip_file.write(file, file.relative_to(openpype_root))
zip_file.write(file, file.resolve().relative_to(openpype_root))

# test if zip is ok
zip_file.testzip()
Expand Down
67 changes: 40 additions & 27 deletions openpype/hosts/blender/api/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

import bpy

from avalon import api
import avalon.blender
from avalon import api, blender
from avalon.blender import ops
from avalon.blender.pipeline import AVALON_CONTAINERS
from openpype.api import PypeCreatorMixin

VALID_EXTENSIONS = [".blend", ".json", ".abc"]
VALID_EXTENSIONS = [".blend", ".json", ".abc", ".fbx"]


def asset_name(
Expand All @@ -27,32 +28,24 @@ def get_unique_number(
asset: str, subset: str
) -> str:
"""Return a unique number based on the asset name."""
avalon_containers = [
c for c in bpy.data.collections
if c.name == 'AVALON_CONTAINERS'
]
containers = []
# First, add the children of avalon containers
for c in avalon_containers:
containers.extend(c.children)
# then keep looping to include all the children
for c in containers:
containers.extend(c.children)
container_names = [
c.name for c in containers
]
avalon_container = bpy.data.collections.get(AVALON_CONTAINERS)
if not avalon_container:
return "01"
asset_groups = avalon_container.all_objects

container_names = [c.name for c in asset_groups if c.type == 'EMPTY']
count = 1
name = f"{asset}_{count:0>2}_{subset}_CON"
name = f"{asset}_{count:0>2}_{subset}"
while name in container_names:
count += 1
name = f"{asset}_{count:0>2}_{subset}_CON"
name = f"{asset}_{count:0>2}_{subset}"
return f"{count:0>2}"


def prepare_data(data, container_name):
name = data.name
local_data = data.make_local()
local_data.name = f"{name}:{container_name}"
local_data.name = f"{container_name}:{name}"
return local_data


Expand Down Expand Up @@ -102,7 +95,7 @@ def get_local_collection_with_name(name):
return None


class Creator(PypeCreatorMixin, avalon.blender.Creator):
class Creator(PypeCreatorMixin, blender.Creator):
pass


Expand Down Expand Up @@ -173,6 +166,16 @@ def load(self,
name: Optional[str] = None,
namespace: Optional[str] = None,
options: Optional[Dict] = None) -> Optional[bpy.types.Collection]:
""" Run the loader on Blender main thread"""
mti = ops.MainThreadItem(self._load, context, name, namespace, options)
ops.execute_in_main_thread(mti)

def _load(self,
context: dict,
name: Optional[str] = None,
namespace: Optional[str] = None,
options: Optional[Dict] = None
) -> Optional[bpy.types.Collection]:
"""Load asset via database
Arguments:
Expand Down Expand Up @@ -218,16 +221,26 @@ def load(self,
# loader=self.__class__.__name__,
# )

asset = context["asset"]["name"]
subset = context["subset"]["name"]
instance_name = asset_name(asset, subset, unique_number) + '_CON'
# asset = context["asset"]["name"]
# subset = context["subset"]["name"]
# instance_name = asset_name(asset, subset, unique_number) + '_CON'

return self._get_instance_collection(instance_name, nodes)
# return self._get_instance_collection(instance_name, nodes)

def update(self, container: Dict, representation: Dict):
def exec_update(self, container: Dict, representation: Dict):
"""Must be implemented by a sub-class"""
raise NotImplementedError("Must be implemented by a sub-class")

def remove(self, container: Dict) -> bool:
def update(self, container: Dict, representation: Dict):
""" Run the update on Blender main thread"""
mti = ops.MainThreadItem(self.exec_update, container, representation)
ops.execute_in_main_thread(mti)

def exec_remove(self, container: Dict) -> bool:
"""Must be implemented by a sub-class"""
raise NotImplementedError("Must be implemented by a sub-class")

def remove(self, container: Dict) -> bool:
""" Run the remove on Blender main thread"""
mti = ops.MainThreadItem(self.exec_remove, container)
ops.execute_in_main_thread(mti)
44 changes: 33 additions & 11 deletions openpype/hosts/blender/plugins/create/create_animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import bpy

from avalon import api, blender
import openpype.hosts.blender.api.plugin
from avalon import api
from avalon.blender import lib, ops
from avalon.blender.pipeline import AVALON_INSTANCES
from openpype.hosts.blender.api import plugin


class CreateAnimation(openpype.hosts.blender.api.plugin.Creator):
class CreateAnimation(plugin.Creator):
"""Animation output for character rigs"""

name = "animationMain"
Expand All @@ -15,16 +17,36 @@ class CreateAnimation(openpype.hosts.blender.api.plugin.Creator):
icon = "male"

def process(self):
""" Run the creator on Blender main thread"""
mti = ops.MainThreadItem(self._process)
ops.execute_in_main_thread(mti)

def _process(self):
# Get Instance Containter 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 = self.name
# if not name:
asset = self.data["asset"]
subset = self.data["subset"]
name = openpype.hosts.blender.api.plugin.asset_name(asset, subset)
collection = bpy.data.collections.new(name=name)
bpy.context.scene.collection.children.link(collection)
name = plugin.asset_name(asset, subset)
# asset_group = bpy.data.objects.new(name=name, object_data=None)
# asset_group.empty_display_type = 'SINGLE_ARROW'
asset_group = bpy.data.collections.new(name=name)
instances.children.link(asset_group)
self.data['task'] = api.Session.get('AVALON_TASK')
blender.lib.imprint(collection, self.data)
lib.imprint(asset_group, self.data)

if (self.options or {}).get("useSelection"):
for obj in blender.lib.get_selection():
collection.objects.link(obj)

return collection
selected = lib.get_selection()
for obj in selected:
asset_group.objects.link(obj)
elif (self.options or {}).get("asset_group"):
obj = (self.options or {}).get("asset_group")
asset_group.objects.link(obj)

return asset_group
42 changes: 32 additions & 10 deletions openpype/hosts/blender/plugins/create/create_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import bpy

from avalon import api
from avalon.blender import lib
import openpype.hosts.blender.api.plugin
from avalon.blender import lib, ops
from avalon.blender.pipeline import AVALON_INSTANCES
from openpype.hosts.blender.api import plugin


class CreateLayout(openpype.hosts.blender.api.plugin.Creator):
class CreateLayout(plugin.Creator):
"""Layout output for character rigs"""

name = "layoutMain"
Expand All @@ -16,13 +17,34 @@ class CreateLayout(openpype.hosts.blender.api.plugin.Creator):
icon = "cubes"

def process(self):

""" Run the creator on Blender main thread"""
mti = ops.MainThreadItem(self._process)
ops.execute_in_main_thread(mti)

def _process(self):
# Get Instance Containter 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
asset = self.data["asset"]
subset = self.data["subset"]
name = openpype.hosts.blender.api.plugin.asset_name(asset, subset)
collection = bpy.context.collection
collection.name = name
name = plugin.asset_name(asset, subset)
asset_group = bpy.data.objects.new(name=name, object_data=None)
asset_group.empty_display_type = 'SINGLE_ARROW'
instances.objects.link(asset_group)
self.data['task'] = api.Session.get('AVALON_TASK')
lib.imprint(collection, self.data)

return collection
lib.imprint(asset_group, self.data)

# Add selected objects to instance
if (self.options or {}).get("useSelection"):
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
42 changes: 30 additions & 12 deletions openpype/hosts/blender/plugins/create/create_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import bpy

from avalon import api
from avalon.blender import lib
import openpype.hosts.blender.api.plugin
from avalon.blender import lib, ops
from avalon.blender.pipeline import AVALON_INSTANCES
from openpype.hosts.blender.api import plugin


class CreateModel(openpype.hosts.blender.api.plugin.Creator):
class CreateModel(plugin.Creator):
"""Polygonal static geometry"""

name = "modelMain"
Expand All @@ -16,17 +17,34 @@ class CreateModel(openpype.hosts.blender.api.plugin.Creator):
icon = "cube"

def process(self):

""" Run the creator on Blender main thread"""
mti = ops.MainThreadItem(self._process)
ops.execute_in_main_thread(mti)

def _process(self):
# Get Instance Containter 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
asset = self.data["asset"]
subset = self.data["subset"]
name = openpype.hosts.blender.api.plugin.asset_name(asset, subset)
collection = bpy.data.collections.new(name=name)
bpy.context.scene.collection.children.link(collection)
name = plugin.asset_name(asset, subset)
asset_group = bpy.data.objects.new(name=name, object_data=None)
asset_group.empty_display_type = 'SINGLE_ARROW'
instances.objects.link(asset_group)
self.data['task'] = api.Session.get('AVALON_TASK')
lib.imprint(collection, self.data)
lib.imprint(asset_group, self.data)

# Add selected objects to instance
if (self.options or {}).get("useSelection"):
for obj in lib.get_selection():
collection.objects.link(obj)

return collection
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
51 changes: 30 additions & 21 deletions openpype/hosts/blender/plugins/create/create_rig.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import bpy

from avalon import api
from avalon.blender import lib
import openpype.hosts.blender.api.plugin
from avalon.blender import lib, ops
from avalon.blender.pipeline import AVALON_INSTANCES
from openpype.hosts.blender.api import plugin


class CreateRig(openpype.hosts.blender.api.plugin.Creator):
class CreateRig(plugin.Creator):
"""Artist-friendly rig with controls to direct motion"""

name = "rigMain"
Expand All @@ -16,26 +17,34 @@ class CreateRig(openpype.hosts.blender.api.plugin.Creator):
icon = "wheelchair"

def process(self):

""" Run the creator on Blender main thread"""
mti = ops.MainThreadItem(self._process)
ops.execute_in_main_thread(mti)

def _process(self):
# Get Instance Containter 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
asset = self.data["asset"]
subset = self.data["subset"]
name = openpype.hosts.blender.api.plugin.asset_name(asset, subset)
collection = bpy.data.collections.new(name=name)
bpy.context.scene.collection.children.link(collection)
name = plugin.asset_name(asset, subset)
asset_group = bpy.data.objects.new(name=name, object_data=None)
asset_group.empty_display_type = 'SINGLE_ARROW'
instances.objects.link(asset_group)
self.data['task'] = api.Session.get('AVALON_TASK')
lib.imprint(collection, self.data)

# Add the rig object and all the children meshes to
# a set and link them all at the end to avoid duplicates.
# Blender crashes if trying to link an object that is already linked.
# This links automatically the children meshes if they were not
# selected, and doesn't link them twice if they, insted,
# were manually selected by the user.
lib.imprint(asset_group, self.data)

# Add selected objects to instance
if (self.options or {}).get("useSelection"):
for obj in lib.get_selection():
for child in obj.users_collection[0].children:
collection.children.link(child)
collection.objects.link(obj)

return collection
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
Loading

0 comments on commit f4e0b52

Please sign in to comment.