Implemented extraction of the animation and setdress

This commit is contained in:
Simone Barbieri 2020-09-30 17:11:32 +01:00
parent 525c4fe2f8
commit bce22acf35
3 changed files with 148 additions and 46 deletions

View file

@ -0,0 +1,56 @@
import os
import json
import pype.api
import pyblish.api
import bpy
class ExtractSetDress(pype.api.Extractor):
"""Extract setdress."""
label = "Extract SetDress"
hosts = ["blender"]
families = ["setdress"]
optional = True
order = pyblish.api.ExtractorOrder + 0.1
def process(self, instance):
stagingdir = self.staging_dir(instance)
json_data = []
for i in instance.context:
collection = i.data.get('name')
container = None
for obj in bpy.data.collections[collection].objects:
if obj.type == 'ARMATURE':
container_name = obj.get('avalon').get('container_name')
container = bpy.data.collections[container_name]
if container:
json_dict = {}
json_dict['subset'] = i.data.get('subset')
json_dict['container'] = container.name
json_dict['instance_name'] = container.get('avalon').get('instance_name')
json_data.append(json_dict)
if "representations" not in instance.data:
instance.data["representations"] = []
json_filename = f"{instance.name}.json"
json_path = os.path.join(stagingdir, json_filename)
with open(json_path, "w+") as file:
json.dump(json_data, fp=file, indent=2)
json_representation = {
'name': 'json',
'ext': 'json',
'files': json_filename,
"stagingDir": stagingdir,
}
instance.data["representations"].append(json_representation)
self.log.info("Extracted instance '{}' to: {}".format(
instance.name, json_representation))

View file

@ -17,14 +17,10 @@ class ExtractAnimationFBX(pype.api.Extractor):
def process(self, instance):
# Define extract output file path
stagingdir = self.staging_dir(instance)
filename = f"{instance.name}.fbx"
filepath = os.path.join(stagingdir, filename)
context = bpy.context
scene = context.scene
view_layer = context.view_layer
# Perform extraction
self.log.info("Performing extraction..")
@ -35,22 +31,6 @@ class ExtractAnimationFBX(pype.api.Extractor):
assert len(collections) == 1, "There should be one and only one " \
"collection collected for this asset"
old_active_layer_collection = view_layer.active_layer_collection
layers = view_layer.layer_collection.children
# Get the layer collection from the collection we need to export.
# This is needed because in Blender you can only set the active
# collection with the layer collection, and there is no way to get
# the layer collection from the collection
# (but there is the vice versa).
layer_collections = [
layer for layer in layers if layer.collection == collections[0]]
assert len(layer_collections) == 1
view_layer.active_layer_collection = layer_collections[0]
old_scale = scene.unit_settings.scale_length
# We set the scale of the scene for the export
@ -59,6 +39,15 @@ class ExtractAnimationFBX(pype.api.Extractor):
armatures = [
obj for obj in collections[0].objects if obj.type == 'ARMATURE']
assert len(collections) == 1, "There should be one and only one " \
"armature collected for this asset"
armature = armatures[0]
armature_name = armature.name
original_name = armature_name.split(':')[0]
armature.name = original_name
object_action_pairs = []
original_actions = []
@ -66,23 +55,23 @@ class ExtractAnimationFBX(pype.api.Extractor):
ending_frames = []
# For each armature, we make a copy of the current action
for obj in armatures:
curr_action = None
copy_action = None
curr_action = None
copy_action = None
if armature.animation_data and armature.animation_data.action:
curr_action = armature.animation_data.action
copy_action = curr_action.copy()
if obj.animation_data and obj.animation_data.action:
curr_frame_range = curr_action.frame_range
curr_action = obj.animation_data.action
copy_action = curr_action.copy()
starting_frames.append(curr_frame_range[0])
ending_frames.append(curr_frame_range[1])
else:
self.log.info("Object have no animation.")
return
curr_frame_range = curr_action.frame_range
starting_frames.append(curr_frame_range[0])
ending_frames.append(curr_frame_range[1])
object_action_pairs.append((obj, copy_action))
original_actions.append(curr_action)
object_action_pairs.append((armature, copy_action))
original_actions.append(curr_action)
# We compute the starting and ending frames
max_frame = min(starting_frames)
@ -96,44 +85,52 @@ class ExtractAnimationFBX(pype.api.Extractor):
do_clean=False
)
# We export the fbx
for obj in bpy.data.objects:
obj.select_set(False)
armature.select_set(True)
fbx_filename = f"{instance.name}_{armature.name}.fbx"
filepath = os.path.join(stagingdir, fbx_filename)
override = bpy.context.copy()
override['selected_objects'] = [armature]
bpy.ops.export_scene.fbx(
override,
filepath=filepath,
use_active_collection=True,
use_selection=True,
bake_anim_use_nla_strips=False,
bake_anim_use_all_actions=False,
add_leaf_bones=False
add_leaf_bones=False,
armature_nodetype='ROOT',
object_types={'ARMATURE'}
)
view_layer.active_layer_collection = old_active_layer_collection
armature.name = armature_name
armature.select_set(False)
scene.unit_settings.scale_length = old_scale
# We delete the baked action and set the original one back
for i in range(0, len(object_action_pairs)):
pair = object_action_pairs[i]
action = original_actions[i]
if action:
pair[0].animation_data.action = action
if pair[1]:
pair[1].user_clear()
bpy.data.actions.remove(pair[1])
if "representations" not in instance.data:
instance.data["representations"] = []
representation = {
fbx_representation = {
'name': 'fbx',
'ext': 'fbx',
'files': filename,
'files': fbx_filename,
"stagingDir": stagingdir,
}
instance.data["representations"].append(representation)
instance.data["representations"].append(fbx_representation)
self.log.info("Extracted instance '%s' to: %s",
instance.name, representation)
self.log.info("Extracted instance '{}' to: {}".format(
instance.name, fbx_representation))

View file

@ -0,0 +1,49 @@
import json
from avalon import io
import pyblish.api
class IntegrateAnimation(pyblish.api.InstancePlugin):
"""Generate a JSON file for animation."""
label = "Integrate Animation"
order = pyblish.api.IntegratorOrder + 0.1
optional = True
hosts = ["blender"]
families = ["setdress"]
def process(self, instance):
self.log.info("Integrate Animation")
representation = instance.data.get('representations')[0]
json_path = representation.get('publishedFiles')[0]
with open(json_path, "r") as file:
data = json.load(file)
# Update the json file for the setdress to add the published
# representations of the animations
for json_dict in data:
i = None
for elem in instance.context:
if elem.data.get('subset') == json_dict['subset']:
i = elem
break
if not i:
continue
rep = None
pub_repr = i.data.get('published_representations')
for elem in pub_repr:
if pub_repr.get(elem).get('representation').get('name') == "fbx":
rep = pub_repr.get(elem)
break
if not rep:
continue
obj_id = rep.get('representation').get('_id')
if obj_id:
json_dict['_id'] = str(obj_id)
with open(json_path, "w") as file:
json.dump(data, fp=file, indent=2)