Improved update for Geometry Caches

This commit is contained in:
Simone Barbieri 2023-10-05 11:49:19 +01:00
parent 671844fa07
commit 8392695623
2 changed files with 153 additions and 91 deletions

View file

@ -649,30 +649,43 @@ def generate_sequence(h, h_dir):
return sequence, (min_frame, max_frame)
def replace_static_mesh_actors(old_assets, new_assets):
def _get_comps_and_assets(
component_class, asset_class, old_assets, new_assets
):
eas = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
smes = unreal.get_editor_subsystem(unreal.StaticMeshEditorSubsystem)
comps = eas.get_all_level_actors_components()
static_mesh_comps = [
c for c in comps if isinstance(c, unreal.StaticMeshComponent)
components = [
c for c in comps if isinstance(c, component_class)
]
# Get all the static meshes among the old assets in a dictionary with
# the name as key
old_meshes = {}
selected_old_assets = {}
for a in old_assets:
asset = unreal.EditorAssetLibrary.load_asset(a)
if isinstance(asset, unreal.StaticMesh):
old_meshes[asset.get_name()] = asset
if isinstance(asset, asset_class):
selected_old_assets[asset.get_name()] = asset
# Get all the static meshes among the new assets in a dictionary with
# the name as key
new_meshes = {}
selected_new_assets = {}
for a in new_assets:
asset = unreal.EditorAssetLibrary.load_asset(a)
if isinstance(asset, unreal.StaticMesh):
new_meshes[asset.get_name()] = asset
if isinstance(asset, asset_class):
selected_new_assets[asset.get_name()] = asset
return components, selected_old_assets, selected_new_assets
def replace_static_mesh_actors(old_assets, new_assets):
smes = unreal.get_editor_subsystem(unreal.StaticMeshEditorSubsystem)
static_mesh_comps, old_meshes, new_meshes = _get_comps_and_assets(
unreal.StaticMeshComponent,
unreal.StaticMesh,
old_assets,
new_assets
)
for old_name, old_mesh in old_meshes.items():
new_mesh = new_meshes.get(old_name)
@ -685,28 +698,12 @@ def replace_static_mesh_actors(old_assets, new_assets):
def replace_skeletal_mesh_actors(old_assets, new_assets):
eas = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
comps = eas.get_all_level_actors_components()
skeletal_mesh_comps = [
c for c in comps if isinstance(c, unreal.SkeletalMeshComponent)
]
# Get all the static meshes among the old assets in a dictionary with
# the name as key
old_meshes = {}
for a in old_assets:
asset = unreal.EditorAssetLibrary.load_asset(a)
if isinstance(asset, unreal.SkeletalMesh):
old_meshes[asset.get_name()] = asset
# Get all the static meshes among the new assets in a dictionary with
# the name as key
new_meshes = {}
for a in new_assets:
asset = unreal.EditorAssetLibrary.load_asset(a)
if isinstance(asset, unreal.SkeletalMesh):
new_meshes[asset.get_name()] = asset
skeletal_mesh_comps, old_meshes, new_meshes = _get_comps_and_assets(
unreal.SkeletalMeshComponent,
unreal.SkeletalMesh,
old_assets,
new_assets
)
for old_name, old_mesh in old_meshes.items():
new_mesh = new_meshes.get(old_name)
@ -719,6 +716,25 @@ def replace_skeletal_mesh_actors(old_assets, new_assets):
comp.set_skeletal_mesh_asset(new_mesh)
def replace_geometry_cache_actors(old_assets, new_assets):
geometry_cache_comps, old_caches, new_caches = _get_comps_and_assets(
unreal.SkeletalMeshComponent,
unreal.SkeletalMesh,
old_assets,
new_assets
)
for old_name, old_mesh in old_caches.items():
new_mesh = new_caches.get(old_name)
if not new_mesh:
continue
for comp in geometry_cache_comps:
if comp.get_editor_property("geometry_cache") == old_mesh:
comp.set_geometry_cache(new_mesh)
def delete_previous_asset_if_unused(container, asset_content):
ar = unreal.AssetRegistryHelpers.get_asset_registry()

View file

@ -7,7 +7,12 @@ from openpype.pipeline import (
AYON_CONTAINER_ID
)
from openpype.hosts.unreal.api import plugin
from openpype.hosts.unreal.api import pipeline as unreal_pipeline
from openpype.hosts.unreal.api.pipeline import (
create_container,
imprint,
replace_geometry_cache_actors,
delete_previous_asset_if_unused,
)
import unreal # noqa
@ -21,8 +26,11 @@ class PointCacheAlembicLoader(plugin.Loader):
icon = "cube"
color = "orange"
root = "/Game/Ayon/Assets"
@staticmethod
def get_task(
self, filename, asset_dir, asset_name, replace,
filename, asset_dir, asset_name, replace,
frame_start=None, frame_end=None
):
task = unreal.AssetImportTask()
@ -38,8 +46,6 @@ class PointCacheAlembicLoader(plugin.Loader):
task.set_editor_property('automated', True)
task.set_editor_property('save', True)
# set import options here
# Unreal 4.24 ignores the settings. It works with Unreal 4.26
options.set_editor_property(
'import_type', unreal.AlembicImportType.GEOMETRY_CACHE)
@ -64,13 +70,42 @@ class PointCacheAlembicLoader(plugin.Loader):
return task
def load(self, context, name, namespace, data):
"""Load and containerise representation into Content Browser.
def import_and_containerize(
self, filepath, asset_dir, asset_name, container_name,
frame_start, frame_end
):
unreal.EditorAssetLibrary.make_directory(asset_dir)
This is two step process. First, import FBX to temporary path and
then call `containerise()` on it - this moves all content to new
directory and then it will create AssetContainer there and imprint it
with metadata. This will mark this path as container.
task = self.get_task(
filepath, asset_dir, asset_name, False, frame_start, frame_end)
unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task])
# Create Asset Container
create_container(container=container_name, path=asset_dir)
def imprint(
self, asset, asset_dir, container_name, asset_name, representation,
frame_start, frame_end
):
data = {
"schema": "ayon:container-2.0",
"id": AYON_CONTAINER_ID,
"asset": asset,
"namespace": asset_dir,
"container_name": container_name,
"asset_name": asset_name,
"loader": str(self.__class__.__name__),
"representation": representation["_id"],
"parent": representation["parent"],
"family": representation["context"]["family"],
"frame_start": frame_start,
"frame_end": frame_end
}
imprint(f"{asset_dir}/{container_name}", data)
def load(self, context, name, namespace, options):
"""Load and containerise representation into Content Browser.
Args:
context (dict): application context
@ -79,30 +114,28 @@ class PointCacheAlembicLoader(plugin.Loader):
This is not passed here, so namespace is set
by `containerise()` because only then we know
real path.
data (dict): Those would be data to be imprinted. This is not used
now, data are imprinted by `containerise()`.
data (dict): Those would be data to be imprinted.
Returns:
list(str): list of container content
"""
# Create directory for asset and Ayon container
root = "/Game/Ayon/Assets"
asset = context.get('asset').get('name')
suffix = "_CON"
if asset:
asset_name = "{}_{}".format(asset, name)
asset_name = f"{asset}_{name}" if asset else f"{name}"
version = context.get('version')
# Check if version is hero version and use different name
if not version.get("name") and version.get('type') == "hero_version":
name_version = f"{name}_hero"
else:
asset_name = "{}".format(name)
name_version = f"{name}_v{version.get('name'):03d}"
tools = unreal.AssetToolsHelpers().get_asset_tools()
asset_dir, container_name = tools.create_unique_asset_name(
"{}/{}/{}".format(root, asset, name), suffix="")
f"{self.root}/{asset}/{name_version}", suffix="")
container_name += suffix
unreal.EditorAssetLibrary.make_directory(asset_dir)
frame_start = context.get('asset').get('data').get('frameStart')
frame_end = context.get('asset').get('data').get('frameEnd')
@ -111,30 +144,17 @@ class PointCacheAlembicLoader(plugin.Loader):
if frame_start == frame_end:
frame_end += 1
path = self.filepath_from_context(context)
task = self.get_task(
path, asset_dir, asset_name, False, frame_start, frame_end)
if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir):
path = self.filepath_from_context(context)
unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # noqa: E501
# Create Asset Container
unreal_pipeline.create_container(
container=container_name, path=asset_dir)
self.import_and_containerize(
path, asset_dir, asset_name, container_name,
frame_start, frame_end)
data = {
"schema": "ayon:container-2.0",
"id": AYON_CONTAINER_ID,
"asset": asset,
"namespace": asset_dir,
"container_name": container_name,
"asset_name": asset_name,
"loader": str(self.__class__.__name__),
"representation": context["representation"]["_id"],
"parent": context["representation"]["parent"],
"family": context["representation"]["context"]["family"]
}
unreal_pipeline.imprint(
"{}/{}".format(asset_dir, container_name), data)
self.imprint(
asset, asset_dir, container_name, asset_name,
context["representation"], frame_start, frame_end)
asset_content = unreal.EditorAssetLibrary.list_assets(
asset_dir, recursive=True, include_folder=True
@ -146,32 +166,58 @@ class PointCacheAlembicLoader(plugin.Loader):
return asset_content
def update(self, container, representation):
name = container["asset_name"]
source_path = get_representation_path(representation)
destination_path = container["namespace"]
representation["context"]
context = representation.get("context", {})
task = self.get_task(source_path, destination_path, name, False)
# do import fbx and replace existing data
unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task])
unreal.log_warning(context)
container_path = "{}/{}".format(container["namespace"],
container["objectName"])
# update metadata
unreal_pipeline.imprint(
container_path,
{
"representation": str(representation["_id"]),
"parent": str(representation["parent"])
})
if not context:
raise RuntimeError("No context found in representation")
# Create directory for asset and Ayon container
asset = context.get('asset')
name = context.get('subset')
suffix = "_CON"
asset_name = f"{asset}_{name}" if asset else f"{name}"
version = context.get('version')
# Check if version is hero version and use different name
name_version = f"{name}_v{version:03d}" if version else f"{name}_hero"
tools = unreal.AssetToolsHelpers().get_asset_tools()
asset_dir, container_name = tools.create_unique_asset_name(
f"{self.root}/{asset}/{name_version}", suffix="")
container_name += suffix
frame_start = int(container.get("frame_start"))
frame_end = int(container.get("frame_end"))
if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir):
path = get_representation_path(representation)
self.import_and_containerize(
path, asset_dir, asset_name, container_name,
frame_start, frame_end)
self.imprint(
asset, asset_dir, container_name, asset_name, representation,
frame_start, frame_end)
asset_content = unreal.EditorAssetLibrary.list_assets(
destination_path, recursive=True, include_folder=True
asset_dir, recursive=True, include_folder=False
)
for a in asset_content:
unreal.EditorAssetLibrary.save_asset(a)
old_assets = unreal.EditorAssetLibrary.list_assets(
container["namespace"], recursive=True, include_folder=False
)
replace_geometry_cache_actors(old_assets, asset_content)
unreal.EditorLevelLibrary.save_current_level()
delete_previous_asset_if_unused(container, old_assets)
def remove(self, container):
path = container["namespace"]
parent_path = os.path.dirname(path)