def importAsset(self, iAObj=None): start, end = HelpFunctions.getFileSequenceStartEnd(iAObj.filePath) nuke.nodePaste(iAObj.filePath % start) if iAObj.options["importSettings"]: component = ftrack.Component(iAObj.componentId) parent = component.getVersion().getAsset().getParent() # Setup fps nuke.root()['fps'].setValue(parent.get('fps')) # Setup frame range nuke.root()['first_frame'].setValue(parent.get('fstart')) nuke.root()['last_frame'].setValue(parent.get('fend')) # Setup resolution width = parent.get("width") height = parent.get("height") fmt = None for f in nuke.formats(): if f.width() == width and f.height() == height: fmt = f if fmt: nuke.root()['format'].setValue(fmt.name()) return
def resolve_path(self, component_id): '''Return path from *component_id*.''' legacy_component = None legacy_location = None try: legacy_component = ftrack.Component(component_id) legacy_location = legacy_component.getLocation() except Exception: self.logger.exception( 'Could not pick location for legacy component {0!r}'.format( legacy_component)) location = None component = None try: component = self.session.get('Component', component_id) location = self.session.pick_location(component) except Exception: self.logger.exception( 'Could not pick location for component {0!r}'.format( legacy_component)) path = None if legacy_location and location: if legacy_location.getPriority() < location.priority: path = legacy_component.getFilesystemPath() self.logger.info( 'Location is defined with a higher priority in legacy api: ' '{0!r}'.format(legacy_location)) elif (legacy_location.getPriority() == location.priority and legacy_location.getId() == location['id'] and legacy_location.getName() == 'ftrack.unmanaged'): # The legacy api is better suited to resolve the path for a # location in the ftrack.unmanaged location, since it will # account for platform and disk while resolving. path = legacy_component.getFilesystemPath() self.logger.info( 'Location is unmanaged on both legacy api and api.') else: path = location.get_filesystem_path(component) self.logger.info( 'Location is defined with a higher priority in api: ' '{0!r}'.format(location)) elif legacy_location: path = legacy_component.getFilesystemPath() self.logger.info( 'Location is only defined in legacy api: {0!r}'.format( legacy_location)) elif location: path = location.get_filesystem_path(component) self.logger.info( 'Location is only in api: {0!r}'.format(legacy_location)) return path
def getStartEndFrames(self, iAObj): '''Return start and end from *iAObj*.''' component = ftrack.Component(iAObj.componentId) if component.getSystemType() == 'sequence': # Find out frame start and end from members if component # system type is sequence. members = component.getMembers(location=None) frames = [int(member.getName()) for member in members] start = min(frames) end = max(frames) else: start, end = HelpFunctions.getFileSequenceStartEnd(iAObj.filePath) return start, end
def setFTab(self, resultingNode, iAObj): componentId = ftrack.Component( iAObj.componentId).getEntityRef() assetVersionId = ftrack.AssetVersion( iAObj.assetVersionId).getEntityRef() components = { 'componentId': HelpFunctions.safeString(componentId), 'componentName': HelpFunctions.safeString(iAObj.componentName), 'assetVersionId': HelpFunctions.safeString(assetVersionId), 'assetVersion': HelpFunctions.safeString(iAObj.assetVersion), 'assetName': HelpFunctions.safeString(iAObj.assetName), 'assetType': HelpFunctions.safeString(iAObj.assetType), 'assetId': HelpFunctions.safeString(iAObj.assetId) } for comp in components: resultingNode.parm(comp).set(components[comp])
def setFTab(self, resultingNode, iAObj): componentId = ftrack.Component(iAObj.componentId).getEntityRef() assetVersionId = ftrack.AssetVersion( iAObj.assetVersionId).getEntityRef() resultingNode.knob('assetId').setValue( HelpFunctions.safeString(iAObj.assetId)) resultingNode.knob('componentId').setValue( HelpFunctions.safeString(componentId)) resultingNode.knob('componentName').setValue( HelpFunctions.safeString(iAObj.componentName)) resultingNode.knob('assetVersionId').setValue( HelpFunctions.safeString(assetVersionId)) resultingNode.knob('assetVersion').setValue( HelpFunctions.safeString(iAObj.assetVersion)) resultingNode.knob('assetName').setValue( HelpFunctions.safeString(iAObj.assetName)) resultingNode.knob('assetType').setValue( HelpFunctions.safeString(iAObj.assetType))
def launch(self, event): data = event['data'] selection = data.get('selection', []) self.logger.info(selection) component = ftrack.Component(selection[0]['entityId']) path = component.getFilesystemPath() path = os.path.abspath(path) if sys.platform == 'win32': subprocess.Popen('explorer "%s"' % path) elif sys.platform == 'darwin': # macOS subprocess.Popen(['open', path]) else: # linux try: subprocess.Popen(['xdg-open', path]) except OSError: raise OSError('unsupported xdg-open call??') return {'success': True, 'message': 'Component Opened'}
def objectById(identifier): '''Return object from *identifier*.''' obj = None if identifier != '': if 'ftrack://' in identifier: url = urlparse.urlparse(identifier) query = urlparse.parse_qs(url.query) entityType = query.get('entityType')[0] identifier = url.netloc if entityType == 'assettake': obj = ftrack.Component(identifier) elif entityType == 'asset_version': obj = ftrack.AssetVersion(identifier) elif entityType == 'asset': obj = ftrack.Asset(identifier) elif entityType == 'show': obj = ftrack.Project(identifier) elif entityType == 'task': obj = ftrack.Task(identifier) else: ftrackObjectClasses = [ ftrack.Task, ftrack.Asset, ftrack.AssetVersion, ftrack.Component, ftrack.Project ] for cls in ftrackObjectClasses: try: obj = cls(id=identifier) break except: pass return obj
def importAsset(self, iAObj=None): component = ftrack.Component(iAObj.componentId) start, end = self.getStartEndFrames(component, iAObj) new_nodes = [] # Image plane if iAObj.options["importType"] == "Image Plane": movie_path = iAObj.filePath % start # Getting camera new_camera = False if iAObj.options["attachCamera"]: cam = pm.ls(selection=True)[0] else: cam = pm.createNode("camera") new_camera = True if iAObj.options["renameCamera"]: asset_name = component.getVersion().getAsset().getName() pm.rename(cam.getTransform(), asset_name) if new_camera: new_nodes.extend([cam.name(), cam.getTransform().name()]) if iAObj.options["resolutionGate"]: cam.displayResolution.set(1) cam.farClipPlane.set(iAObj.options["imagePlaneDepth"] * 10) # Create image plane visibility = True option = "Hidden from other cameras" if iAObj.options["imagePlaneVisibility"] == option: visibility = False image_plane_transform, image_plane_shape = pm.imagePlane( camera=cam, showInAllViews=visibility) image_plane_shape.depth.set(iAObj.options["imagePlaneDepth"]) # Need to get "type" by string, because its a method as well. pm.Attribute(image_plane_shape + ".type").set(2) image_plane_shape.imageName.set(movie_path) image_plane_shape.useFrameExtension.set(1) new_nodes.extend( [image_plane_transform.name(), image_plane_shape.name()]) # Create ground plane if iAObj.options["createGround"]: ground_transform, ground_shape = pm.polyPlane( name="ground", height=iAObj.options["groundSize"], width=iAObj.options["groundSize"]) ground_shader = pm.shadingNode("lambert", asShader=True) visiblity = iAObj.options["groundVisibility"] / 100 ground_shader.transparency.set(visiblity, visiblity, visiblity) pm.select(ground_transform) pm.hyperShade(assign=ground_shader.name()) new_nodes.extend([ ground_transform.name(), ground_shape.name(), ground_shader.name() ]) self.newData = set(new_nodes) self.oldData = set() self.linkToFtrackNode(iAObj)
def importAsset(self, iAObj=None): component = ftrack.Component(iAObj.componentId) start, end = self.getStartEndFrames(component, iAObj) first_image = iAObj.filePath % start new_nodes = [] # Image plane if iAObj.options["importType"] == "Image Plane": # Getting camera new_camera = False if iAObj.options["attachCamera"]: cam = pm.ls(selection=True)[0] else: cam = pm.createNode("camera") new_camera = True if iAObj.options["renameCamera"]: asset_name = component.getVersion().getAsset().getName() pm.rename(cam.getTransform(), asset_name) if new_camera: new_nodes.extend([cam.name(), cam.getTransform().name()]) if iAObj.options["resolutionGate"]: cam.displayResolution.set(1) cam.farClipPlane.set(iAObj.options["imagePlaneDepth"] * 10) # Create image plane visibility = True option = "Hidden from other cameras" if iAObj.options["imagePlaneVisibility"] == option: visibility = False image_plane_transform, image_plane_shape = pm.imagePlane( camera=cam, fileName=first_image, showInAllViews=visibility) image_plane_shape.useFrameExtension.set(1) image_plane_shape.depth.set(iAObj.options["imagePlaneDepth"]) new_nodes.extend( [image_plane_transform.name(), image_plane_shape.name()]) # Create ground plane if iAObj.options["createGround"]: ground_transform, ground_shape = pm.polyPlane( name="ground", height=iAObj.options["groundSize"], width=iAObj.options["groundSize"]) ground_shader = pm.shadingNode("lambert", asShader=True) visiblity = iAObj.options["groundVisibility"] / 100 ground_shader.transparency.set(visiblity, visiblity, visiblity) pm.select(ground_transform) pm.hyperShade(assign=ground_shader.name()) new_nodes.extend([ ground_transform.name(), ground_shape.name(), ground_shader.name() ]) # File Node if iAObj.options["importType"] == "File Node": file_node = pm.shadingNode("file", asTexture=True) file_node.fileTextureName.set(first_image) file_node.useFrameExtension.set(1) exp = pm.shadingNode("expression", asUtility=True) exp.expression.set(file_node.name() + ".frameExtension=frame") new_nodes.extend([file_node.name(), exp.name()]) # Connecting file node to color management in 2016+ if pm.objExists("defaultColorMgtGlobals"): colMgmtGlob = pm.PyNode("defaultColorMgtGlobals") mapping = { "cmEnabled": "colorManagementEnabled", "configFileEnabled": "colorManagementConfigFileEnabled", "configFilePath": "colorManagementConfigFilePath", "workingSpaceName": "workingSpace" } for key, value in mapping.iteritems(): src_name = colMgmtGlob.name() + "." + key dst_name = file_node.name() + "." + value pm.PyNode(src_name) >> pm.PyNode(dst_name) texture = None if iAObj.options["fileNodeType"] != "Single Node": texture = pm.shadingNode("place2dTexture", asUtility=True) src_name = texture.name() + ".outUV" dst_name = file_node.name() + ".uvCoord" pm.PyNode(src_name) >> pm.PyNode(dst_name) src_name = texture.name() + ".outUvFilterSize" dst_name = file_node.name() + ".uvFilterSize" pm.PyNode(src_name) >> pm.PyNode(dst_name) connections = [ "rotateUV", "offset", "noiseUV", "vertexCameraOne", "vertexUvThree", "vertexUvTwo", "vertexUvOne", "repeatUV", "wrapV", "wrapU", "stagger", "mirrorU", "mirrorV", "rotateFrame", "translateFrame", "coverage" ] for connection in connections: src_name = texture.name() + "." + connection dst_name = file_node.name() + "." + connection pm.PyNode(src_name) >> pm.PyNode(dst_name) new_nodes.append(texture.name()) if iAObj.options["fileNodeType"] == "Projection": projection = pm.shadingNode("projection", asUtility=True) texture3d = pm.shadingNode("place3dTexture", asUtility=True) src_name = file_node.name() + ".outColor" dst_name = projection.name() + ".image" pm.PyNode(src_name) >> pm.PyNode(dst_name) src_name = texture3d.name() + ".worldInverseMatrix" dst_name = projection.name() + ".placementMatrix" pm.PyNode(src_name) >> pm.PyNode(dst_name) new_nodes.extend([projection.name(), texture3d.name()]) self.newData = set(new_nodes) self.oldData = set() self.linkToFtrackNode(iAObj)
def getEntityById(self, identifier, throw=True): '''Return an entity represented by the given *identifier*. If *throw* is True then raise :py:exc:`FnAssetAPI.exceptions.InvalidEntityReference` if no entity can be found, otherwise return None. ''' entity = None if identifier != '': if 'ftrack://' in identifier: url = urlparse.urlparse(identifier) query = urlparse.parse_qs(url.query) entityType = query.get('entityType')[0] identifier = url.netloc try: return self._memoiser.cache.get(identifier) except KeyError: pass try: if entityType == 'component': entity = ftrack.Component(identifier) elif entityType == 'asset_version': entity = ftrack.AssetVersion(identifier) elif entityType == 'asset': entity = ftrack.Asset(identifier) elif entityType == 'show': entity = ftrack.Project(identifier) elif entityType == 'task': entity = ftrack.Task(identifier) elif entityType == 'tasktype': entity = ftrack.TaskType(identifier) except: pass else: ftrackObjectClasses = [ ftrack.Task, ftrack.Asset, ftrack.AssetVersion, ftrack.Component, ftrack.Project, ftrack.TaskType ] try: return self._memoiser.cache.get(identifier) except KeyError: pass for cls in ftrackObjectClasses: try: entity = cls(id=identifier) break except ftrack.FTrackError as error: if error.message.find('was not found') == -1: raise pass except Exception, error: FnAssetAPI.logging.log( 'Exception caught trying to create {0}: {1}'. format(cls.__name__, error), FnAssetAPI.logging.kError) raise
def import_components(components): for new_component in components: component = ftrack.Component(new_component["id"]) assetversion = component.getVersion() asset = assetversion.getAsset() assettype = asset.getType() # Create node resultingNode = nuke.createNode('Read', inpanel=False) resultingNode['name'].setValue( HelpFunctions.safeString(asset.getName()) + '_' + HelpFunctions.safeString(component.getName())) # Add Ftrack tab knobs = resultingNode.knobs().keys() if 'ftracktab' not in knobs: # Note: the tab is supposed to be existing as it gets created # through callback during the read and write nodes creation. # This check is to ensure corner cases are handled properly. tab = nuke.Tab_Knob('ftracktab', 'ftrack') resultingNode.addKnob(tab) btn = nuke.String_Knob('componentId') resultingNode.addKnob(btn) btn = nuke.String_Knob('componentName') resultingNode.addKnob(btn) btn = nuke.String_Knob('assetVersionId') resultingNode.addKnob(btn) btn = nuke.String_Knob('assetVersion') resultingNode.addKnob(btn) btn = nuke.String_Knob('assetName') resultingNode.addKnob(btn) btn = nuke.String_Knob('assetType') resultingNode.addKnob(btn) btn = nuke.String_Knob('assetId') resultingNode.addKnob(btn) # Setup node file_path = component.getResourceIdentifier() resultingNode['file'].fromUserText(HelpFunctions.safeString(file_path)) members = component.getMembers() frames = [int(member.getName()) for member in members] start = min(frames) end = max(frames) resultingNode['first'].setValue(start) resultingNode['origfirst'].setValue(start) resultingNode['last'].setValue(end) resultingNode['origlast'].setValue(end) resultingNode.knob('assetId').setValue( HelpFunctions.safeString(asset.getId())) resultingNode.knob('componentId').setValue( HelpFunctions.safeString(component.getEntityRef())) resultingNode.knob('componentName').setValue( HelpFunctions.safeString(component.getName())) resultingNode.knob('assetVersionId').setValue( HelpFunctions.safeString(assetversion.getEntityRef())) resultingNode.knob('assetVersion').setValue( HelpFunctions.safeString(str(assetversion.getVersion()))) resultingNode.knob('assetName').setValue( HelpFunctions.safeString(asset.getName())) resultingNode.knob('assetType').setValue( HelpFunctions.safeString(assettype.getShort()))
def importAsset(self, iAObj=None): '''Import asset defined in *iAObj*''' if (iAObj.componentName == 'alembic' or iAObj.filePath.endswith('abc')): try: mc.loadPlugin('AbcImport.so', qt=1) except: return 'Failed to load alembic plugin' self.oldData = set(mc.ls()) mc.createNode('transform', n=iAObj.assetName) mc.AbcImport(iAObj.filePath, mode='import', reparent=iAObj.assetName) self.newData = set(mc.ls()) self.linkToFtrackNode(iAObj) elif any([ iAObj.filePath.endswith(format) for format in SUPPORTED_SOUND_FORMATS ]): self.oldData = set(mc.ls()) start_frame = mc.playbackOptions(q=True, min=True) mc.sound(file=iAObj.filePath, offset=start_frame) self.newData = set(mc.ls()) self.linkToFtrackNode(iAObj) else: component = ftrack.Component(iAObj.componentId) self.importAssetBool = False preserveReferences = True self.referenceAssetBool = True groupReferenceBool = True # Determine namespace nameSpaceStr = ':' if iAObj.options['mayaAddNamespace']: if iAObj.options['mayaNamespace'] == 'File name': nameSpaceStr = os.path.basename(iAObj.filePath) nameSpaceStr = os.path.splitext(nameSpaceStr)[0] # Remove the last bit, which usually is the version nameSpaceStr = '_'.join(nameSpaceStr.split('_')[:-1]) if iAObj.options['mayaNamespace'] == 'Component': nameSpaceStr = iAObj.componentName if iAObj.options['mayaNamespace'] == 'Custom': # Use custom namespace if any is specified. if iAObj.options['nameSpaceStr']: nameSpaceStr = iAObj.options['nameSpaceStr'] # Determine import type mapping = {'.ma': 'mayaAscii', '.mb': 'mayaBinary'} importType = mapping.get(component.getFileType(), 'mayaBinary') if iAObj.componentName in [ 'mayaBinary', 'main', 'mayaBinaryScene', 'mayaAscii', 'mayaAsciiScene' ]: if 'importMode' in iAObj.options: if iAObj.options['importMode'] == 'Import': self.importAssetBool = True self.referenceAssetBool = False # do not group when importing groupReferenceBool = False if iAObj.componentName in ('mayaAscii', 'mayaAsciiScene'): importType = 'mayaAscii' elif iAObj.componentName in ['audio']: importType = 'audio' self.importAssetBool = True self.referenceAssetBool = False if iAObj.componentName in ['mayaBinaryScene']: confirmDialog = mc.confirmDialog( title='Confirm', message='Replace current scene?', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if confirmDialog == 'Yes': mc.file(new=True, force=True) else: return 'Canceled Import' if ('mayaReference' in iAObj.options and iAObj.options['mayaReference']): preserveReferences = iAObj.options['mayaReference'] self.oldData = set(mc.ls()) nodes = mc.file(iAObj.filePath, type=importType, i=self.importAssetBool, reference=self.referenceAssetBool, groupLocator=False, groupReference=groupReferenceBool, groupName=iAObj.assetName, loadReferenceDepth='all', sharedNodes='renderLayersByName', preserveReferences=preserveReferences, mergeNamespacesOnClash=True, namespace=nameSpaceStr, returnNewNodes=True, options='v=0') self.newData = set(mc.ls()) # Find the actual groupName if iAObj.componentName in ['audio']: mc.rename(nodes[0], iAObj.assetName) else: iAObj.assetName = self.getGroupName(nodes, iAObj.assetName) try: self.linkToFtrackNode(iAObj) except Exception as error: print error # Restore timeline on asset import. mayacon.Connector.setTimeLine() return 'Imported ' + iAObj.assetType + ' asset'