def get_version_from_full_path(cls, full_path): """Finds the Version instance from the given full_path value. Finds and returns a :class:`~stalker.models.version.Version` instance from the given full_path value. Returns None if it can't find any matching. :param full_path: The full_path of the desired :class:`~stalker.models.version.Version` instance. :return: :class:`~stalker.models.version.Version` """ logger.debug('full_path: %s' % full_path) # convert '\\' to '/' full_path = os.path.normpath( os.path.expandvars(full_path) ).replace('\\', '/') # trim repo path from stalker import Repository, Version os_independent_path = Repository.to_os_independent_path(full_path) # try to get a version with that info logger.debug('getting a version with path: %s' % full_path) version = Version.query\ .filter(Version.full_path == os_independent_path).first() logger.debug('version: %s' % version) return version
def bind_to_original(cls): """binds the current scene references to original references from the repository """ # get all reference paths import os from anima.env import mayaEnv from stalker import Repository, Version, Task m = mayaEnv.Maya() current_version = m.get_current_version() # get the current project project = None if current_version: project = current_version.task.project # no project then do nothing if project: for ref in pm.listReferences(): unresolved_path = ref.unresolvedPath() filename = os.path.basename(unresolved_path) # find the corresponding version v = Version.query\ .join(Version.task, Task.versions)\ .filter(Task.project == project)\ .filter(Version.full_path.endswith(filename)).first() if v: ref.replaceWith( Repository.to_os_independent_path( v.absolute_full_path ) )
def upload_thumbnail(task, thumbnail_full_path): """Uploads the given thumbnail for the given entity :param task: An instance of :class:`~stalker.models.entity.SimpleEntity` or a derivative. :param str thumbnail_full_path: A string which is showing the path of the thumbnail image """ extension = os.path.splitext(thumbnail_full_path)[-1] # move the file to the task thumbnail folder # and mimic StalkerPyramids output format thumbnail_original_file_name = 'thumbnail%s' % extension thumbnail_final_full_path = os.path.join( task.absolute_path, 'Thumbnail', thumbnail_original_file_name ) try: os.makedirs(os.path.dirname(thumbnail_final_full_path)) except OSError: pass # # convert the thumbnail to jpg if it is a format that is not supported by # # browsers # ext_not_supported_by_browsers = ['.bmp', '.tga', '.tif', '.tiff', '.exr'] # if extension in ext_not_supported_by_browsers: # # use MediaManager to convert them # from anima.utils import MediaManager # mm = MediaManager() # thumbnail_full_path = mm.generate_image_thumbnail(thumbnail_full_path) shutil.copy(thumbnail_full_path, thumbnail_final_full_path) from stalker import Link, Version, Repository thumbnail_os_independent_path = \ Repository.to_os_independent_path(thumbnail_final_full_path) l_thumb = Link.query\ .filter(Link.full_path == thumbnail_os_independent_path).first() if not l_thumb: l_thumb = Link( full_path=thumbnail_os_independent_path, original_filename=thumbnail_original_file_name ) task.thumbnail = l_thumb # get a version of this Task from stalker.db.session import DBSession v = Version.query.filter(Version.task == task).first() if v: for naming_parent in v.naming_parents: if not naming_parent.thumbnail: naming_parent.thumbnail = l_thumb DBSession.add(naming_parent) DBSession.add(l_thumb) DBSession.commit()
def upload_thumbnail(task, thumbnail_full_path): """Uploads the given thumbnail for the given entity :param task: An instance of :class:`~stalker.models.entity.SimpleEntity` or a derivative. :param str thumbnail_full_path: A string which is showing the path of the thumbnail image """ extension = os.path.splitext(thumbnail_full_path)[-1] # move the file to the task thumbnail folder # and mimic StalkerPyramids output format thumbnail_original_file_name = 'thumbnail%s' % extension thumbnail_final_full_path = os.path.join(task.absolute_path, 'Thumbnail', thumbnail_original_file_name) try: os.makedirs(os.path.dirname(thumbnail_final_full_path)) except OSError: pass # # convert the thumbnail to jpg if it is a format that is not supported by # # browsers # ext_not_supported_by_browsers = ['.bmp', '.tga', '.tif', '.tiff', '.exr'] # if extension in ext_not_supported_by_browsers: # # use MediaManager to convert them # from anima.utils import MediaManager # mm = MediaManager() # thumbnail_full_path = mm.generate_image_thumbnail(thumbnail_full_path) import shutil shutil.copy(thumbnail_full_path, thumbnail_final_full_path) from stalker import Link, Version, Repository thumbnail_os_independent_path = \ Repository.to_os_independent_path(thumbnail_final_full_path) l_thumb = Link.query\ .filter(Link.full_path == thumbnail_os_independent_path).first() if not l_thumb: l_thumb = Link(full_path=thumbnail_os_independent_path, original_filename=thumbnail_original_file_name) task.thumbnail = l_thumb # get a version of this Task from stalker.db.session import DBSession v = Version.query.filter(Version.task == task).first() if v: for naming_parent in v.naming_parents: if not naming_parent.thumbnail: naming_parent.thumbnail = l_thumb DBSession.add(naming_parent) DBSession.add(l_thumb) DBSession.commit()
def test_to_os_independent_path_is_working_properly(self): """testing if to_os_independent_path class method is working properly """ from stalker.db.session import DBSession DBSession.add(self.test_repo) DBSession.commit() relative_part = 'some/path/to/a/file.ma' test_path = '%s/%s' % (self.test_repo.path, relative_part) from stalker import Repository assert Repository.to_os_independent_path(test_path) == \ '$REPO%s/%s' % (self.test_repo.id, relative_part)
def to_repr(self, repr_name): """Replaces the current reference with the representation with the given repr_name. :param str repr_name: The desired repr name :return: """ rep_v = self.find_repr(repr_name) from stalker import Repository if rep_v is not None and rep_v != self.version: self.replaceWith( Repository.to_os_independent_path(rep_v.absolute_full_path))
def test_to_os_independent_path_is_working_properly(self): """testing if stalker.Repository.to_os_independent_path() is working as we are expecting it to work """ # repo4 linux_path = '/test/repo/4/linux/path/PRJ1/Assets/test.ma' windows_path = 'T:/test/repo/4/windows/path/PRJ1/Assets/test.ma' osx_path = '/test/repo/4/osx/path/PRJ1/Assets/test.ma' os_independent_path = '$REPO%s/PRJ1/Assets/test.ma' % self.repo4.id self.assertEqual(Repository.to_os_independent_path(linux_path), os_independent_path) self.assertEqual(Repository.to_os_independent_path(windows_path), os_independent_path) self.assertEqual(Repository.to_os_independent_path(osx_path), os_independent_path) # repo5 linux_path = '/test/repo/5/linux/path/PRJ1/Assets/test.ma' windows_path = 'T:/test/repo/5/windows/path/PRJ1/Assets/test.ma' osx_path = '/test/repo/5/osx/path/PRJ1/Assets/test.ma' os_independent_path = '$REPO%s/PRJ1/Assets/test.ma' % self.repo5.id self.assertEqual(Repository.to_os_independent_path(linux_path), os_independent_path) self.assertEqual(Repository.to_os_independent_path(windows_path), os_independent_path) self.assertEqual(Repository.to_os_independent_path(osx_path), os_independent_path)
def to_repr(self, repr_name): """Replaces the current reference with the representation with the given repr_name. :param str repr_name: The desired repr name :return: """ rep_v = self.find_repr(repr_name) from stalker import Repository if rep_v is not None and rep_v != self.version: self.replaceWith( Repository.to_os_independent_path(rep_v.absolute_full_path) )
def upload_thumbnail(task, thumbnail_full_path): """Uploads the given thumbnail for the given entity :param task: An instance of :class:`~stalker.models.entity.SimpleEntity` or a derivative. :param str thumbnail_full_path: A string which is showing the path of the thumbnail image """ extension = os.path.splitext(thumbnail_full_path)[-1] # move the file to the task thumbnail folder # and mimic StalkerPyramids output format thumbnail_original_file_name = 'thumbnail%s' % extension thumbnail_final_full_path = os.path.join( task.absolute_path, 'Thumbnail', thumbnail_original_file_name ) try: os.makedirs(os.path.dirname(thumbnail_final_full_path)) except OSError: pass shutil.copy(thumbnail_full_path, thumbnail_final_full_path) from stalker import db, Link, Version, Repository thumbnail_os_independent_path = \ Repository.to_os_independent_path(thumbnail_final_full_path) l_thumb = Link.query\ .filter(Link.full_path == thumbnail_os_independent_path).first() if not l_thumb: l_thumb = Link( full_path=thumbnail_os_independent_path, original_filename=thumbnail_original_file_name ) task.thumbnail = l_thumb # get a version of this Task v = Version.query.filter(Version.task == task).first() if v: for naming_parent in v.naming_parents: if not naming_parent.thumbnail: naming_parent.thumbnail = l_thumb db.DBSession.add(naming_parent) db.DBSession.add(l_thumb) db.DBSession.commit()
def upload_thumbnail(task, thumbnail_full_path): """Uploads the given thumbnail for the given entity :param task: An instance of :class:`~stalker.models.entity.SimpleEntity` or a derivative. :param str thumbnail_full_path: A string which is showing the path of the thumbnail image """ extension = os.path.splitext(thumbnail_full_path)[-1] # move the file to the task thumbnail folder # and mimic StalkerPyramids output format thumbnail_original_file_name = 'thumbnail%s' % extension thumbnail_final_full_path = os.path.join(task.absolute_path, 'Thumbnail', thumbnail_original_file_name) try: os.makedirs(os.path.dirname(thumbnail_final_full_path)) except OSError: pass shutil.copy(thumbnail_full_path, thumbnail_final_full_path) from stalker import db, Link, Version, Repository thumbnail_os_independent_path = \ Repository.to_os_independent_path(thumbnail_final_full_path) l_thumb = Link.query\ .filter(Link.full_path == thumbnail_os_independent_path).first() if not l_thumb: l_thumb = Link(full_path=thumbnail_os_independent_path, original_filename=thumbnail_original_file_name) task.thumbnail = l_thumb # get a version of this Task v = Version.query.filter(Version.task == task).first() if v: for naming_parent in v.naming_parents: if not naming_parent.thumbnail: naming_parent.thumbnail = l_thumb db.DBSession.add(naming_parent) db.DBSession.add(l_thumb) db.DBSession.commit()
def bind_to_original(cls): """binds the current scene references to original references from the repository """ # get all reference paths import os from stalker import Repository, Version for ref in pm.listReferences(): unresolved_path = ref.unresolvedPath() filename = os.path.basename(unresolved_path) # find the corresponding version # TODO: get the versions from current project v = Version.query\ .filter(Version.full_path.endswith(filename))\ .first() if v: ref.replaceWith( Repository.to_os_independent_path(v.absolute_full_path) )
def test_to_os_independent_path_is_working_properly(self): """testing if stalker.Repository.to_os_independent_path() is working as we are expecting it to work """ # repo4 linux_path = '/test/repo/4/linux/path/PRJ1/Assets/test.ma' windows_path = 'T:/test/repo/4/windows/path/PRJ1/Assets/test.ma' osx_path = '/test/repo/4/osx/path/PRJ1/Assets/test.ma' os_independent_path = '$REPO%s/PRJ1/Assets/test.ma' % self.repo4.id self.assertEqual( Repository.to_os_independent_path(linux_path), os_independent_path ) self.assertEqual( Repository.to_os_independent_path(windows_path), os_independent_path ) self.assertEqual( Repository.to_os_independent_path(osx_path), os_independent_path ) # repo5 linux_path = '/test/repo/5/linux/path/PRJ1/Assets/test.ma' windows_path = 'T:/test/repo/5/windows/path/PRJ1/Assets/test.ma' osx_path = '/test/repo/5/osx/path/PRJ1/Assets/test.ma' os_independent_path = '$REPO%s/PRJ1/Assets/test.ma' % self.repo5.id self.assertEqual( Repository.to_os_independent_path(linux_path), os_independent_path ) self.assertEqual( Repository.to_os_independent_path(windows_path), os_independent_path ) self.assertEqual( Repository.to_os_independent_path(osx_path), os_independent_path )
def get_versions_from_path(self, path): """Finds Version instances from the given path value. Finds and returns the :class:`~stalker.models.version.Version` instances from the given path value. Returns an empty list if it can't find any matching. This method is different than :meth:`~stalker.env.EnvironmentBase.get_version_from_full_path` because it returns a list of :class:`~stalker.models.version.Version` instances which are residing in that path. The list is ordered by the ``id``\ s of the instances. :param path: A path which has possible :class:`~stalker.models.version.Version` instances. :return: A list of :class:`~stalker.models.version.Version` instances. """ if not path: return [] # convert '\\' to '/' path = os.path.normpath(path).replace('\\', '/') from stalker import Repository os_independent_path = Repository.to_os_independent_path(path) logger.debug('os_independent_path: %s' % os_independent_path) from stalker import Version from stalker.db.session import DBSession # try to get all versions with that info with DBSession.no_autoflush: versions = Version.query.\ filter(Version.full_path.startswith(os_independent_path)).all() return versions
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)