def version_updater(logging_level=logging.WARNING): """helper function for version_updater UI for Maya """ # connect to db do_db_setup() # use PySide for Maya 2014 import pymel try: if pymel.versions.current() >= pymel.versions.v2014: from anima import ui ui.SET_PYSIDE() except AttributeError: pass from anima.ui import version_updater, models from anima.env import mayaEnv reload(mayaEnv) reload(version_updater) reload(models) m = Maya() m.name = "Maya" + str(pymel.versions.current())[0:4] logger.setLevel(logging_level) # generate a reference_resolution version_updater.UI(environment=m)
def from_edl(self, path): """Parses EDL file and returns a Sequence instance which reflects the whole time line hierarchy. :param path: The path of the XML file :return: :class:`.Sequence` """ if not isinstance(path, str): raise TypeError( 'path argument in %s.from_edl should be a string, not %s' % (self.__class__.__name__, path.__class__.__name__) ) from anima.env.mayaEnv import Maya m = Maya() fps = m.get_fps() import edl p = edl.Parser(str(fps)) with open(path) as f: l = p.parse(f) seq = Sequence() seq.from_edl(l) self.from_seq(seq)
def check_if_previous_version_references(): """check if a previous version of the same task is referenced to the scene """ from anima.env.mayaEnv import Maya m = Maya() ver = m.get_current_version() if ver is None: return same_version_references = [] for ref in pm.listReferences(): # check only 1st level references ref_version = m.get_version_from_full_path(ref.path) if ref_version: if ref_version.task == ver.task \ and ref_version.take_name == ver.take_name: same_version_references.append(ref) if len(same_version_references): print('The following nodes are references to an older version of this ' 'scene') print('\n'.join( map(lambda x: x.refNode.name(), same_version_references))) raise PublishError( 'The current scene contains a <b>reference</b> to a<br>' '<b>previous version</b> of itself.<br><br>' 'Please remove it!!!')
def check_if_previous_version_references(): """check if a previous version of the same task is referenced to the scene """ from anima.env.mayaEnv import Maya m = Maya() ver = m.get_current_version() if ver is None: return same_version_references = [] for ref in pm.listReferences(): # check only 1st level references ref_version = m.get_version_from_full_path(ref.path) if ref_version: if ref_version.task == ver.task \ and ref_version.take_name == ver.take_name: same_version_references.append(ref) if len(same_version_references): print('The following nodes are references to an older version of this ' 'scene') print( '\n'.join(map(lambda x: x.refNode.name(), same_version_references)) ) raise PublishError( 'The current scene contains a <b>reference</b> to a<br>' '<b>previous version</b> of itself.<br><br>' 'Please remove it!!!' )
def archive_current_scene(cls): """archives the current scene """ # before doing anything ask it response = pm.confirmDialog( title='Do Archive?', message='This will create a ZIP file containing\n' 'the current scene and all its references\n' '\n' 'Is that OK?', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if response == 'No': return import os import shutil import anima from anima.env.mayaEnv import Maya from anima.env.mayaEnv.archive import Archiver m_env = Maya() version = m_env.get_current_version() if version: path = version.absolute_full_path arch = Archiver() task = version.task if False: from stalker import Version, Task assert (isinstance(version, Version)) assert (isinstance(task, Task)) # project_name = version.nice_name project_name = os.path.splitext( os.path.basename(version.absolute_full_path))[0] project_path = arch.flatten(path, project_name=project_name) # append link file stalker_link_file_path = \ os.path.join(project_path, 'scenes/stalker_links.txt') version_upload_link = '%s/tasks/%s/versions/list' % ( anima.defaults.stalker_server_external_address, task.id) request_review_link = '%s/tasks/%s/view' % ( anima.defaults.stalker_server_external_address, task.id) with open(stalker_link_file_path, 'w+') as f: f.write("Version Upload Link: %s\n" "Request Review Link: %s\n" % (version_upload_link, request_review_link)) zip_path = arch.archive(project_path) new_zip_path = os.path.join(version.absolute_path, os.path.basename(zip_path)) # move the zip right beside the original version file shutil.move(zip_path, new_zip_path) # open the zip file in browser from anima.utils import open_browser_in_location open_browser_in_location(new_zip_path)
def archive_current_scene(cls): """archives the current scene """ from anima.env.mayaEnv import Maya from anima.env.mayaEnv.archive import Archiver from anima.utils.archive import archive_current_scene m_env = Maya() version = m_env.get_current_version() archiver = Archiver() archive_current_scene(version, archiver)
def playblast_on_farm(cls): """Submits playblast creation jobs to Afanasy """ from anima.env.mayaEnv import Maya, afanasy_publisher m = Maya() v = m.get_current_version() if v: afanasy_publisher.submit_playblast_job( v.absolute_full_path, project_code=v.task.project.code) else: raise RuntimeError("This scene is not a Stalker version!")
def repr(self): """the representation name of the related version """ from anima.env.mayaEnv import Maya m = Maya() v = m.get_version_from_full_path(self.path) if v is None: return None rep = Representation(version=v) return rep.repr
def __init__(self): self.mEnv = Maya() self.width = 265 self.height = 300 self.row_spacing = 3 self.window = None self.window_name = 'Previz_Window' self.window_title = "Previz Tools v%s" % anima.__version__ self.edl_checkBox = None self.mxf_checkBox = None
def __init__(self, version=None): local_session = LocalSession() self.logged_in_user = local_session.logged_in_user if not self.logged_in_user: raise RuntimeError('Please login first!') from anima.env.mayaEnv import Maya self.maya_env = Maya() self.base_take_name = None self.version = version
def get_base(self): """returns the base version instance """ from anima.env.mayaEnv import Maya m = Maya() v = m.get_version_from_full_path(self.path) if v is None: return True rep = Representation(version=v) return rep.find(rep.base_repr_name)
def is_base(self): """returns True or False depending to if this is the base representation for this reference """ from anima.env.mayaEnv import Maya m = Maya() v = m.get_version_from_full_path(self.path) if v is None: return True rep = Representation(version=v) return rep.is_base()
def has_repr(self, repr_name): """checks if the reference has the given representation :param str repr_name: The name of the desired representation :return: """ from anima.env.mayaEnv import Maya m = Maya() v = m.get_version_from_full_path(self.path) if v is None: return False rep = Representation(version=v) return rep.has_repr(repr_name)
def is_repr(self, repr_name): """returns True or False depending to if this is the requested repr :param str repr_name: The representation name :return: """ from anima.env.mayaEnv import Maya m = Maya() v = m.get_version_from_full_path(self.path) if v is None: return False rep = Representation(version=v) return rep.is_repr(repr_name=repr_name)
def list_all_repr(self): """Returns a list of strings representing all the representation names of this FileReference :return: list of str """ from anima.env.mayaEnv import Maya m = Maya() v = m.get_version_from_full_path(self.path) if v is None: return [] rep = Representation(version=v) return rep.list_all()
def find_repr(self, repr_name): """Finds the representation with the given repr_name. :param str repr_name: The desired repr name :return: :class:`.Version` """ from anima.env.mayaEnv import Maya m = Maya() v = m.get_version_from_full_path(self.path) if v is None: return rep = Representation(version=v) rep_v = rep.find(repr_name) return rep_v
def version_creator(logging_level=logging.WARNING): """Helper function for version_creator UI for Maya """ # connect to db do_db_setup() # use PySide for Maya 2014 set_qt_lib() from anima.ui import version_creator, models from anima.env import mayaEnv reload(version_creator) reload(models) reload(mayaEnv) m = Maya() import pymel m.name = "Maya%s" % str(pymel.versions.current())[0:4] logger.setLevel(logging_level) version_creator.UI(environment=m)
def version_updater(logging_level=logging.WARNING): """helper function for version_updater UI for Maya """ # connect to db do_db_setup() # set Qt lib set_qt_lib() from anima.ui import version_updater, models from anima.env import mayaEnv reload(mayaEnv) reload(version_updater) reload(models) m = Maya() import pymel m.name = "Maya" + str(pymel.versions.current())[0:4] logger.setLevel(logging_level) # generate a reference_resolution version_updater.UI(environment=m)
def generate_repr_of_all_references(cls, generate_gpu=True, generate_ass=True, generate_rs=True, skip_existing=False): """generates all representations of all references of this scene """ from anima.ui.progress_dialog import ProgressDialogManager from anima.env.mayaEnv import Maya, repr_tools, auxiliary reload(auxiliary) reload(repr_tools) paths_visited = [] versions_to_visit = [] versions_cannot_be_published = [] # generate a sorted version list # and visit each reference only once from anima.env.mayaEnv import MayaMainProgressBarWrapper wrp = MayaMainProgressBarWrapper() pdm = ProgressDialogManager(dialog=wrp) use_progress_window = False if not pm.general.about(batch=1): use_progress_window = True all_refs = pm.listReferences(recursive=True) pdm.use_ui = use_progress_window caller = pdm.register(len(all_refs), 'List References') for ref in reversed(all_refs): ref_path = str(ref.path) caller.step(message=ref_path) if ref_path not in paths_visited: v = ref.version if v is not None: paths_visited.append(ref_path) versions_to_visit.append(v) response = pm.confirmDialog( title='Do Create Representations?', message='Create all Repr. for all %s FileReferences?' % len(versions_to_visit), button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return # register a new caller caller = pdm.register(max_iteration=len(versions_to_visit), title='Generate Reprs') m_env = Maya() source_version = m_env.get_current_version() gen = repr_tools.RepresentationGenerator() # open each version from stalker import Version for v in versions_to_visit: local_generate_gpu = generate_gpu local_generate_ass = generate_ass local_generate_rs = generate_rs # check if this is a repr if '@' in v.take_name: # use the parent v = v.parent if not v: continue if skip_existing: # check if there is a GPU or ASS repr # generated from this version child_versions = Version.query.filter(Version.parent == v).all() for cv in child_versions: if local_generate_gpu is True and '@GPU' in cv.take_name: local_generate_gpu = False if local_generate_ass is True and '@ASS' in cv.take_name: local_generate_ass = False if local_generate_rs is True and '@RS' in cv.take_name: local_generate_rs = False gen.version = v # generate representations if local_generate_gpu: try: gen.generate_gpu() except RuntimeError: if v not in versions_cannot_be_published: versions_cannot_be_published.append(v) if local_generate_ass: try: gen.generate_ass() except RuntimeError: if v not in versions_cannot_be_published: versions_cannot_be_published.append(v) if local_generate_rs: try: gen.generate_rs() except RuntimeError: if v not in versions_cannot_be_published: versions_cannot_be_published.append(v) caller.step() # now open the source version again m_env.open(source_version, force=True, skip_update_check=True) # and generate representation for the source gen.version = source_version # generate representations if not versions_cannot_be_published: if generate_gpu: gen.generate_gpu() if generate_ass: gen.generate_ass() if generate_rs: gen.generate_rs() else: pm.confirmDialog( title='Error', message='The following versions can not be published ' '(check script editor):\n\n%s' % ( '\n'.join( map(lambda x: x.nice_name, versions_cannot_be_published) ) ), button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) pm.error( '\n'.join( map(lambda x: x.absolute_full_path, versions_cannot_be_published) ) )
def generate_repr_of_scene(cls, generate_gpu=True, generate_ass=True, generate_rs=True, skip_existing=False): """generates desired representations of this scene """ from anima.ui.progress_dialog import ProgressDialogManager from anima.env.mayaEnv import Maya, repr_tools, auxiliary reload(auxiliary) reload(repr_tools) response = pm.confirmDialog( title='Do Create Representations?', message='Create all Repr. for this scene?', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return # register a new caller from anima.env.mayaEnv import MayaMainProgressBarWrapper wrp = MayaMainProgressBarWrapper() pdm = ProgressDialogManager(dialog=wrp) m_env = Maya() source_version = m_env.get_current_version() gen = repr_tools.RepresentationGenerator() # open each version from stalker import Version if skip_existing: # check if there is a GPU or ASS repr # generated from this version child_versions = \ Version.query.filter(Version.parent == source_version).all() for cv in child_versions: if generate_gpu is True and '@GPU' in cv.take_name: generate_gpu = False if generate_ass is True and '@ASS' in cv.take_name: generate_ass = False if generate_rs is True and '@RS' in cv.take_name: generate_rs = False total_number_of_reprs = generate_gpu + generate_ass + generate_rs caller = pdm.register(total_number_of_reprs, title='Generate Reprs') gen.version = source_version # generate representations if generate_gpu: gen.generate_gpu() caller.step() if generate_ass: gen.generate_ass() caller.step() if generate_rs: gen.generate_rs() caller.step() # now open the source version again m_env.open(source_version, force=True, skip_update_check=True)
class RepresentationGenerator(object): """Generates different representations of the current scene """ def __init__(self, version=None): local_session = LocalSession() self.logged_in_user = local_session.logged_in_user if not self.logged_in_user: raise RuntimeError('Please login first!') from anima.env.mayaEnv import Maya self.maya_env = Maya() self.base_take_name = None self.version = version @classmethod def get_local_root_nodes(cls): """returns the root nodes that are not referenced """ return [node for node in auxiliary.get_root_nodes() if node.referenceFile() is None] def get_latest_repr_version(self, take_name): """returns the latest published version or creates a new version :param str take_name: The take_name :return: """ from stalker import Version # filter to get the latest published version v = Version.query\ .filter(Version.task == self.version.task)\ .filter(Version.take_name == take_name)\ .filter(Version.is_published == True)\ .order_by(Version.version_number.desc())\ .first() if v is None: # create a new version v = Version( created_by=self.logged_in_user, task=self.version.task, take_name=take_name ) v.is_published = True else: # change updated by v.updated_by = self.logged_in_user return v @classmethod def is_model_task(cls, task): """checks if the given task is a model task :param task: A Stalker Task instance """ task_type = task.type if task_type: # check the task type name if task_type.name.lower() in ['model']: return True else: # check the task name if task.name.lower() in ['model']: return True # if we came here it must not be a model task return False @classmethod def is_look_dev_task(cls, task): """checks if the given task is a look development task :param task: A Stalker Task instance """ task_type = task.type if task_type: # check the task type name if task_type.name.lower() in ['look development']: return True else: # check the task name if task.name.lower() in ['look_dev', 'lookdev', 'look dev']: return True # if we came here it must not be a look dev task task return False @classmethod def is_scene_assembly_task(cls, task): """checks if the given task is a scene assembly task :param task: A Stalker Task instance """ task_type = task.type if task_type: # check the task type name if task_type.name.lower() in ['scene assembly']: return True else: # check the task name if task.name.lower() in ['scene assembly']: return True # if we came here it must not be a scene assembly task task return False @classmethod def is_vegetation_task(cls, task): """checks if the given task is a vegetation task :param task: A Stalker Task instance """ task_type = task.type if task_type: # check the task type name if task_type.name.lower() in ['vegetation']: return True else: # check the task name if task.name.lower() in ['vegetation']: return True # if we came here it must not be a vegetation task task return False @classmethod def is_exterior_or_interior_task(cls, task): """checks if the given task is the first Layout task of an Exterior or Interior task. :param task: a stalker.task :return: """ if task.type and task.type.name.lower() == 'layout': parent = task.parent if task.name.lower() == 'hires': if parent and parent.parent and parent.parent.type \ and parent.parent.type.name.lower() in ['exterior', 'interior']: return True elif task.name.lower() == 'layout': if parent and parent.type \ and parent.type.name.lower() in ['exterior', 'interior']: return True return False def _validate_version(self, version): """validates the given version value :param version: A stalker.model.version.Version instance :return: """ if not version: raise RuntimeError( 'Please supply a valid Stalker Version object!' ) from stalker import Version if not isinstance(version, Version): raise TypeError( 'version should be a stalker.models.version.Version instance' ) r = Representation(version=version) self.base_take_name = r.get_base_take_name(version) if not r.is_base(): raise RuntimeError( 'This is not a Base take for this representation series, ' 'please open the base (%s) take!!!' % self.base_take_name ) return version def open_version(self, version=None): """Opens the given version :param version: A stalker.models.version.Version instance :return: """ current_v = self.maya_env.get_current_version() if current_v is not version: self.maya_env.open(version, force=True, skip_update_check=True, reference_depth=3) @classmethod def make_unique(cls, filename, force=True): """Generates a unique filename if the file already exists :param filename: :return: """ import uuid def generate_filename(): random_part = uuid.uuid4().hex[-4:] data = os.path.splitext(filename) return '%s_%s%s' % (data[0], random_part, data[1]) if not force: if os.path.exists(filename): new_filename = generate_filename() while os.path.exists(new_filename): new_filename = generate_filename() return new_filename else: return filename else: return generate_filename() def generate_all(self): """generates all representations at once """ self.generate_gpu() self.generate_ass() def generate_bbox(self): """generates the BBox representation of the current scene """ # validate the version first self.version = self._validate_version(self.version) self.open_version(self.version) task = self.version.task # check if all references have an BBOX repr first refs_with_no_bbox_repr = [] for ref in pm.listReferences(): if ref.version and not ref.has_repr('BBOX'): refs_with_no_bbox_repr.append(ref) if len(refs_with_no_bbox_repr): raise RuntimeError( 'Please generate the BBOX Representation of the references ' 'first!!!\n%s' % '\n'.join(map(lambda x: str(x.path), refs_with_no_bbox_repr)) ) # do different things for Vegetation tasks if self.is_vegetation_task(task): # load all references back for ref in pm.listReferences(): ref.load() # find the _pfxPolygons node pfx_polygons_node = pm.PyNode('kks___vegetation_pfxPolygons') all_children = [] for node in pfx_polygons_node.getChildren(): for child_node in node.getChildren(): all_children.append(child_node) auxiliary.replace_with_bbox(all_children) # clean up other nodes pm.delete('kks___vegetation_pfxStrokes') pm.delete('kks___vegetation_paintableGeos') elif self.is_scene_assembly_task(task): # reload all references # replace all root references with their BBOX representation for ref in pm.listReferences(): ref.to_repr('BBOX') else: # find all non referenced root nodes root_nodes = self.get_local_root_nodes() if len(root_nodes): all_children = [] for root_node in root_nodes: for child in root_node.getChildren(): all_children.append(child) auxiliary.replace_with_bbox(all_children) # reload all references # replace all root references with their BBOX representation for ref in pm.listReferences(): ref.to_repr('BBOX') # if this is an Exterior/Interior -> Layout -> Hires task flatten it if self.is_exterior_or_interior_task(task): # and import all of the references all_refs = pm.listReferences() while len(all_refs) != 0: for ref in all_refs: if not ref.isLoaded(): ref.load() ref.importContents() all_refs = pm.listReferences() # save the scene as {{original_take}}___BBOX # use maya take_name = '%s%s%s' % ( self.base_take_name, Representation.repr_separator, 'BBOX' ) v = self.get_latest_repr_version(take_name) self.maya_env.save_as(v) # reopen the original version pm.newFile(force=True) def generate_proxy(self): """generates the Proxy representation of the current scene """ pass def generate_gpu(self): """generates the GPU representation of the current scene """ # validate the version first self.version = self._validate_version(self.version) self.open_version(self.version) # load necessary plugins pm.loadPlugin('gpuCache') pm.loadPlugin('AbcExport') pm.loadPlugin('AbcImport') # check if all references have an GPU repr first refs_with_no_gpu_repr = [] for ref in pm.listReferences(): if ref.version and not ref.has_repr('GPU'): refs_with_no_gpu_repr.append(ref) if len(refs_with_no_gpu_repr): raise RuntimeError( 'Please generate the GPU Representation of the references ' 'first!!!\n%s' % '\n'.join(map(lambda x: str(x.path), refs_with_no_gpu_repr)) ) # unload all references for ref in pm.listReferences(): ref.unload() # for local models generate an ABC file output_path = os.path.join( self.version.absolute_path, 'Outputs/alembic/' ).replace('\\', '/') abc_command = \ 'AbcExport -j "-frameRange %(start_frame)s ' \ '%(end_frame)s ' \ '-ro -stripNamespaces ' \ '-uvWrite ' \ '-wholeFrameGeo ' \ '-worldSpace ' \ '-root |%(node)s -file %(file_path)s";' gpu_command = \ 'gpuCache -startTime %(start_frame)s ' \ '-endTime %(end_frame)s ' \ '-optimize -optimizationThreshold 40000 ' \ '-writeMaterials ' \ '-directory "%(path)s" ' \ '-fileName "%(filename)s" ' \ '%(node)s;' start_frame = end_frame = int(pm.currentTime(q=1)) if not self.is_scene_assembly_task(self.version.task): if self.is_vegetation_task(self.version.task): # in vegetation files, we export the GPU files directly from # the Base version, also we use the geometry under # "pfxPolygons" and parent the resulting Stand-In nodes to the # pfxPolygons # load all references for ref in pm.listReferences(): ref.load() # find the _pfxPolygons node pfx_polygons_node = pm.PyNode('kks___vegetation_pfxPolygons') for node in pfx_polygons_node.getChildren(): for child_node in node.getChildren(): child_node_name = child_node.name().split('___')[-1] child_node_shape = child_node.getShape() child_node_shape_name = None if child_node_shape: child_node_shape_name = child_node_shape.name() pm.select(child_node) temp_output_fullpath = \ tempfile.mktemp().replace('\\', '/') temp_output_path, temp_output_filename = \ os.path.split(temp_output_fullpath) output_filename = '%s_%s' % ( self.version.nice_name, child_node_name.split(':')[-1] .replace(':', '_') .replace('|', '_') ) # run the mel command # check if file exists pm.mel.eval( gpu_command % { 'start_frame': start_frame, 'end_frame': end_frame, 'node': child_node.fullPath(), 'path': temp_output_path, 'filename': temp_output_filename } ) cache_file_full_path = \ os.path\ .join(output_path, output_filename + '.abc')\ .replace('\\', '/') # create the intermediate directories try: os.makedirs( os.path.dirname(cache_file_full_path) ) except OSError: # directory exists pass # now move in to its place shutil.move( temp_output_fullpath + '.abc', cache_file_full_path ) # set rotate and scale pivots rp = pm.xform(child_node, q=1, ws=1, rp=1) sp = pm.xform(child_node, q=1, ws=1, sp=1) #child_node.setRotatePivotTranslation([0, 0, 0]) # delete the child and add a GPU node instead pm.delete(child_node) # check if file exists and create nodes if os.path.exists(cache_file_full_path): gpu_node = pm.createNode('gpuCache') gpu_node_tra = gpu_node.getParent() pm.parent(gpu_node_tra, node) gpu_node_tra.rename(child_node_name) if child_node_shape_name is not None: gpu_node.rename(child_node_shape_name) pm.xform(gpu_node_tra, ws=1, rp=rp) pm.xform(gpu_node_tra, ws=1, sp=sp) gpu_node.setAttr( 'cacheFileName', cache_file_full_path, type="string" ) else: print('File not found!: %s' % cache_file_full_path) # clean up other nodes pm.delete('kks___vegetation_pfxStrokes') pm.delete('kks___vegetation_paintableGeos') else: root_nodes = self.get_local_root_nodes() if len(root_nodes): for root_node in root_nodes: # export each child of each root as separate nodes for child_node in root_node.getChildren(): # check if it is a transform node if not isinstance(child_node, pm.nt.Transform): continue if not auxiliary.has_shape(child_node): continue child_name = child_node.name() child_shape = child_node.getShape() child_shape_name = None if child_shape: child_shape_name = child_shape.name() child_full_path = \ child_node.fullPath()[1:].replace('|', '_') temp_output_fullpath = \ tempfile.mktemp().replace('\\', '/') temp_output_path, temp_output_filename = \ os.path.split(temp_output_fullpath) output_filename =\ '%s_%s' % ( self.version.nice_name, child_full_path ) # run the mel command # check if file exists pm.mel.eval( gpu_command % { 'start_frame': start_frame, 'end_frame': end_frame, 'node': child_node.fullPath(), 'path': temp_output_path, 'filename': temp_output_filename } ) cache_file_full_path = \ os.path\ .join( output_path, '%s.abc' % ( output_filename ) )\ .replace('\\', '/') # create the intermediate directories try: os.makedirs( os.path.dirname(cache_file_full_path) ) except OSError: # directory exists pass # now move in to its place shutil.move( temp_output_fullpath + '.abc', cache_file_full_path ) # set rotate and scale pivots rp = pm.xform(child_node, q=1, ws=1, rp=1) sp = pm.xform(child_node, q=1, ws=1, sp=1) # rpt = child_node.getRotatePivotTranslation() # delete the child and add a GPU node instead pm.delete(child_node) # check if file exists if os.path.exists(cache_file_full_path): gpu_node = pm.createNode('gpuCache') gpu_node_tra = gpu_node.getParent() pm.parent(gpu_node_tra, root_node) gpu_node_tra.rename(child_name) if child_shape_name is not None: gpu_node.rename(child_shape_name) pm.xform(gpu_node_tra, ws=1, rp=rp) pm.xform(gpu_node_tra, ws=1, sp=sp) # child_node.setRotatePivotTranslation(rpt) gpu_node.setAttr( 'cacheFileName', cache_file_full_path, type="string" ) # load all references again # convert all references to GPU logger.debug('converting all references to GPU') for ref in pm.listReferences(): # check if this is a Model reference ref.to_repr('GPU') ref.load() # if this is an Exterior/Interior -> Layout -> Hires task flatten it task = self.version.task is_exterior_or_interior_task = self.is_exterior_or_interior_task(task) if is_exterior_or_interior_task: logger.debug('importing all references') # and import all of the references all_refs = pm.listReferences() while len(all_refs) != 0: for ref in all_refs: if not ref.isLoaded(): ref.load() ref.importContents() all_refs = pm.listReferences() # assign lambert1 to all GPU nodes pm.sets('initialShadingGroup', e=1, fe=auxiliary.get_root_nodes()) # clean up self.clean_up() # 6. save the scene as {{original_take}}___GPU # use maya take_name = '%s%s%s' % ( self.base_take_name, Representation.repr_separator, 'GPU' ) v = self.get_latest_repr_version(take_name) self.maya_env.save_as(v) # export the root nodes under the same file if is_exterior_or_interior_task: logger.debug('exporting root nodes') pm.select(auxiliary.get_root_nodes()) pm.exportSelected( v.absolute_full_path, type='mayaAscii', force=True ) logger.debug('renewing scene') # clear scene pm.newFile(force=True) def make_tx(self, texture_path): """converts the given texture to TX """ tx_path = ''.join([os.path.splitext(texture_path)[0], '.tx']) # generate if not exists if not os.path.exists(tx_path): cmd = 'maketx -o "%s" -u --oiio %s' % (tx_path, texture_path) if os.name == 'nt': proc = subprocess.Popen( cmd, creationflags=subprocess.SW_HIDE, shell=True ) else: proc = subprocess.Popen( cmd, shell=True ) proc.wait() return tx_path @classmethod def clean_up(self): """cleans up the scene """ num_of_items_deleted = pm.mel.eval('MLdeleteUnused') logger.debug('deleting unknown references') delete_nodes_types = ['reference', 'unknown'] for node in pm.ls(type=delete_nodes_types): node.unlock() logger.debug('deleting "delete_nodes_types"') try: pm.delete(pm.ls(type=delete_nodes_types)) except RuntimeError: pass def generate_ass(self): """generates the ASS representation of the current scene For Model Tasks the ASS is generated over the LookDev Task because it is not possible to assign a material to an object inside an ASS file. """ # before doing anything, check if this is a look dev task # and export the objects from the referenced files with their current # shadings, then replace all of the references to ASS repr and than # add Stand-in nodes and parent them under the referenced models # load necessary plugins pm.loadPlugin('mtoa') # disable "show plugin shapes" active_panel = auxiliary.Playblaster.get_active_panel() show_plugin_shapes = pm.modelEditor(active_panel, q=1, pluginShapes=1) pm.modelEditor(active_panel, e=1, pluginShapes=False) # validate the version first self.version = self._validate_version(self.version) self.open_version(self.version) task = self.version.task # export_command = 'arnoldExportAss -f "%(path)s" -s -mask 24 ' \ # '-lightLinks 0 -compressed -boundingBox ' \ # '-shadowLinks 0 -cam perspShape;' export_command = 'arnoldExportAss -f "%(path)s" -s -mask 60' \ '-lightLinks 1 -compressed -boundingBox ' \ '-shadowLinks 1 -cam perspShape;' # calculate output path output_path = \ os.path.join(self.version.absolute_path, 'Outputs/ass/')\ .replace('\\', '/') # check if all references have an ASS repr first refs_with_no_ass_repr = [] for ref in pm.listReferences(): if ref.version and not ref.has_repr('ASS'): refs_with_no_ass_repr.append(ref) if len(refs_with_no_ass_repr): raise RuntimeError( 'Please generate the ASS Representation of the references ' 'first!!!\n%s' % '\n'.join(map(lambda x: str(x.path), refs_with_no_ass_repr)) ) if self.is_look_dev_task(task): # in look dev files, we export the ASS files directly from the Base # version and parent the resulting Stand-In node to the parent of # the child node # load only Model references for ref in pm.listReferences(): v = ref.version load_ref = False if v: ref_task = v.task if self.is_model_task(ref_task): load_ref = True if load_ref: ref.load() ref.importContents() # Make all texture paths relative # replace all "$REPO#" from all texture paths first # # This is needed to properly render textures with any OS types_and_attrs = { 'aiImage': 'filename', 'file': 'fileTextureName', 'imagePlane': 'imageName' } for node_type in types_and_attrs.keys(): attr_name = types_and_attrs[node_type] for node in pm.ls(type=node_type): orig_path = node.getAttr(attr_name).replace("\\", "/") path = re.sub( r'(\$REPO[0-9/]+)', '', orig_path ) tx_path = self.make_tx(path) inputs = node.attr(attr_name).inputs(p=1) if len(inputs): # set the input attribute for input_node_attr in inputs: input_node_attr.set(tx_path) else: node.setAttr(attr_name, tx_path) # randomize all render node names # This is needed to prevent clashing of materials in a bigger scene for node in pm.ls(type=RENDER_RELATED_NODE_TYPES): if node.referenceFile() is None and \ node.name() not in READ_ONLY_NODE_NAMES: node.rename('%s_%s' % (node.name(), uuid.uuid4().hex)) nodes_to_ass_files = {} # export all root ass files as they are for root_node in auxiliary.get_root_nodes(): for child_node in root_node.getChildren(): # check if it is a transform node if not isinstance(child_node, pm.nt.Transform): continue if not auxiliary.has_shape(child_node): continue # randomize child node name # TODO: This is not working as intended, node names are like |NS:node1|NS:node2 # resulting a child_node_name as "node2" child_node_name = child_node\ .fullPath()\ .replace('|', '_')\ .split(':')[-1] child_node_full_path = child_node.fullPath() pm.select(child_node) child_node.rename('%s_%s' % (child_node.name(), uuid.uuid4().hex)) output_filename =\ '%s_%s.ass' % ( self.version.nice_name, child_node_name ) output_full_path = \ os.path.join(output_path, output_filename) # run the mel command pm.mel.eval( export_command % { 'path': output_full_path.replace('\\', '/') } ) nodes_to_ass_files[child_node_full_path] = \ '%s.gz' % output_full_path # print('%s -> %s' % ( # child_node_full_path, # output_full_path) # ) # reload the scene pm.newFile(force=True) self.open_version(self.version) # convert all references to ASS # we are doing it a little bit early here, but we need to for ref in pm.listReferences(): ref.to_repr('ASS') all_stand_ins = pm.ls(type='aiStandIn') for ass_node in all_stand_ins: ass_tra = ass_node.getParent() full_path = ass_tra.fullPath() if full_path in nodes_to_ass_files: ass_file_path = \ Repository.to_os_independent_path( nodes_to_ass_files[full_path] ) ass_node.setAttr('dso', ass_file_path) elif self.is_vegetation_task(task): # in vegetation files, we export the ASS files directly from the # Base version, also we use the geometry under "pfxPolygons" # and parent the resulting Stand-In nodes to the # pfxPolygons # load all references for ref in pm.listReferences(): ref.load() # Make all texture paths relative # replace all "$REPO#" from all texture paths first # # This is needed to properly render textures with any OS types_and_attrs = { 'aiImage': 'filename', 'file': 'fileTextureName', 'imagePlane': 'imageName' } for node_type in types_and_attrs.keys(): attr_name = types_and_attrs[node_type] for node in pm.ls(type=node_type): orig_path = node.getAttr(attr_name).replace("\\", "/") path = re.sub( r'(\$REPO[0-9/]+)', '', orig_path ) tx_path = self.make_tx(path) inputs = node.attr(attr_name).inputs(p=1) if len(inputs): # set the input attribute for input_node_attr in inputs: input_node_attr.set(tx_path) else: node.setAttr(attr_name, tx_path) # randomize all render node names # This is needed to prevent clashing of materials in a bigger scene for node in pm.ls(type=RENDER_RELATED_NODE_TYPES): if node.referenceFile() is None and \ node.name() not in READ_ONLY_NODE_NAMES: node.rename('%s_%s' % (node.name(), uuid.uuid4().hex)) # find the _pfxPolygons node pfx_polygons_node = pm.PyNode('kks___vegetation_pfxPolygons') for node in pfx_polygons_node.getChildren(): for child_node in node.getChildren(): #print('processing %s' % child_node.name()) child_node_name = child_node.name().split('___')[-1] pm.select(child_node) output_filename =\ '%s_%s.ass' % ( self.version.nice_name, child_node_name.replace(':', '_').replace('|', '_') ) output_full_path = \ os.path.join(output_path, output_filename) # run the mel command pm.mel.eval( export_command % { 'path': output_full_path.replace('\\', '/') } ) # generate an aiStandIn node and set the path ass_node = auxiliary.create_arnold_stand_in( path='%s.gz' % output_full_path ) ass_tra = ass_node.getParent() # parent the ass node under the current node # under pfx_polygons_node pm.parent(ass_tra, node) # set pivots rp = pm.xform(child_node, q=1, ws=1, rp=1) sp = pm.xform(child_node, q=1, ws=1, sp=1) # rpt = child_node.getRotatePivotTranslation() pm.xform(ass_node, ws=1, rp=rp) pm.xform(ass_node, ws=1, sp=sp) # ass_node.setRotatePivotTranslation(rpt) # delete the child_node pm.delete(child_node) # give it the same name with the original ass_tra.rename('%s' % child_node_name) # clean up other nodes pm.delete('kks___vegetation_pfxStrokes') pm.delete('kks___vegetation_paintableGeos') elif self.is_model_task(task): # convert all children of the root node # to an empty aiStandIn node # and save it as it is root_nodes = self.get_local_root_nodes() for root_node in root_nodes: for child_node in root_node.getChildren(): child_node_name = child_node.name() rp = pm.xform(child_node, q=1, ws=1, rp=1) sp = pm.xform(child_node, q=1, ws=1, sp=1) pm.delete(child_node) ass_node = auxiliary.create_arnold_stand_in(path='') ass_tra = ass_node.getParent() pm.parent(ass_tra, root_node) ass_tra.rename(child_node_name) # set pivots pm.xform(ass_tra, ws=1, rp=rp) pm.xform(ass_tra, ws=1, sp=sp) # because there will be possible material assignments # in look dev disable overrideShaders ass_node.setAttr('overrideShaders', False) # we definitely do not use light linking in our studio, # which seems to create more problems then it solves. ass_node.setAttr('overrideLightLinking', False) # convert all references to ASS for ref in pm.listReferences(): ref.to_repr('ASS') ref.load() # fix an arnold bug for node_name in ['initialShadingGroup', 'initialParticleSE']: node = pm.PyNode(node_name) node.setAttr("ai_surface_shader", (0, 0, 0), type="float3") node.setAttr("ai_volume_shader", (0, 0, 0), type="float3") # if this is an Exterior/Interior -> Layout -> Hires task flatten it is_exterior_or_interior_task = self.is_exterior_or_interior_task(task) if is_exterior_or_interior_task: # and import all of the references all_refs = pm.listReferences() while len(all_refs) != 0: for ref in all_refs: if not ref.isLoaded(): ref.load() ref.importContents() all_refs = pm.listReferences() # assign lambert1 to all GPU nodes pm.sets('initialShadingGroup', e=1, fe=auxiliary.get_root_nodes()) # now remove them from the group pm.sets('initialShadingGroup', e=1, rm=pm.ls()) # and to make sure that no override is enabled [node.setAttr('overrideLightLinking', False) for node in pm.ls(type='aiStandIn')] # clean up self.clean_up() # check if all aiStandIn nodes are included in # ArnoldStandInDefaultLightSet set try: arnold_stand_in_default_light_set = \ pm.PyNode('ArnoldStandInDefaultLightSet') except pm.MayaNodeError: # just create it arnold_stand_in_default_light_set = \ pm.createNode( 'objectSet', name='ArnoldStandInDefaultLightSet' ) pm.select(None) pm.sets( arnold_stand_in_default_light_set, fe=pm.ls(type='aiStandIn') ) # save the scene as {{original_take}}___ASS # use maya take_name = '%s%s%s' % ( self.base_take_name, Representation.repr_separator, 'ASS' ) v = self.get_latest_repr_version(take_name) self.maya_env.save_as(v) # export the root nodes under the same file if is_exterior_or_interior_task: pm.select(auxiliary.get_root_nodes()) pm.exportSelected( v.absolute_full_path, type='mayaAscii', force=True ) # new scene pm.newFile(force=True) # reset show plugin shapes option active_panel = auxiliary.Playblaster.get_active_panel() pm.modelEditor(active_panel, e=1, pluginShapes=show_plugin_shapes)
class PrevisUI(object): """Main class for managing the previs UI """ def __init__(self): self.mEnv = Maya() self.width = 265 self.height = 300 self.row_spacing = 3 self.window = None self.window_name = 'Previz_Window' self.window_title = "Previz Tools v%s" % anima.__version__ self.edl_checkBox = None self.mxf_checkBox = None def init_ui(self): if core.window(self.window_name, q=True, ex=True): core.deleteUI(self.window_name, wnd=True) self.window = core.window( self.window_name, wh=(self.width, self.height), mnb = False, mxb=False, sizeable=False, title=self.window_title ) #the layout main_formLayout = core.formLayout( 'main_formLayout', nd=100, parent=self.window ) prog_columnLayout = core.columnLayout( 'prog_columnLayout', columnAttach=('both', 3), rowSpacing=10, columnWidth=265, parent=main_formLayout ) top_rowLayout = core.rowLayout( 'top_rowLayout', numberOfColumns=2, columnWidth2=(85, 180), adjustableColumn=2, columnAlign=(1, 'right'), columnAttach=[(1, 'both', 0), (2, 'both', 0)], parent= prog_columnLayout ) topleft_columnLayout = core.columnLayout( 'topleft_columnLayout', w=85, columnAttach=('left' , 5), cal='left', rowSpacing=17, columnWidth=85, parent=top_rowLayout ) core.text(label='Scene Code', parent=topleft_columnLayout) core.text(label='File Version', parent=topleft_columnLayout) core.text(label='Handle Lenght', parent=topleft_columnLayout) core.text(label='Export', parent=topleft_columnLayout) core.text(label='Convert MOVs', parent=topleft_columnLayout) right_columnLayout = core.columnLayout( 'right_columnLayout', columnAttach=('left' , 5), cal='left', rowSpacing=10, columnWidth=85, parent=top_rowLayout ) Seqname_rowLayout = core.rowLayout( 'seqNameRow', numberOfColumns=3, columnWidth3=(40,60,55), columnAttach=[(1, 'both', 5), (2, 'both', 10), (3, 'both', 5)], parent=right_columnLayout ) seq = core.textField(pht="SEQ" , parent=Seqname_rowLayout) loc = core.textField(pht="LOC" , parent=Seqname_rowLayout) script = core.textField(pht= "Script", parent=Seqname_rowLayout) topRight_columnLayout = core.columnLayout( 'topRight_columnLayout', w=170, columnAttach=('both', 5), rowSpacing=10, columnWidth=160, parent=right_columnLayout ) current_version = self.mEnv.get_current_version() if current_version: version_number = current_version.version_number else: version_number = 1 version_string = 'v%03d' % version_number version = core.textField(text=version_string) lenght_slider_grp = core.intSliderGrp(field= True, cw2= (30,70), cc=self.set_handle, min=0, v=15, max=50 ) self.edl_checkBox = core.checkBox('EDL', value=True) self.mxf_checkBox = core.checkBox('to MXF', value=True) core.separator (h=20, parent= prog_columnLayout) bottom_columnLayout = core.columnLayout( 'bottom_rowLayout', w = 260, columnAttach=('both', 5), rowSpacing=10, columnWidth=260, parent= prog_columnLayout ) core.button(label='Export' , bgc=(0.1, 0.4, 0.1), w=250, parent=bottom_columnLayout, c=self.export) core.button( label='Close Window', command=self.close, bgc= (0.3, 0.1, 0.1), w=250, parent= bottom_columnLayout ) def show(self): if not self.window: self.init_ui() try: core.showWindow(self.window) except RuntimeError: self.init_ui core.showWindow(self.window) core.window(self.window, edit=True, w=self.width, h=self.height) def close(self, value): """closes the UI """ core.deleteUI(self.window_name, window=True) ### learning Scene Version def set_ver(self): scVer = 'v001' sm.set_version(scVer) def set_handle(self, value): """sets handles from UI """ sm = core.ls('sequenceManager1')[0] seq1 = sm.sequences.get()[0] seq1.set_shot_handles(value) def set_seq_name(name): """sets sequence name """ sm.get_shot_name_template() # sets the default shot name template seq1.set_sequence_name('SEQ001_TNGI_Scr_010') def export(self, button_value): """ """ ### get sequenceManager1 sm = pymel.core.PyNode('sequenceManager1') ### get sequencer seq1 = sm.sequences.get()[0] # set path values current_workspace_path = pymel.core.workspace.path playblast_output_path = os.path.normpath( os.path.join(current_workspace_path, 'Outputs', 'All_Shots') ) edl_path = os.path.normpath( os.path.join( playblast_output_path, '%s_%s.%s' % (seq1.get_sequence_name(), sm.get_version(), 'edl') ) ) # create shot playblast seq1.create_shot_playblasts(playblast_output_path) # convert to MXF if self.mxf_checkBox.value(): shot_count = len(seq1.shots.get()) step = int(100.0/shot_count) import time core.progressWindow( title='Converting To MXFs', progress=0, status='', isInterruptable=True ) for i in seq1.metafuze(): core.progressWindow(e=1, step=step) core.progressWindow(endProgress=1) if self.edl_checkBox.value(): # create EDL file l = sm.to_edl() with open(edl_path, 'w') as f: f.write(l.to_string())
class PrevisUI(object): """Main class for managing the previs UI """ def __init__(self): self.mEnv = Maya() self.width = 265 self.height = 300 self.row_spacing = 3 self.window = None self.window_name = 'Previz_Window' self.window_title = "Previz Tools v%s" % anima.__version__ self.edl_checkBox = None self.mxf_checkBox = None def init_ui(self): if core.window(self.window_name, q=True, ex=True): core.deleteUI(self.window_name, wnd=True) self.window = core.window(self.window_name, wh=(self.width, self.height), mnb=False, mxb=False, sizeable=False, title=self.window_title) #the layout main_formLayout = core.formLayout('main_formLayout', nd=100, parent=self.window) prog_columnLayout = core.columnLayout('prog_columnLayout', columnAttach=('both', 3), rowSpacing=10, columnWidth=265, parent=main_formLayout) top_rowLayout = core.rowLayout('top_rowLayout', numberOfColumns=2, columnWidth2=(85, 180), adjustableColumn=2, columnAlign=(1, 'right'), columnAttach=[(1, 'both', 0), (2, 'both', 0)], parent=prog_columnLayout) topleft_columnLayout = core.columnLayout('topleft_columnLayout', w=85, columnAttach=('left', 5), cal='left', rowSpacing=17, columnWidth=85, parent=top_rowLayout) core.text(label='Scene Code', parent=topleft_columnLayout) core.text(label='File Version', parent=topleft_columnLayout) core.text(label='Handle Lenght', parent=topleft_columnLayout) core.text(label='Export', parent=topleft_columnLayout) core.text(label='Convert MOVs', parent=topleft_columnLayout) right_columnLayout = core.columnLayout('right_columnLayout', columnAttach=('left', 5), cal='left', rowSpacing=10, columnWidth=85, parent=top_rowLayout) Seqname_rowLayout = core.rowLayout('seqNameRow', numberOfColumns=3, columnWidth3=(40, 60, 55), columnAttach=[(1, 'both', 5), (2, 'both', 10), (3, 'both', 5)], parent=right_columnLayout) seq = core.textField(pht="SEQ", parent=Seqname_rowLayout) loc = core.textField(pht="LOC", parent=Seqname_rowLayout) script = core.textField(pht="Script", parent=Seqname_rowLayout) topRight_columnLayout = core.columnLayout('topRight_columnLayout', w=170, columnAttach=('both', 5), rowSpacing=10, columnWidth=160, parent=right_columnLayout) current_version = self.mEnv.get_current_version() if current_version: version_number = current_version.version_number else: version_number = 1 version_string = 'v%03d' % version_number version = core.textField(text=version_string) lenght_slider_grp = core.intSliderGrp(field=True, cw2=(30, 70), cc=self.set_handle, min=0, v=15, max=50) self.edl_checkBox = core.checkBox('EDL', value=True) self.mxf_checkBox = core.checkBox('to MXF', value=True) core.separator(h=20, parent=prog_columnLayout) bottom_columnLayout = core.columnLayout('bottom_rowLayout', w=260, columnAttach=('both', 5), rowSpacing=10, columnWidth=260, parent=prog_columnLayout) core.button(label='Export', bgc=(0.1, 0.4, 0.1), w=250, parent=bottom_columnLayout, c=self.export) core.button(label='Close Window', command=self.close, bgc=(0.3, 0.1, 0.1), w=250, parent=bottom_columnLayout) def show(self): if not self.window: self.init_ui() try: core.showWindow(self.window) except RuntimeError: self.init_ui core.showWindow(self.window) core.window(self.window, edit=True, w=self.width, h=self.height) def close(self, value): """closes the UI """ core.deleteUI(self.window_name, window=True) ### learning Scene Version def set_ver(self): scVer = 'v001' sm.set_version(scVer) def set_handle(self, value): """sets handles from UI """ sm = core.ls('sequenceManager1')[0] seq1 = sm.sequences.get()[0] seq1.set_shot_handles(value) def set_seq_name(name): """sets sequence name """ sm.get_shot_name_template() # sets the default shot name template seq1.set_sequence_name('SEQ001_TNGI_Scr_010') def export(self, button_value): """ """ ### get sequenceManager1 sm = pymel.core.PyNode('sequenceManager1') ### get sequencer seq1 = sm.sequences.get()[0] # set path values current_workspace_path = pymel.core.workspace.path playblast_output_path = os.path.normpath( os.path.join(current_workspace_path, 'Outputs', 'All_Shots')) edl_path = os.path.normpath( os.path.join( playblast_output_path, '%s_%s.%s' % (seq1.get_sequence_name(), sm.get_version(), 'edl'))) # create shot playblast seq1.create_shot_playblasts(playblast_output_path) # convert to MXF if self.mxf_checkBox.value(): shot_count = len(seq1.shots.get()) step = int(100.0 / shot_count) import time core.progressWindow(title='Converting To MXFs', progress=0, status='', isInterruptable=True) for i in seq1.metafuze(): core.progressWindow(e=1, step=step) core.progressWindow(endProgress=1) if self.edl_checkBox.value(): # create EDL file l = sm.to_edl() with open(edl_path, 'w') as f: f.write(l.to_string())
def export_edl(): """exports edl of animation scenes """ from anima.env.mayaEnv import Maya m = Maya() current_version = m.get_current_version() if not current_version: return # get sequenceManager1 sm = pm.PyNode('sequenceManager1') seqs = sm.sequences.get() if not len(seqs): return seq1 = seqs[0] edl_path = tempfile.gettempdir() edl_file_name = '%s_v%03i.edl' % ( current_version.nice_name, current_version.version_number ) edl_file_full_path = os.path.join(edl_path, edl_file_name) # convert to MXF from anima.ui.progress_dialog import ProgressDialogManager pdm = ProgressDialogManager() #shots = seq1.shots.get() shots = pm.ls(type='shot') shot_count = len(shots) # before doing a playblast set all shot handles to 48 for shot in pm.ls(type='shot'): if shot.hasAttr('handle'): shot.handle.set(48) caller = pdm.register(shot_count, title='Converting To MXF') # update shot outputs to the correct place first # there should be only one shot in the current animation scene # if there is more than one shot, the other publisher will already warn the # user so the code path will not reach to this point # we also should already have a video output created by another publisher playblast_file = None for output in current_version.outputs: extension = os.path.splitext(output.full_path)[-1] if extension in ['.mov', '.avi', '.mp4']: playblast_file = output break if not playblast_file: return shot = shots[0] shot.output.set(playblast_file.full_path) for i in seq1.metafuze(): caller.step() # create EDL file from anima import utils mm = utils.MediaManager() l = sm.to_edl() with open(edl_file_full_path, 'w') as f: f.write(l.to_string()) with open(edl_file_full_path, 'r') as f: link = mm.upload_version_output(current_version, f, edl_file_name) # add the link to database from stalker import db db.DBSession.commit() # revert the handles to 0 for shot in pm.ls(type='shot'): if shot.hasAttr('handle'): shot.handle.set(0)
def version(self): """returns the Stalker Version instance related to this reference """ from anima.env.mayaEnv import Maya m = Maya() return m.get_version_from_full_path(self.path)
def setUp(self): """create test data """ database_url = 'sqlite:///:memory:' db.setup({'sqlalchemy.url': database_url}) db.init() self.temp_repo_path = tempfile.mkdtemp() self.user1 = User(name='User 1', login='******', email='*****@*****.**', password='******') self.repo1 = Repository(name='Test Project Repository', linux_path=self.temp_repo_path, windows_path=self.temp_repo_path, osx_path=self.temp_repo_path) self.status_new = Status.query.filter_by(code='NEW').first() self.status_wip = Status.query.filter_by(code='WIP').first() self.status_comp = Status.query.filter_by(code='CMPL').first() self.task_template = FilenameTemplate( name='Task Template', target_entity_type='Task', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.asset_template = FilenameTemplate( name='Asset Template', target_entity_type='Asset', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.shot_template = FilenameTemplate( name='Shot Template', target_entity_type='Shot', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.sequence_template = FilenameTemplate( name='Sequence Template', target_entity_type='Sequence', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.structure = Structure(name='Project Struture', templates=[ self.task_template, self.asset_template, self.shot_template, self.sequence_template ]) self.project_status_list = \ StatusList.query.filter_by(target_entity_type='Project').first() self.image_format = ImageFormat(name='HD 1080', width=1920, height=1080, pixel_aspect=1.0) # create a test project self.project = Project(name='Test Project', code='TP', repository=self.repo1, status_list=self.project_status_list, structure=self.structure, image_format=self.image_format) # create task hierarchy # # ASSETS # self.assets = Task(name='Assets', project=self.project, responsible=[self.user1]) # # SEQUENCES # self.sequences = Task(name='Sequences', project=self.project, responsible=[self.user1]) self.seq001 = Sequence(name='Seq001', code='Seq001', parent=self.sequences) self.scene_task = Task(name='001_IST', parent=self.seq001) self.scene_previs_type = Type(name='Scene Previs', code='Scene Previs', target_entity_type='Task') self.scene_previs = Task(name='Scene Previs', parent=self.scene_task, type=self.scene_previs_type) self.shots = Task(name='Shots', parent=self.scene_task) self.shot1 = Shot(name='Seq001_001_IST_0010', code='Seq001_001_IST_0010', parent=self.shots) # create shot tasks self.previs = Task(name='Previs', parent=self.shot1) self.camera = Task(name='Camera', parent=self.shot1) self.animation = Task(name='Animation', parent=self.shot1) self.scene_assembly = Task(name='SceneAssembly', parent=self.shot1) self.lighting = Task(name='Lighting', parent=self.shot1) self.comp = Task(name='Comp', parent=self.shot1) # create maya files self.maya_env = Maya() pm.newFile(force=True) sm = pm.PyNode('sequenceManager1') seq1 = sm.create_sequence('001_IST') # create 3 shots shot1 = seq1.create_shot('shot1') shot2 = seq1.create_shot('shot2') shot3 = seq1.create_shot('shot3') # set shot ranges shot1.startFrame.set(1) shot1.endFrame.set(100) shot2.startFrame.set(101) shot2.endFrame.set(200) shot2.sequenceStartFrame.set(101) shot3.startFrame.set(201) shot3.endFrame.set(300) shot3.sequenceStartFrame.set(201) # save the file under scene previs v = Version(task=self.scene_previs) self.maya_env.save_as(v) pm.newFile(force=1) print(v.absolute_full_path)
def setUp(self): """create test data """ database_url = 'sqlite:///:memory:' db.setup({'sqlalchemy.url': database_url}) db.init() self.temp_repo_path = tempfile.mkdtemp() self.user1 = User( name='User 1', login='******', email='*****@*****.**', password='******' ) self.repo1 = Repository( name='Test Project Repository', linux_path=self.temp_repo_path, windows_path=self.temp_repo_path, osx_path=self.temp_repo_path ) self.status_new = Status.query.filter_by(code='NEW').first() self.status_wip = Status.query.filter_by(code='WIP').first() self.status_comp = Status.query.filter_by(code='CMPL').first() self.task_template = FilenameTemplate( name='Task Template', target_entity_type='Task', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.asset_template = FilenameTemplate( name='Asset Template', target_entity_type='Asset', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.shot_template = FilenameTemplate( name='Shot Template', target_entity_type='Shot', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.sequence_template = FilenameTemplate( name='Sequence Template', target_entity_type='Sequence', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.structure = Structure( name='Project Struture', templates=[self.task_template, self.asset_template, self.shot_template, self.sequence_template] ) self.project_status_list = StatusList( name='Project Statuses', target_entity_type='Project', statuses=[self.status_new, self.status_wip, self.status_comp] ) self.image_format = ImageFormat( name='HD 1080', width=1920, height=1080, pixel_aspect=1.0 ) # create a test project self.project = Project( name='Test Project', code='TP', repository=self.repo1, status_list=self.project_status_list, structure=self.structure, image_format=self.image_format ) # create task hierarchy # # ASSETS # self.assets = Task( name='Assets', project=self.project, responsible=[self.user1] ) # # SEQUENCES # self.sequences = Task( name='Sequences', project=self.project, responsible=[self.user1] ) self.seq001 = Sequence( name='Seq001', code='Seq001', parent=self.sequences ) self.scene_task = Task( name='001_IST', parent=self.seq001 ) self.scene_previs_type = Type( name='Scene Previs', code='Scene Previs', target_entity_type='Task' ) self.scene_previs = Task( name='Scene Previs', parent=self.scene_task, type=self.scene_previs_type ) self.shots = Task( name='Shots', parent=self.scene_task ) self.shot1 = Shot( name='Seq001_001_IST_0010', code='Seq001_001_IST_0010', parent=self.shots ) # create shot tasks self.previs = Task( name='Previs', parent=self.shot1 ) self.camera = Task( name='Camera', parent=self.shot1 ) self.animation = Task( name='Animation', parent=self.shot1 ) self.scene_assembly = Task( name='SceneAssembly', parent=self.shot1 ) self.lighting = Task( name='Lighting', parent=self.shot1 ) self.comp = Task( name='Comp', parent=self.shot1 ) # create maya files self.maya_env = Maya() pm.newFile(force=True) sm = pm.PyNode('sequenceManager1') seq1 = sm.create_sequence('001_IST') # create 3 shots shot1 = seq1.create_shot('shot1') shot2 = seq1.create_shot('shot2') shot3 = seq1.create_shot('shot3') # set shot ranges shot1.startFrame.set(1) shot1.endFrame.set(100) shot2.startFrame.set(101) shot2.endFrame.set(200) shot2.sequenceStartFrame.set(101) shot3.startFrame.set(201) shot3.endFrame.set(300) shot3.sequenceStartFrame.set(201) # save the file under scene previs v = Version(task=self.scene_previs) self.maya_env.save_as(v) pm.newFile(force=1) print(v.absolute_full_path)
def export_edl(): """exports edl of animation scenes """ from anima.env.mayaEnv import Maya m = Maya() current_version = m.get_current_version() if not current_version: return # get sequenceManager1 sm = pm.PyNode('sequenceManager1') seqs = sm.sequences.get() if not len(seqs): return seq1 = seqs[0] edl_path = tempfile.gettempdir() edl_file_name = '%s_v%03i.edl' % (current_version.nice_name, current_version.version_number) edl_file_full_path = os.path.join(edl_path, edl_file_name) # convert to MXF from anima.ui.progress_dialog import ProgressDialogManager pdm = ProgressDialogManager() #shots = seq1.shots.get() shots = pm.ls(type='shot') shot_count = len(shots) # before doing a playblast set all shot handles to 48 for shot in pm.ls(type='shot'): if shot.hasAttr('handle'): shot.handle.set(48) caller = pdm.register(shot_count, title='Converting To MXF') # update shot outputs to the correct place first # there should be only one shot in the current animation scene # if there is more than one shot, the other publisher will already warn the # user so the code path will not reach to this point # we also should already have a video output created by another publisher playblast_file = None for output in current_version.outputs: extension = os.path.splitext(output.full_path)[-1] if extension in ['.mov', '.avi', '.mp4']: playblast_file = output break if not playblast_file: return shot = shots[0] shot.output.set(playblast_file.full_path) for i in seq1.metafuze(): caller.step() # create EDL file from anima import utils mm = utils.MediaManager() l = sm.to_edl() with open(edl_file_full_path, 'w') as f: f.write(l.to_string()) with open(edl_file_full_path, 'r') as f: link = mm.upload_version_output(current_version, f, edl_file_name) # add the link to database from stalker import db db.DBSession.commit() # revert the handles to 0 for shot in pm.ls(type='shot'): if shot.hasAttr('handle'): shot.handle.set(0)
def generate_sequence_structure(self): """Generates a Sequence structure suitable for XML<->EDL conversion :return: Sequence """ import timecode from anima.env.mayaEnv import Maya m = Maya() fps = m.get_fps() # export only the first sequence, ignore others sequencers = self.sequences.get() if len(sequencers) == 0: return None sequencer = sequencers[0] time = pm.PyNode('time1') seq = Sequence() seq.name = str(sequencer.get_sequence_name()) seq.rate = Rate(timebase=str(fps), ntsc=False) seq.timecode = str(timecode.Timecode( framerate=seq.rate.timebase, frames=time.timecodeProductionStart.get() + 1 )) seq.duration = sequencer.duration media = Media() video = Video() media.video = video for shot in sequencer.shots.get(): clip = Clip() clip.id = str(shot.full_shot_name) clip.name = str(shot.full_shot_name) clip.duration = shot.duration + 2 * shot.handle.get() clip.enabled = True clip.start = shot.sequenceStartFrame.get() clip.end = shot.sequenceEndFrame.get() + 1 # clips always start from 0 and includes the shot handle clip.in_ = shot.handle.get() # handle at start clip.out = shot.handle.get() + shot.duration # handle at end clip.type = 'Video' # always video for now f = File() f.name = os.path.splitext( os.path.basename(str(shot.output.get())) )[0] f.duration = shot.duration + 2 * shot.handle.get() f.pathurl = str('file://localhost/%s' % shot.output.get()) clip.file = f track_number = shot.track.get() - 1 # tracks should start from 0 try: track = video.tracks[track_number] except IndexError: track = Track() video.tracks.append(track) track.clips.append(clip) # set video resolution video.width = shot.wResolution.get() video.height = shot.hResolution.get() seq.media = media return seq