diff --git a/pype/maya/lib.py b/pype/maya/lib.py index ac3b40bf5e..a61a494eae 100644 --- a/pype/maya/lib.py +++ b/pype/maya/lib.py @@ -2032,3 +2032,103 @@ def bake_to_world_space(nodes, shape=shape) return world_space_nodes + + +def load_capture_preset(path): + import capture_gui + import capture + + path = path + preset = capture_gui.lib.load_json(path) + print preset + + options = dict() + + # CODEC + id = 'Codec' + for key in preset[id]: + options[str(key)]= preset[id][key] + + # GENERIC + id = 'Generic' + for key in preset[id]: + if key.startswith('isolate'): + pass + # options['isolate'] = preset[id][key] + else: + options[str(key)] = preset[id][key] + + # RESOLUTION + id = 'Resolution' + options['height'] = preset[id]['height'] + options['width'] = preset[id]['width'] + + + # DISPLAY OPTIONS + id = 'Display Options' + disp_options = {} + for key in preset['Display Options']: + if key.startswith('background'): + disp_options[key] = preset['Display Options'][key] + else: + disp_options['displayGradient'] = True + + options['display_options'] = disp_options + + + # VIEWPORT OPTIONS + temp_options = {} + id = 'Renderer' + for key in preset[id]: + temp_options[str(key)] = preset[id][key] + + temp_options2 = {} + id = 'Viewport Options' + light_options = { 0: "default", + 1: 'all', + 2: 'selected', + 3: 'flat', + 4: 'nolights'} + for key in preset[id]: + if key == 'high_quality': + temp_options2['multiSampleEnable'] = True + temp_options2['multiSampleCount'] = 4 + temp_options2['textureMaxResolution'] = 512 + temp_options2['enableTextureMaxRes'] = True + + if key == 'alphaCut' : + temp_options2['transparencyAlgorithm'] = 5 + temp_options2['transparencyQuality'] = 1 + + if key == 'headsUpDisplay' : + temp_options['headsUpDisplay'] = True + + if key == 'displayLights': + temp_options[str(key)] = light_options[preset[id][key]] + else: + temp_options[str(key)] = preset[id][key] + + for key in ['override_viewport_options', 'high_quality', 'alphaCut']: + temp_options.pop(key, None) + + options['viewport_options'] = temp_options + options['viewport2_options'] = temp_options2 + + + # use active sound track + scene = capture.parse_active_scene() + options['sound'] = scene['sound'] + cam_options = dict() + cam_options['overscan'] = 1.0 + cam_options['displayFieldChart'] = False + cam_options['displayFilmGate'] = False + cam_options['displayFilmOrigin'] = False + cam_options['displayFilmPivot'] = False + cam_options['displayGateMask'] = False + cam_options['displayResolution'] = False + cam_options['displaySafeAction'] = False + cam_options['displaySafeTitle'] = False + + # options['display_options'] = temp_options + + return options diff --git a/pype/plugins/maya/create/create_review.py b/pype/plugins/maya/create/create_review.py new file mode 100644 index 0000000000..bf2fe3088f --- /dev/null +++ b/pype/plugins/maya/create/create_review.py @@ -0,0 +1,23 @@ +from collections import OrderedDict +import avalon.maya +from pype.maya import lib + + +class CreateReview(avalon.maya.Creator): + """Single baked camera""" + + name = "reviewDefault" + label = "Review" + family = "review" + icon = "video-camera" + + def __init__(self, *args, **kwargs): + super(CreateReview, self).__init__(*args, **kwargs) + + # get basic animation data : start / end / handles / steps + data = OrderedDict(**self.data) + animation_data = lib.collect_animation_data() + for key, value in animation_data.items(): + data[key] = value + + self.data = data diff --git a/pype/plugins/maya/publish/collect_review.py b/pype/plugins/maya/publish/collect_review.py new file mode 100644 index 0000000000..67969440d7 --- /dev/null +++ b/pype/plugins/maya/publish/collect_review.py @@ -0,0 +1,17 @@ +from maya import cmds + +import pyblish.api + +class CollectReviewData(pyblish.api.InstancePlugin): + """Collect Review data + + """ + + order = pyblish.api.CollectorOrder + 0.499 + label = 'Collect Review Data' + families = ["review"] + + def process(self, instance): + + # make ftrack publishable + instance.data["families"] = ['ftrack'] diff --git a/pype/plugins/maya/publish/extract_quicktime.py b/pype/plugins/maya/publish/extract_quicktime.py new file mode 100644 index 0000000000..222d349174 --- /dev/null +++ b/pype/plugins/maya/publish/extract_quicktime.py @@ -0,0 +1,185 @@ +import os +import contextlib +import time + +import capture_gui + +import pype.maya.lib as lib +import pype.api + +from maya import cmds +import pymel.core as pm + + +import avalon.maya + +# import maya_utils as mu + +# from tweakHUD import master +# from tweakHUD import draft_hud as dHUD +# from tweakHUD import ftrackStrings as fStrings + +# +# def soundOffsetFunc(oSF, SF, H): +# tmOff = (oSF - H) - SF +# return tmOff + + +class ExtractQuicktime(pype.api.Extractor): + """Extract a Camera as Alembic. + + The cameras gets baked to world space by default. Only when the instance's + `bakeToWorldSpace` is set to False it will include its full hierarchy. + + """ + + label = "Quicktime (Alembic)" + hosts = ["maya"] + families = ["review"] + + def process(self, instance): + self.log.info("Extracting capture..") + + start = instance.data["startFrame"] + end = instance.data["endFrame"] + self.log.info("start: {}, end: {}".format(start, end)) + handles = instance.data.get("handles", 0) + if handles: + start -= handles + end += handles + + # get cameras + members = instance.data['setMembers'] + cameras = cmds.ls(members, leaf=True, shapes=True, long=True, + dag=True, type="camera") + + # validate required settings + assert len(cameras) == 1, "Not a single camera found in extraction" + camera = cameras[0] + + + # project_code = ftrack_data['Project']['code'] + # task_type = ftrack_data['Task']['type'] + # + # # load Preset + # studio_repos = os.path.abspath(os.environ.get('studio_repos')) + # shot_preset_path = os.path.join(studio_repos, 'maya', + # 'capture_gui_presets', + # (project_code + '_' + task_type + '_' + asset + '.json')) + # + # task_preset_path = os.path.join(studio_repos, 'maya', + # 'capture_gui_presets', + # (project_code + '_' + task_type + '.json')) + # + # project_preset_path = os.path.join(studio_repos, 'maya', + # 'capture_gui_presets', + # (project_code + '.json')) + # + # default_preset_path = os.path.join(studio_repos, 'maya', + # 'capture_gui_presets', + # 'default.json') + # + # if os.path.isfile(shot_preset_path): + # preset_to_use = shot_preset_path + # elif os.path.isfile(task_preset_path): + # preset_to_use = task_preset_path + # elif os.path.isfile(project_preset_path): + # preset_to_use = project_preset_path + # else: + # preset_to_use = default_preset_path + + capture_preset = "" + try: + preset = lib.load_capture_preset(capture_preset) + except: + preset = {} + self.log.info('using viewport preset: {}'.format(capture_preset)) + + #preset["off_screen"] = False + + preset['camera'] = camera + preset['format'] = "image" + # preset['compression'] = "qt" + preset['quality'] = 50 + preset['compression'] = "jpg" + preset['start_frame'] = 1 + preset['end_frame'] = 25 + preset['camera_options'] = { + "displayGateMask": False, + "displayResolution": False, + "displayFilmGate": False, + "displayFieldChart": False, + "displaySafeAction": False, + "displaySafeTitle": False, + "displayFilmPivot": False, + "displayFilmOrigin": False, + "overscan": 1.0, + "depthOfField": cmds.getAttr("{0}.depthOfField".format(camera)), + } + + stagingdir = self.staging_dir(instance) + filename = "{0}".format(instance.name) + path = os.path.join(stagingdir, filename) + + self.log.info("Outputting images to %s" % path) + + preset['filename'] = path + preset['overwrite'] = True + + # pm.refresh(f=True) + # + # refreshFrameInt = int(pm.playbackOptions(q=True, minTime=True)) + # pm.currentTime(refreshFrameInt - 1, edit=True) + # pm.currentTime(refreshFrameInt, edit=True) + + with maintained_time(): + playblast = capture_gui.lib.capture_scene(preset) + + if "files" not in instance.data: + instance.data["files"] = list() + instance.data["files"].append(playblast) + + + + + + + # self.log.info("Calculating HUD data overlay") + + # movieFullPth = path + ".mov" + # fls = [os.path.join(dir_path, f).replace("\\","/") for f in os.listdir( dir_path ) if f.endswith(preset['compression'])] + #self.log.info(" these %s" % fls[0]) + + # ftrackStrings = fStrings.annotationData() + # nData = ftrackStrings.niceData + # nData['version'] = instance.context.data('version') + # fFrame = int(pm.playbackOptions( q = True, minTime = True)) + # eFrame = int(pm.playbackOptions( q = True, maxTime = True)) + # nData['frame'] = [(str("{0:05d}".format(f))) for f in range(fFrame, eFrame + 1)] + # soundOfst = int(float(nData['oFStart'])) - int(float(nData['handle'])) - fFrame + # soundFile = mu.giveMePublishedAudio() + # self.log.info("SOUND offset %s" % str(soundOfst)) + # self.log.info("SOUND source video to %s" % str(soundFile)) + # ann = dHUD.draftAnnotate() + # if soundFile: + # ann.addAnotation(seqFls = fls, outputMoviePth = movieFullPth, annotateDataArr = nData, soundFile = soundFile, soundOffset = soundOfst) + # else: + # ann.addAnotation(seqFls = fls, outputMoviePth = movieFullPth, annotateDataArr = nData) + + # for f in fls: + # os.remove(f) + + # playblast = (ann.expPth).replace("\\","/") + + + instance.data["outputPath_qt"] = playblast + self.log.info("Outputting video to %s" % playblast) + + +@contextlib.contextmanager +def maintained_time(): + ct = cmds.currentTime(query=True) + try: + yield + finally: + cmds.currentTime(ct, edit=True)