def get_frame_per_file_render_arguments(self): """ Generates the render arguments for when FramePerFile mode is set to True. This means that each output frame has an associated scene file with the same frame number. This is mostly used in Octane 1 before .orbx was a thing. :return: a list of commandline arguments, and the scene file """ render_args = ['-e', '-q'] sceneFile = self.GetPluginInfoEntry("SceneFile") sceneFile = PathUtils.ToPlatformIndependentPath( RepositoryUtils.CheckPathMapping(sceneFile)) outputFile = self.CreateOutputFile() paddingSize = 0 if not self.GetBooleanPluginInfoEntryWithDefault("SingleFile", True): currPadding = FrameUtils.GetFrameStringFromFilename(sceneFile) paddingSize = len(currPadding) if paddingSize > 0: newPadding = StringUtils.ToZeroPaddedString( self.GetStartFrame(), paddingSize, False) sceneFile = FrameUtils.SubstituteFrameNumber( sceneFile, newPadding) # Build the new output file name. if outputFile: outputFile = PathUtils.ToPlatformIndependentPath( RepositoryUtils.CheckPathMapping(outputFile)) # Add padding to output file if necessary. if paddingSize > 0: outputFile = FrameUtils.SubstituteFrameNumber( outputFile, newPadding) outputPath = os.path.dirname(outputFile) outputFileName, outputExtension = os.path.splitext(outputFile) outputFile = os.path.join( outputPath, outputFileName + newPadding + outputExtension) render_args.extend(['-o', outputFile]) sample = self.GetIntegerPluginInfoEntryWithDefault( "OverrideSampling", 0) if sample > 0: render_args.extend(['-s', str(sample)]) render_target = self.GetPluginInfoEntryWithDefault( "RenderTargetOCS", "") if render_target: render_args.extend(['-t', render_target]) return render_args, sceneFile
def _check_selected_files( self, pass_type, local_files, errors, warnings ): """ Performs sanity checks on the selected files that will be included in the denoising process :param pass_type: The pass type corresponding to the files to check :param local_files: Existing list of local files :param errors: Existing list of errors :param warnings: Existing list of warnings :return: """ stereo_enabled = self.GetValue( "StereoBox" ) if self._pass_enabled( pass_type ): files_str = self.GetValue( "%sBox" % pass_type ) if not files_str: errors.append( "No outputs set for the enabled pass: %s." % pass_type ) return split_files = files_str.split( ";" ) if not stereo_enabled: if pass_type != "Extra": if len( split_files ) % 2 != 0: errors.append( "An even number of files must be selected for frame passes if Extra is enabled and not using stereo rendering." ) else: if len( split_files ) != 2: errors.append( "Two files must be selected for frame passes if Extra is enabled and not using stereo rendering." ) for split_file in split_files: if not os.path.isfile( split_file ): warnings.append( "\nThe selected .exr file %s does not exist." % split_file ) elif PathUtils.IsPathLocal( split_file ): local_files.append( split_file ) return
def RenderArgument(self): """ Builds up the commandline render arguments as a list which then gets transformed into string :return: a string of commandline arguments """ scene_file = self.GetPluginInfoEntry("SceneFile") scene_file = PathUtils.ToPlatformIndependentPath( RepositoryUtils.CheckPathMapping(scene_file)) render_args = ['--no-gui'] frame_per_file_mode = self.GetBooleanPluginInfoEntryWithDefault( "FramePerFileMode", False) if frame_per_file_mode: # Octane 1 workflow that's still supported in 2 and onward. temp_render_args, scene_file = self.get_frame_per_file_render_arguments( ) render_args.extend(temp_render_args) else: render_args.extend(self.get_script_render_arguments()) additional_args = self.GetPluginInfoEntryWithDefault( "AdditionalArgs", "").strip() if additional_args: render_args.append(additional_args) render_args.extend(self.get_gpu_render_arguments()) render_args.append(scene_file) return self.quote_cmdline_args(render_args)
def get_script_render_arguments(self): """ Generates the render arguments for the octane lua script workflow. Octane 2 and later. :return: a list of commandline arguments """ output_folder = self.GetPluginInfoEntryWithDefault("OutputFolder", "") output_folder = PathUtils.ToPlatformIndependentPath( RepositoryUtils.CheckPathMapping(output_folder)) lua_script = os.path.join(self.GetPluginDirectory(), "DeadlineOctane.lua") filename_template = self.GetPluginInfoEntryWithDefault( "FilenameTemplate", "") file_format = self.GetPluginInfoEntryWithDefault("FileFormat", "png8") render_target_ocs = self.GetPluginInfoEntryWithDefault( "RenderTargetOCS", "") render_target_orbx = self.GetPluginInfoEntryWithDefault( "RenderTargetORBX", "") render_target = "" if render_target_ocs: render_target = render_target_ocs elif render_target_orbx: render_target = render_target_orbx render_args = [ '-q', '--script', lua_script, '-a', filename_template, '-a', output_folder, '-a', file_format, '-a', str(self.GetStartFrame()), '-a', str(self.GetEndFrame()), '-a', render_target, '--stop-after-script', ] sample = self.GetIntegerPluginInfoEntryWithDefault( "OverrideSampling", 0) if sample > 0: render_args.extend(['-s', str(sample)]) if render_target: render_args.extend(['-t', render_target]) return render_args
def _check_config_input( self, errors, warnings ): """ Performs a sanity check on the configuration file input :param errors: Existing list of errors :param warnings: Existing list of warnings :return: """ config_file = self.GetValue( "ConfigBox" ) if not config_file: errors.append( "No config file has been set!" ) elif not os.path.isfile( config_file ): errors.append( "The selected config file %s does not exist." % config_file ) elif PathUtils.IsPathLocal( config_file ): warnings.append( "The selected config file %s is local." % config_file )
def _check_output_destination( self, errors, warnings): """ Performs sanity checks on the output destination. :param errors: list of encountered errors :param warnings: list of encountered warnings :return: """ output_folder = self.GetValue( "OutputBox" ) if not output_folder: errors.append("An output path must be selected.") else: output_dir = os.path.dirname( output_folder ) if PathUtils.IsPathLocal( output_dir ): warnings.append( "Output folder %s is local." % output_dir ) if not os.path.isdir( output_dir ): warnings.append( "Output folder %s does not exist." % output_dir )
def isValidSubmission(): """ Runs sanity checks on the current submission params to see if we know the submission is bad, so we can fail fast. If there's warnings and/or errors, we present them to the user so they can be fixed. :return: a boolean indicating if we believe this submission is valid """ global scriptDialog errors = "" warnings = "" # Check if SU file exists sceneFile = scriptDialog.GetValue( "SceneBox" ) if not os.path.isfile( sceneFile ): errors += 'SketchUp file "%s" does not exist.\n\n' % sceneFile elif PathUtils.IsPathLocal( sceneFile ) and not scriptDialog.GetValue( "SubmitSceneBox" ): warnings += 'SketchUp file "%s" is local.\n\n' % sceneFile # Check Output exportDirectory = scriptDialog.GetValue( "ExportDirectoryBox" ).strip() if not exportDirectory: errors += "An output directory was not specific.\n\n" elif not os.path.isdir( exportDirectory ): errors += 'The directory of the output file does not exist: "%s"\n\n' % exportDirectory isVray = scriptDialog.GetEnabled( "VrayBox" ) and scriptDialog.GetValue( "VrayBox" ) vrayVersion = int( scriptDialog.GetValue( "VrayVersionBox" ) ) vrayFrames = scriptDialog.GetValue( "VrayFramesBox" ).strip() # Check if a valid frame range has been specified for V-Ray 3 or later if isVray and vrayVersion >= 3 and is2dAnimation() and not FrameUtils.FrameRangeValid( vrayFrames ): errors += 'Frame range "%s" is not valid.\n\n' % vrayFrames if errors: scriptDialog.ShowMessageBox( "The following errors occurred, you must fix these before continuing.\n\n%s" % errors.strip(), "Error" ) return False elif warnings: result = scriptDialog.ShowMessageBox( "The following warnings occurred, are you sure you want to continue?\n\n%s" % warnings.strip(), "Warning", ( "Yes", "No" ) ) if result == "No": return False return True
def SubmitButtonPressed(*args): global scriptDialog global integration_dialog try: submitScene = scriptDialog.GetValue("SubmitSceneBox") # Check if Integration options are valid if not integration_dialog.CheckIntegrationSanity(): return warnings = [] errors = [] # Check if max files exist. sceneFiles = StringUtils.FromSemicolonSeparatedString( scriptDialog.GetValue("SceneBox"), False) if not sceneFiles: errors.append("No 3dsmax file specified") for sceneFile in sceneFiles: if not File.Exists(sceneFile): errors.append("3dsmax file %s does not exist" % sceneFile) return elif not submitScene and PathUtils.IsPathLocal(sceneFile): warnings.append( "The scene file " + sceneFile + " is local and is not being submitted with the job, are you sure you want to continue?" ) # Check if path config file exists. pathConfigFile = scriptDialog.GetValue("PathConfigBox").strip() if pathConfigFile: if not File.Exists(pathConfigFile): errors.append("Path configuration file %s does not exist" % pathConfigFile) # Check if PreLoad script file exists. preLoadFile = scriptDialog.GetValue("PreLoadBox").strip() if preLoadFile: if not File.Exists(preLoadFile): errors.append("PreLoad MAXScript file %s does not exist" % preLoadFile) # Check if PostLoad script file exists. postLoadFile = scriptDialog.GetValue("PostLoadBox").strip() if postLoadFile: if not File.Exists(postLoadFile): errors.append("PostLoad MAXScript file %s does not exist" % postLoadFile) # Check if PreFrame script file exists. preFrameFile = scriptDialog.GetValue("PreFrameBox").strip() if preFrameFile: if not File.Exists(preFrameFile): errors.append("PreFrame MAXScript file %s does not exist" % preFrameFile) # Check if PostFrame script file exists. postFrameFile = scriptDialog.GetValue("PostFrameBox").strip() if postFrameFile: if not File.Exists(postFrameFile): errors.append("PostFrame MAXScript file %s does not exist" % postFrameFile) # Check if a valid frame range has been specified. frames = scriptDialog.GetValue("FramesBox") if scriptDialog.GetValue("DBRModeBox") != "Disabled": frameArray = FrameUtils.Parse(frames) if len(frameArray) != 1: errors.append( "Please specify a single frame for distributed rendering in the Frame List." ) elif not FrameUtils.FrameRangeValid(frames): errors.append( "Please specify a valid single frame for distributed rendering in the Frame List." ) frames = "0-" + str(scriptDialog.GetValue("DBRServersBox") - 1) else: if not FrameUtils.FrameRangeValid(frames): errors.append("Frame range %s is not valid" % frames) # If using 'select GPU device Ids' then check device Id syntax is valid if scriptDialog.GetValue( "GPUsPerTaskBox") == 0 and scriptDialog.GetValue( "GPUsSelectDevicesBox"): regex = re.compile("^(\d{1,2}(,\d{1,2})*)?$") validSyntax = regex.match( scriptDialog.GetValue("GPUsSelectDevicesBox")) if not validSyntax: errors.append( "'Select GPU Devices' syntax is invalid!\nTrailing 'commas' if present, should be removed.\nValid Examples: 0 or 2 or 0,1,2 or 0,3,4 etc" ) # Check if concurrent threads > 1 if scriptDialog.GetValue("ConcurrentTasksBox") > 1: errors.append( "If using 'Select GPU Devices', then 'Concurrent Tasks' must be set to 1" ) if errors: scriptDialog.ShowMessageBox( "The following errors were encountered:\n\n%s\n\nPlease resolve these issues and submit again.\n" % ("\n\n".join(errors)), "Errors") return if warnings: result = scriptDialog.ShowMessageBox( "Warnings:\n\n%s\n\nDo you still want to continue?" % ("\n\n".join(warnings)), "Warnings", ("Yes", "No")) if result == "No": return successes = 0 failures = 0 # Submit each scene file separately. for sceneFile in sceneFiles: jobName = scriptDialog.GetValue("NameBox") if len(sceneFiles) > 1: jobName = jobName + " [" + Path.GetFileName(sceneFile) + "]" # Create job info file. jobInfoFilename = Path.Combine(ClientUtils.GetDeadlineTempPath(), "max_job_info.job") writer = StreamWriter(jobInfoFilename, False, Encoding.Unicode) writer.WriteLine("Plugin=3dsmax") writer.WriteLine("Name=%s" % jobName) writer.WriteLine("Comment=%s" % scriptDialog.GetValue("CommentBox")) writer.WriteLine("Department=%s" % scriptDialog.GetValue("DepartmentBox")) writer.WriteLine("Pool=%s" % scriptDialog.GetValue("PoolBox")) writer.WriteLine("SecondaryPool=%s" % scriptDialog.GetValue("SecondaryPoolBox")) writer.WriteLine("Group=%s" % scriptDialog.GetValue("GroupBox")) writer.WriteLine("Priority=%s" % scriptDialog.GetValue("PriorityBox")) writer.WriteLine("TaskTimeoutMinutes=%s" % scriptDialog.GetValue("TaskTimeoutBox")) writer.WriteLine("EnableAutoTimeout=%s" % scriptDialog.GetValue("AutoTimeoutBox")) writer.WriteLine("ConcurrentTasks=%s" % scriptDialog.GetValue("ConcurrentTasksBox")) writer.WriteLine("LimitConcurrentTasksToNumberOfCpus=%s" % scriptDialog.GetValue("LimitConcurrentTasksBox")) writer.WriteLine("MachineLimit=%s" % scriptDialog.GetValue("MachineLimitBox")) if scriptDialog.GetValue("IsBlacklistBox"): writer.WriteLine("Blacklist=%s" % scriptDialog.GetValue("MachineListBox")) else: writer.WriteLine("Whitelist=%s" % scriptDialog.GetValue("MachineListBox")) writer.WriteLine("LimitGroups=%s" % scriptDialog.GetValue("LimitGroupBox")) writer.WriteLine("JobDependencies=%s" % scriptDialog.GetValue("DependencyBox")) writer.WriteLine("OnJobComplete=%s" % scriptDialog.GetValue("OnJobCompleteBox")) if scriptDialog.GetValue("SubmitSuspendedBox"): writer.WriteLine("InitialStatus=Suspended") writer.WriteLine("Frames=%s" % frames) if scriptDialog.GetValue("DBRModeBox") == "Disabled": writer.WriteLine("ChunkSize=%s" % scriptDialog.GetValue("ChunkSizeBox")) # Integration extraKVPIndex = 0 groupBatch = False if integration_dialog.IntegrationProcessingRequested(): extraKVPIndex = integration_dialog.WriteIntegrationInfo( writer, extraKVPIndex) groupBatch = groupBatch or integration_dialog.IntegrationGroupBatchRequested( ) if groupBatch: writer.WriteLine("BatchName=%s\n" % jobName) writer.Close() # Create plugin info file. pluginInfoFilename = Path.Combine( ClientUtils.GetDeadlineTempPath(), "max_plugin_info.job") writer = StreamWriter(pluginInfoFilename, False, Encoding.Unicode) writer.WriteLine("Version=%s" % scriptDialog.GetValue("VersionBox")) writer.WriteLine("IsMaxDesign=%s" % scriptDialog.GetValue("IsMaxDesignBox")) if int(scriptDialog.GetValue("VersionBox")) < 2014: writer.WriteLine("MaxVersionToForce=%s" % scriptDialog.GetValue("BuildBox")) writer.WriteLine("MaxVersionToForce0=None") writer.WriteLine("MaxVersionToForce1=32bit") writer.WriteLine("MaxVersionToForce2=64bit") writer.WriteLine("UseSlaveMode=%d" % (not scriptDialog.GetValue("WorkstationModeBox"))) if scriptDialog.GetValue("WorkstationModeBox"): writer.WriteLine("UseSilentMode=%s" % (scriptDialog.GetValue("SilentModeBox"))) else: writer.WriteLine("UseSilentMode=False") writer.WriteLine("ShowFrameBuffer=%s" % scriptDialog.GetValue("ShowVfbBox")) writer.WriteLine("RemovePadding=%s" % scriptDialog.GetValue("RemovePaddingBox")) writer.WriteLine("RestartRendererMode=%s" % scriptDialog.GetValue("RestartRendererBox")) writer.WriteLine( "IgnoreMissingExternalFiles=%s" % scriptDialog.GetValue("IgnoreMissingExternalFilesBox")) writer.WriteLine("IgnoreMissingUVWs=%s" % scriptDialog.GetValue("IgnoreMissingUVWsBox")) writer.WriteLine("IgnoreMissingXREFs=%s" % scriptDialog.GetValue("IgnoreMissingXREFsBox")) writer.WriteLine("IgnoreMissingDLLs=%s" % scriptDialog.GetValue("IgnoreMissingDLLsBox")) writer.WriteLine("LocalRendering=%s" % scriptDialog.GetValue("LocalRenderingBox")) writer.WriteLine("DisableMultipass=%s" % scriptDialog.GetValue("DisableMultipassBox")) writer.WriteLine("OneCpuPerTask=%s" % scriptDialog.GetValue("OneCpuPerTaskBox")) if pathConfigFile: writer.WriteLine("PathConfigFile=%s" % Path.GetFileName(pathConfigFile)) writer.WriteLine("MergePathConfigFile=%s" % scriptDialog.GetValue("MergePathConfigBox")) if preLoadFile: writer.WriteLine("PreLoadScript=%s" % Path.GetFileName(preLoadFile)) if postLoadFile: writer.WriteLine("PostLoadScript=%s" % Path.GetFileName(postLoadFile)) if preFrameFile: writer.WriteLine("PreFrameScript=%s" % Path.GetFileName(preFrameFile)) if postFrameFile: writer.WriteLine("PostFrameScript=%s" % Path.GetFileName(postFrameFile)) pluginIniOverride = scriptDialog.GetValue("PluginIniBox").strip() if pluginIniOverride: writer.WriteLine("OverridePluginIni=%s" % pluginIniOverride) writer.WriteLine("GammaCorrection=%s" % scriptDialog.GetValue("GammaCorrectionBox")) writer.WriteLine("GammaInput=%s" % scriptDialog.GetValue("GammaInputBox")) writer.WriteLine("GammaOutput=%s" % scriptDialog.GetValue("GammaOutputBox")) if int(scriptDialog.GetValue("VersionBox")) >= 2013: if scriptDialog.GetValue("OverrideLanguageBox"): writer.WriteLine("Language=%s" % scriptDialog.GetValue("LanguageBox")) else: writer.WriteLine("Language=Default") camera = scriptDialog.GetValue("CameraBox") if camera: writer.WriteLine("Camera=%s" % camera) writer.WriteLine("Camera0=") writer.WriteLine("Camera1=%s" % camera) if not submitScene: writer.WriteLine("SceneFile=%s" % sceneFile) if scriptDialog.GetValue("DBRModeBox") != "Disabled": if scriptDialog.GetValue("DBRModeBox") == "VRay DBR": writer.WriteLine("VRayDBRJob=True") elif scriptDialog.GetValue( "DBRModeBox") == "Mental Ray Satellite": writer.WriteLine("MentalRayDBRJob=True") elif scriptDialog.GetValue("DBRModeBox") == "VRay RT DBR": writer.WriteLine("VRayRtDBRJob=True") writer.WriteLine("DBRJobFrame=%s" % scriptDialog.GetValue("FramesBox")) if scriptDialog.GetValue("DBRModeBox") == "Disabled": writer.WriteLine("GPUsPerTask=%s" % scriptDialog.GetValue("GPUsPerTaskBox")) writer.WriteLine("GPUsSelectDevices=%s" % scriptDialog.GetValue("GPUsSelectDevicesBox")) writer.Close() # Setup the command line arguments. arguments = [jobInfoFilename, pluginInfoFilename] if scriptDialog.GetValue("SubmitSceneBox"): arguments.append(sceneFile) if pathConfigFile: arguments.append(pathConfigFile) if preLoadFile: arguments.append(preLoadFile) if postLoadFile: arguments.append(postLoadFile) if preFrameFile: arguments.append(preFrameFile) if postFrameFile: arguments.append(postFrameFile) if len(sceneFiles) == 1: results = ClientUtils.ExecuteCommandAndGetOutput(arguments) scriptDialog.ShowMessageBox(results, "Submission Results") else: # Now submit the job. exitCode = ClientUtils.ExecuteCommand(arguments) if exitCode == 0: successes += 1 else: failures += 1 if len(sceneFiles) > 1: scriptDialog.ShowMessageBox( "Jobs submitted successfully: %d\nJobs not submitted: %d" % (successes, failures), "Submission Results") except: scriptDialog.ShowMessageBox(traceback.format_exc(), "")
def renderArgument(self): renderEngines = { "V-Ray": "0", "V-Ray RT": "1", u"V-Ray RT(OpenCL)": "3", u"V-Ray RT(CUDA)": "5" } sRGBOptions = ["On", "Off"] displayWindow = self.GetBooleanPluginInfoEntryWithDefault( "DisplayVFB", False) autoclose = self.GetBooleanPluginInfoEntryWithDefault( "AutocloseVFB", True) displaySRGB = self.GetPluginInfoEntryWithDefault("DisplaySRGB", "On") # Get the frame information. startFrame = self.GetStartFrame() endFrame = self.GetEndFrame() singleRegionJob = self.IsTileJob() singleRegionFrame = str(self.GetStartFrame()) singleRegionIndex = self.GetCurrentTaskId() separateFilesPerFrame = self.GetBooleanPluginInfoEntryWithDefault( "SeparateFilesPerFrame", False) regionRendering = self.GetBooleanPluginInfoEntryWithDefault( "RegionRendering", False) rtEngine = self.GetPluginInfoEntryWithDefault("VRayEngine", "V-Ray") rtTimeout = self.GetFloatPluginInfoEntryWithDefault("RTTimeout", 0.00) rtNoise = self.GetFloatPluginInfoEntryWithDefault("RTNoise", 0.001) rtSampleLevel = self.GetIntegerPluginInfoEntryWithDefault( "RTSamples", 0) # Can't allow it to be interactive or display the image because that would hang the slave renderarguments = " -scenefile=\"" + self.tempSceneFilename + "\" -interactive=0" if not displayWindow: renderarguments += " -display=0" # Default value is 1 else: if autoclose: renderarguments += " -autoclose=1" # Default value is 0 renderarguments += " -displaySRGB=%s" % ( sRGBOptions.index(displaySRGB) + 1) renderarguments += " -rtEngine=%s" % renderEngines[rtEngine.strip()] if not rtEngine == "V-Ray": renderarguments += " -rtTimeOut=%s -rtNoise=%s -rtSampleLevel=%s" % ( rtTimeout, rtNoise, rtSampleLevel) renderarguments += " -frames=" + str(startFrame) if endFrame > startFrame: renderarguments += "-" + str(endFrame) # Set the output path. outputFile = self.GetPluginInfoEntryWithDefault("OutputFilename", "").strip() if outputFile != "": outputFile = RepositoryUtils.CheckPathMapping(outputFile) outputFile = PathUtils.ToPlatformIndependentPath(outputFile) if regionRendering: outputPath = Path.GetDirectoryName(outputFile) outputFileName = Path.GetFileNameWithoutExtension(outputFile) outputExtension = Path.GetExtension(outputFile) if singleRegionJob: outputFile = os.path.join( outputPath, ("_tile%s_" % singleRegionIndex) + outputFileName + outputExtension) else: currTile = self.GetIntegerPluginInfoEntryWithDefault( "CurrentTile", 1) outputFile = os.path.join(outputPath, ("_tile%d_" % currTile) + outputFileName + outputExtension) renderarguments += " -imgFile=\"" + outputFile + "\"" # Now set the rest of the options. renderarguments += " -numThreads=" + str(self.GetThreadCount()) width = self.GetIntegerPluginInfoEntryWithDefault("Width", 0) if width > 0: renderarguments += " -imgWidth=" + str(width) height = self.GetIntegerPluginInfoEntryWithDefault("Height", 0) if height > 0: renderarguments += " -imgHeight=" + str(height) if regionRendering: regionNumString = "" if singleRegionJob: regionNumString = str(singleRegionIndex) #Coordinates In Pixels will always be true when using the common tilerendering code. if self.GetBooleanPluginInfoEntryWithDefault( "CoordinatesInPixels", False): #With the coordinates already being in pixels we do not need to modify the coordinates. xStart = self.GetIntegerPluginInfoEntryWithDefault( "RegionXStart" + regionNumString, 0) xEnd = self.GetIntegerPluginInfoEntryWithDefault( "RegionXEnd" + regionNumString, 0) yStart = self.GetIntegerPluginInfoEntryWithDefault( "RegionYStart" + regionNumString, 0) yEnd = self.GetIntegerPluginInfoEntryWithDefault( "RegionYEnd" + regionNumString, 0) else: self.LogWarning( "Using deprecated coordinate system. Please submit new jobs to use the new coordinates system." ) xStart = round( self.GetFloatPluginInfoEntryWithDefault( "RegionXStart" + regionNumString, 0) * width) xEnd = round( self.GetFloatPluginInfoEntryWithDefault( "RegionXEnd" + regionNumString, 0) * width) yStart = round( self.GetFloatPluginInfoEntryWithDefault( "RegionYStart" + regionNumString, 0) * height) yEnd = round( self.GetFloatPluginInfoEntryWithDefault( "RegionYEnd" + regionNumString, 0) * height) renderarguments += " -region=%d;%d;%d;%d" % (xStart, yStart, xEnd, yEnd) disableProgressColor = self.GetBooleanConfigEntryWithDefault( "DisableProgressColor", False) if disableProgressColor: renderarguments += " -DisableProgressColor=0" renderarguments += " " + self.GetPluginInfoEntryWithDefault( "CommandLineOptions", "") yetiSearchPaths = [] searchPathIndex = 0 while True: searchPath = self.GetPluginInfoEntryWithDefault( "YetiSearchPath" + str(searchPathIndex), "").replace("\\", "/") if not searchPath: break yetiSearchPaths.append( RepositoryUtils.CheckPathMapping(searchPath)) searchPathIndex += 1 if len(yetiSearchPaths) > 0: oldSearchPath = os.environ.get("PG_IMAGE_PATH") if oldSearchPath: yetiSearchPaths.append(oldSearchPath) yetiSepChar = ":" if SystemUtils.IsRunningOnWindows(): yetiSepChar = ";" self.SetProcessEnvironmentVariable( "PG_IMAGE_PATH", yetiSepChar.join(yetiSearchPaths)) return renderarguments
def PreRenderTasks(self): self.LogInfo("Starting V-Ray Task") # Get the scene file to render. sceneFilename = self.GetPluginInfoEntry("InputFilename") sceneFilename = RepositoryUtils.CheckPathMapping(sceneFilename) sceneFilename = PathUtils.ToPlatformIndependentPath(sceneFilename) # If we're rendering separate files per frame, need to get the vrscene file for the current frame. separateFilesPerFrame = self.GetBooleanPluginInfoEntryWithDefault( "SeparateFilesPerFrame", False) if separateFilesPerFrame: currPadding = FrameUtils.GetFrameStringFromFilename(sceneFilename) paddingSize = len(currPadding) newPadding = StringUtils.ToZeroPaddedString( self.GetStartFrame(), paddingSize, False) sceneFilename = sceneFilename.replace(currPadding, newPadding) # Check if we should be doing path mapping. slaveInfo = RepositoryUtils.GetSlaveInfo(self.GetSlaveName(), True) if self.GetBooleanConfigEntryWithDefault( "EnableVrscenePathMapping", True) or slaveInfo.IsAWSPortalInstance: self.LogInfo("Performing path mapping on vrscene file") tempSceneDirectory = self.CreateTempDirectory( "thread" + str(self.GetThreadNumber())) tempSceneFileName = Path.GetFileName(sceneFilename) self.tempSceneFilename = os.path.join(tempSceneDirectory, tempSceneFileName) mappedFiles = set() filesToMap = [(sceneFilename, os.path.dirname(sceneFilename))] while filesToMap: curFile, originalSceneDirectory = filesToMap.pop() #Include directives normally contain relative paths but just to be safe we must run pathmapping again. curFile = RepositoryUtils.CheckPathMapping(curFile) if not os.path.isabs(curFile): curFile = os.path.join(originalSceneDirectory, curFile) if not os.path.exists(curFile): self.LogInfo("The include file %s does not exist." % curFile) continue if os.path.basename(curFile) in mappedFiles: self.LogInfo( "The include file %s has already been mapped." % curFile) continue self.LogInfo("Starting to map %s" % curFile) mappedFiles.add(os.path.basename(curFile)) tempFileName = os.path.join(tempSceneDirectory, os.path.basename(curFile)) foundFiles = self.map_vrscene_includes_cancelable( curFile, tempFileName) newOriginDirectory = os.path.dirname(curFile) for foundFile in foundFiles: filesToMap.append((foundFile, newOriginDirectory)) map_files_and_replace_slashes(tempFileName, tempFileName) if self.IsCanceled(): self.FailRender( "Received cancel task command from Deadline.") else: self.tempSceneFilename = sceneFilename self.tempSceneFilename = PathUtils.ToPlatformIndependentPath( self.tempSceneFilename)
def PostRenderTasks(self): failures = 0 if self.FailWithoutFinishedMessage: if not self.RenderSuccess: # fail here if Succeed didn't get tripped. self.FailAERender( "The composition was not rendered completely. Found NO \"Finished Composition\" notice. To disable this failure if applicable, ensure 'Fail Without Finished Message' is set to False in AE plugin configuration." ) myRePath = self.getAERenderOnlyFileName() self.CleanupRenderEngineFile(myRePath) # Clean up the temp file if we did path mapping on the aepx project file. if (os.path.splitext(self.TempSceneFilename)[1] ).lower() == ".aepx" and self.GetBooleanConfigEntryWithDefault( "EnableAepxPathMapping", True): os.remove(self.TempSceneFilename) if self.DelayedFailure: self.FailRender( "There was an error but the message could not properly be extracted\n" + self.FailureMessage) else: # Since the output option is only valid when rendering a specific comp, we will only check # the output size in this case. comp = self.GetPluginInfoEntryWithDefault("Comp", "") if comp and not self.MultiMachine: if self.LocalRendering: self.LogInfo("Moving output files and folders from " + self.LocalFilePath + " to " + self.NetworkFilePath) self.VerifyAndMoveDirectory(self.LocalFilePath, self.NetworkFilePath, True, 0) outputDirectories = self.GetJob().JobOutputDirectories outputFilenames = self.GetJob().JobOutputFileNames minSizeInKB = self.GetIntegerPluginInfoEntryWithDefault( "MinFileSize", 0) deleteFilesUnderMinSize = self.GetBooleanPluginInfoEntryWithDefault( "DeleteFilesUnderMinSize", False) for outputDirectory, outputFilename in zip( outputDirectories, outputFilenames): outputFile = os.path.join(outputDirectory, outputFilename) outputFile = RepositoryUtils.CheckPathMapping(outputFile) outputFile = PathUtils.ToPlatformIndependentPath( outputFile) if outputFile and minSizeInKB > 0: if outputFile.find("#") >= 0: frames = range(self.GetStartFrame(), self.GetEndFrame() + 1) for frame in frames: currFile = FrameUtils.ReplacePaddingWithFrameNumber( outputFile, frame) failures += self.CheckFileSize( currFile, minSizeInKB, deleteFilesUnderMinSize) else: failures += self.CheckFileSize( outputFile, minSizeInKB, deleteFilesUnderMinSize) if failures != 0: self.FailRender( "There were 1 or more errors with the output") else: self.SetProgress(100) self.SetStatusMessage("Finished Rendering " + str(self.GetEndFrame() - self.GetStartFrame() + 1) + " frames") else: self.LogInfo( "Skipping output file size check because a specific comp isn't being rendered or Multi-Machine rendering is enabled" )
def PreRenderTasks(self): self.FailureMessage = "" self.Framecount = 0 self.PreviousFrameTime = "" # Reset Slave Status Message between Tasks. self.SetStatusMessage("") # Check if we should be doing path mapping. sceneFilename = RepositoryUtils.CheckPathMapping( self.GetPluginInfoEntryWithDefault("SceneFile", self.GetDataFilename())) if SystemUtils.IsRunningOnMac(): sceneFilename = sceneFilename.replace("\\", "/") else: sceneFilename = sceneFilename.replace("/", "\\") # We can only do path mapping on .aepx files (they're xml files). if (os.path.splitext(sceneFilename)[1] ).lower() == ".aepx" and self.GetBooleanConfigEntryWithDefault( "EnableAepxPathMapping", True): self.LogInfo("Performing path mapping on aepx project file") tempSceneDirectory = self.CreateTempDirectory( "thread" + str(self.GetThreadNumber())) tempSceneFileName = os.path.basename(sceneFilename) self.TempSceneFilename = os.path.join(tempSceneDirectory, tempSceneFileName) if SystemUtils.IsRunningOnMac(): RepositoryUtils.CheckPathMappingInFileAndReplace( sceneFilename, self.TempSceneFilename, ("\\", "platform=\"Win\""), ("/", "platform=\"MacPOSIX\"")) os.chmod(self.TempSceneFilename, os.stat(sceneFilename).st_mode) else: RepositoryUtils.CheckPathMappingInFileAndReplace( sceneFilename, self.TempSceneFilename, ("/", "platform=\"MacPOSIX\"", "\\>"), ("\\", "platform=\"Win\"", "/>")) if SystemUtils.IsRunningOnLinux(): os.chmod(self.TempSceneFilename, os.stat(sceneFilename).st_mode) else: self.TempSceneFilename = sceneFilename self.TempSceneFilename = PathUtils.ToPlatformIndependentPath( self.TempSceneFilename) # Get the path to the text file that forces After Effects to run the English version. if SystemUtils.IsRunningOnMac(): myDocumentsPath = os.path.join( Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Documents/ae_force_english.txt") else: myDocumentsPath = os.path.join( Environment.GetFolderPath(Environment.SpecialFolder.Personal), "ae_force_english.txt") # Check if we want to change After Effects to the English version. If we do, create the file. if self.GetBooleanConfigEntryWithDefault("ForceRenderingEnglish", False): try: self.LogInfo( "Attempting to create \"%s\" to force After Effects to run in English" % myDocumentsPath) open(myDocumentsPath, 'w').close() except: self.LogWarning("Failed to create \"%s\" because %s" % (myDocumentsPath, traceback.format_exc())) else: # If we don't want to force the English version, delete the file. if os.path.isfile(myDocumentsPath): try: self.LogInfo( "Attempting to delete \"%s\" to allow After Effects to run in the user's original language" % myDocumentsPath) os.remove(myDocumentsPath) except: self.LogWarning("Failed to delete \"%s\" because %s" % (myDocumentsPath, traceback.format_exc())) myRePath = self.getAERenderOnlyFileName() # Check if we want to start After Effects in render engine mode. If we do, create the file. And important delete it later. if self.GetBooleanConfigEntryWithDefault("ForceRenderEngine", False): try: self.LogInfo( "Attempting to create \"%s\" to force After Effects to run in Render Engine mode" % myRePath) open(myRePath, 'w').close() except: self.LogWarning("Failed to create \"%s\" because %s" % (myRePath, traceback.format_exc())) else: if self.GetBooleanConfigEntryWithDefault("DeleteRenderEngineFile", False): # If we don't want to force in Render Engine mode, delete the file. if os.path.isfile(myRePath): try: self.LogInfo( "Attempting to delete \"%s\" to allow After Effects to run in the workstation environment" % myDocumentsPath) os.remove(myRePath) except: self.LogWarning("Failed to delete \"%s\" because %s" % (myRePath, traceback.format_exc()))
def RenderArgument(self): version = int(self.GetFloatPluginInfoEntry("Version")) self.MultiMachine = self.GetBooleanPluginInfoEntryWithDefault( "MultiMachineMode", False) if self.MultiMachine: self.MultiMachineStartFrame = self.GetIntegerPluginInfoEntryWithDefault( "MultiMachineStartFrame", -1) self.MultiMachineEndFrame = self.GetIntegerPluginInfoEntryWithDefault( "MultiMachineEndFrame", -1) renderarguments = "-project \"" + self.TempSceneFilename + "\"" # See if we're rendering a specific comp. The -s, -e, and -output options are only valid in this case. comp = self.GetPluginInfoEntryWithDefault("Comp", "") if comp != "": self.HandleProgress = True renderarguments += " -comp \"" + comp + "\"" if self.MultiMachine: self.LogInfo("Multi Machine Mode enabled") else: renderarguments += " -s " + str(self.GetStartFrame()) renderarguments += " -e " + str(self.GetEndFrame()) self.LocalRendering = False outputFile = self.GetPluginInfoEntryWithDefault("Output", "").strip() outputFile = RepositoryUtils.CheckPathMapping(outputFile) outputFile = PathUtils.ToPlatformIndependentPath(outputFile) if outputFile != "": outputDir = os.path.dirname(outputFile) self.NetworkFilePath = outputDir if not self.MultiMachine: self.LocalRendering = self.GetBooleanPluginInfoEntryWithDefault( "LocalRendering", False) if self.LocalRendering: outputDir = self.CreateTempDirectory( "AfterEffectsOutput") self.LocalFilePath = outputDir outputFile = os.path.join(outputDir, os.path.basename(outputFile)) self.LogInfo( "Rendering to local drive, will copy files and folders to final location after render is complete" ) else: self.LogInfo("Rendering to network drive") if SystemUtils.IsRunningOnMac(): outputFile = outputFile.replace("\\", "/") else: outputFile = outputFile.replace("/", "\\") self.ValidateFilepath(self.NetworkFilePath) renderarguments += " -output \"" + outputFile + "\"" else: self.HandleProgress = False # Check if we should use the memory management flag. memoryManagementString = self.GetBooleanPluginInfoEntryWithDefault( "MemoryManagement", False) if memoryManagementString: imageCache = self.GetIntegerPluginInfoEntryWithDefault( "ImageCachePercentage", 0) maxMemory = self.GetIntegerPluginInfoEntryWithDefault( "MaxMemoryPercentage", 0) if imageCache > 0 and maxMemory > 0: renderarguments = renderarguments + " -mem_usage " + str( imageCache) + " " + str(maxMemory) # Check if we should use the multi-process flag (AE 8 and later). multiProcessString = self.GetBooleanPluginInfoEntryWithDefault( "MultiProcess", False) if multiProcessString: renderarguments = renderarguments + " -mp" continueOnMissingFootage = self.GetBooleanPluginInfoEntryWithDefault( "ContinueOnMissingFootage", False) if version >= 9 and continueOnMissingFootage: self.LogInfo("Continuing on missing footage") renderarguments = renderarguments + " -continueOnMissingFootage" if self.GetBooleanPluginInfoEntryWithDefault( "IgnoreMissingEffectReferencesErrors", False): self.LogInfo("Ignoring missing effect reference errors") if self.GetBooleanPluginInfoEntryWithDefault( "IgnoreMissingLayerDependenciesErrors", False): self.LogInfo("Ignoring missing layer dependency errors") if self.GetBooleanPluginInfoEntryWithDefault("FailOnWarnings", False): self.LogInfo("Failing on warning messages") # Ensure we always enforce StdOut/Err/render progress to be generated. if version >= 9: renderarguments += " -v ERRORS_AND_PROGRESS" renderarguments += " -close DO_NOT_SAVE_CHANGES" renderarguments += " -sound OFF" return renderarguments
def _sanity_checks(self): """ Ply2VrmeshSubmissionDialog._sanity_checks() -> success Checks the values of the submitter UI controls and determines if any inputs are invalid. Warnings will be presented to the user with the choice of dismissing them or aborting the submission. Errors will be shown in a message dialog to the user. Returns: success Returns true if no errors were encountered and there were no undismissed warnings. """ # Warn the user if the directory of the input file does not exist scene_file = self.scene_file # VRSCENE-specific sanity checks extension = os.path.splitext(scene_file)[1].lower() if extension == ".vrscene": if not self.GetValue("VrsceneNodeNameBox"): self.ShowMessageBox("No VRSCENE node name specified.", "Error") return if self.GetValue("VrsceneAnimationBox"): if int(self.GetValue("VrsceneStartFrameBox")) > int( self.GetValue("VrsceneEndFrameBox")): self.ShowMessageBox( "Start frame is greater than end frame") return if not os.path.isdir(os.path.dirname(scene_file)): warning = "The directory of the input file %s does not exist. Are you sure you want to continue?" % scene_file if not self._prompt_warning(warning): return False # Warn the user if path is local if PathUtils.IsPathLocal(scene_file): warning = "Input file %s is local. Are you sure you want to continue?" % scene_file if not self._prompt_warning(warning): return False if self.output_specified: output_path = self.output_path output_directory = os.path.dirname(output_path) # If the output file is specified, ensure that the directory exists if not os.path.isdir(output_directory): self._show_error( "The directory of the output file does not exist:\n" + output_directory) return False # Warn the user if the output directory is local elif PathUtils.IsPathLocal(output_path): warning = "The output file " + output_path + " is local, are you sure you want to continue?" if not self._prompt_warning(warning): return False output_ext = os.path.splitext(output_path)[1] # Ensure the output file has an extension if not output_ext: self._show_error("No extension was found in output file name.") return False # Ensure the output file is specified when using "Merge Output Files" elif self.GetValue("MergeBox"): self._show_error( "An output file must be specified to merge files.") return False return True
def SubmitButtonPressed(*args): global scriptDialog global integration_dialog submitScene = bool(scriptDialog.GetValue("SubmitSceneBox")) multiMachine = bool(scriptDialog.GetValue("MultiMachineBox")) # Check if scene file exists sceneFile = scriptDialog.GetValue( "SceneBox" ) if( not File.Exists( sceneFile ) ): scriptDialog.ShowMessageBox("Project file %s does not exist." % sceneFile, "Error" ) return elif(not submitScene and PathUtils.IsPathLocal(sceneFile)): result = scriptDialog.ShowMessageBox("The project file " + sceneFile + " is local, are you sure you want to continue?","Warning", ("Yes","No") ) if( result == "No" ): return concurrentTasks = scriptDialog.GetValue( "ConcurrentTasksBox" ) if concurrentTasks > 1: result = scriptDialog.ShowMessageBox("The concurrent tasks is set to a value greater than 1. This can cause Jobs to hang when rendering, are you sure you want to continue?","Warning", ("Yes","No") ) if( result == "No" ): return outputFile = "" frames = "" jobName = scriptDialog.GetValue( "NameBox" ) # Get the comp comp = scriptDialog.GetValue("CompBox") if comp != "": # Check that the output is valid outputFile = scriptDialog.GetValue( "OutputBox" ).strip() if len(outputFile) > 0: if not Directory.Exists( Path.GetDirectoryName(outputFile) ): scriptDialog.ShowMessageBox( "The directory of the output file does not exist:\n" + Path.GetDirectoryName(outputFile), "Error" ) return elif(PathUtils.IsPathLocal(outputFile)): result = scriptDialog.ShowMessageBox("The output file " + outputFile + " is local, are you sure you want to continue?","Warning", ("Yes","No") ) if( result == "No" ): return extension = Path.GetExtension( outputFile ) if not IsMovieFormat( extension ): if outputFile.find( "[#" ) < 0 and outputFile.find( "#]" ) < 0: directory = Path.GetDirectoryName( outputFile ) filename = Path.GetFileNameWithoutExtension( outputFile ) outputFile = Path.Combine( directory, filename + "[#####]" + extension ) #Since we don't specify ranges for multi-machine rendering, don't check frame range when Multi-Machine Rendering = True if not multiMachine: # Check if a valid frame range has been specified. frames = scriptDialog.GetValue( "FramesBox" ) if( not FrameUtils.FrameRangeValid( frames ) ): scriptDialog.ShowMessageBox( "Frame range %s is not valid" % frames, "Error" ) return else: jobName = jobName + " - Entire Render Queue" if multiMachine: jobName = jobName + " (multi-machine rendering)" # Check if Integration options are valid if not integration_dialog.CheckIntegrationSanity( outputFile ): return # Create job info file. jobInfoFilename = Path.Combine( ClientUtils.GetDeadlineTempPath(), "ae_job_info.job" ) writer = StreamWriter( jobInfoFilename, False, Encoding.Unicode ) writer.WriteLine( "Plugin=AfterEffects" ) writer.WriteLine( "Name=%s" % jobName ) writer.WriteLine( "Comment=%s" % scriptDialog.GetValue( "CommentBox" ) ) writer.WriteLine( "Department=%s" % scriptDialog.GetValue( "DepartmentBox" ) ) writer.WriteLine( "Pool=%s" % scriptDialog.GetValue( "PoolBox" ) ) writer.WriteLine( "SecondaryPool=%s" % scriptDialog.GetValue( "SecondaryPoolBox" ) ) writer.WriteLine( "Group=%s" % scriptDialog.GetValue( "GroupBox" ) ) writer.WriteLine( "Priority=%s" % scriptDialog.GetValue( "PriorityBox" ) ) writer.WriteLine( "TaskTimeoutMinutes=%s" % scriptDialog.GetValue( "TaskTimeoutBox" ) ) writer.WriteLine( "EnableAutoTimeout=%s" % scriptDialog.GetValue( "AutoTimeoutBox" ) ) writer.WriteLine( "ConcurrentTasks=%s" % concurrentTasks ) writer.WriteLine( "LimitConcurrentTasksToNumberOfCpus=%s" % scriptDialog.GetValue( "LimitConcurrentTasksBox" ) ) if( bool(scriptDialog.GetValue( "IsBlacklistBox" )) ): writer.WriteLine( "Blacklist=%s" % scriptDialog.GetValue( "MachineListBox" ) ) else: writer.WriteLine( "Whitelist=%s" % scriptDialog.GetValue( "MachineListBox" ) ) writer.WriteLine( "LimitGroups=%s" % scriptDialog.GetValue( "LimitGroupBox" ) ) writer.WriteLine( "JobDependencies=%s" % scriptDialog.GetValue( "DependencyBox" ) ) writer.WriteLine( "OnJobComplete=%s" % scriptDialog.GetValue( "OnJobCompleteBox" ) ) if( bool(scriptDialog.GetValue( "SubmitSuspendedBox" )) ): writer.WriteLine( "InitialStatus=Suspended" ) if multiMachine: writer.WriteLine( "MachineLimit=0" ) writer.WriteLine( "Frames=1-%s" % scriptDialog.GetValue( "MultiMachineTasksBox" ) ) writer.WriteLine( "ChunkSize=1" ) else: if comp != "": writer.WriteLine( "MachineLimit=%s" % scriptDialog.GetValue( "MachineLimitBox" ) ) writer.WriteLine( "Frames=%s" % frames ) writer.WriteLine( "ChunkSize=%s" % scriptDialog.GetValue( "ChunkSizeBox" ) ) else: writer.WriteLine( "MachineLimit=1" ) writer.WriteLine( "Frames=0" ) writer.WriteLine( "ChunkSize=1" ) if len(outputFile) > 0: writer.WriteLine( "OutputFilename0=%s" % outputFile.replace( "[#####]", "#####" ) ) extraKVPIndex = 0 groupBatch = False if integration_dialog.IntegrationProcessingRequested(): extraKVPIndex = integration_dialog.WriteIntegrationInfo( writer, extraKVPIndex ) groupBatch = groupBatch or integration_dialog.IntegrationGroupBatchRequested() if groupBatch: writer.WriteLine( "BatchName=%s\n" % ( jobName ) ) writer.Close() # Create plugin info file. version = GetVersionNumber() pluginInfoFilename = Path.Combine( ClientUtils.GetDeadlineTempPath(), "ae_plugin_info.job" ) writer = StreamWriter( pluginInfoFilename, False, Encoding.Unicode ) if(not bool(scriptDialog.GetValue("SubmitSceneBox"))): writer.WriteLine("SceneFile=%s" % scriptDialog.GetValue("SceneBox").replace("\\","/").strip()) writer.WriteLine("Comp=%s" % scriptDialog.GetValue("CompBox")) writer.WriteLine("Version=%s" % str(version) ) writer.WriteLine("IgnoreMissingLayerDependenciesErrors=%s" % scriptDialog.GetValue("MissingLayers")) writer.WriteLine("IgnoreMissingEffectReferencesErrors=%s" % scriptDialog.GetValue("MissingEffects")) writer.WriteLine("FailOnWarnings=%s" % scriptDialog.GetValue("FailOnWarnings")) if multiMachine: writer.WriteLine("MultiMachineMode=True") else: writer.WriteLine("LocalRendering=%s" % scriptDialog.GetValue("LocalRendering")) writer.WriteLine("OverrideFailOnExistingAEProcess=%s" % scriptDialog.GetValue("OverrideFailOnExistingAEProcess")) writer.WriteLine("FailOnExistingAEProcess=%s" % scriptDialog.GetValue("OverrideFailOnExistingAEProcess")) writer.WriteLine("MemoryManagement=%s" % scriptDialog.GetValue("MemoryManagement")) writer.WriteLine("ImageCachePercentage=%s" % scriptDialog.GetValue("ImageCachePercentage")) writer.WriteLine("MaxMemoryPercentage=%s" % scriptDialog.GetValue("MaxMemoryPercentage")) writer.WriteLine("MultiProcess=%s" % scriptDialog.GetValue("MultiProcess")) if version > 8: writer.WriteLine("ContinueOnMissingFootage=%s" % scriptDialog.GetValue("MissingFootage")) if len(outputFile) > 0: writer.WriteLine("Output=%s" % outputFile) writer.Close() # Setup the command line arguments. arguments = [ jobInfoFilename, pluginInfoFilename ] if scriptDialog.GetValue( "SubmitSceneBox" ): arguments.append( sceneFile ) # Now submit the job. results = ClientUtils.ExecuteCommandAndGetOutput( arguments ) scriptDialog.ShowMessageBox( results, "Submission Results" )