cmd += ' -s @#@ -e @#@ -b %d' % by else: cmd += ' -an 1 -s @#@ -e @#@ -inc %d' % by if node != '': cmd += ' -cam "%s"' % node if take != '': if scenetype == 'maya_delight': cmd += ' -rp "%s"' % take else: cmd += ' -rl "%s"' % take if images != '': images = images.split(',') if len(images) > 1: images = afcommon.patternFromPaths(images[0], images[1]) else: images = afcommon.patternFromFile(images[0]) if pwd != '': cmd += ' -proj "%s"' % os.path.normpath(pwd) if output != '': cmd += ' -rd "%s"' % os.path.normpath(output) if scenetype == 'maya_mental': cmd += ' -art -v 5' if extrargs != '': cmd += ' ' + extrargs cmd += ' "%s"' % scene
def launch(self, *args, **kwargs): """launch renderer command """ # do nothing if there is no window (called externally) if not self.window: return # warn the user about the ignore settings try: dAO = pm.PyNode('defaultArnoldRenderOptions') ignore_attrs = [ 'ignoreSubdivision', 'ignoreDisplacement', 'ignoreBump', 'ignoreMotionBlur' ] attr_values = [ (attr, dAO.getAttr(attr)) for attr in ignore_attrs if dAO.getAttr(attr) is True ] if any(attr_values): msg_text = '<br>'.join( map( lambda x: '%s: %s' % (x[0], x[1]), attr_values ) ) response = pm.confirmDialog( title='Ignore These Settings?', message='You have ignored:<br><br>%s<br><br><b>Is that ok?</b>' % msg_text, button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return except pm.MayaNodeError: # no Arnold pass # check if rendering with persp camera try: wrong_camera_names = [ 'perspShape', 'topShape', 'sideShape', 'fontShape', 'persp1Shape', 'perspShape1', ] renderable_cameras = [node for node in pm.ls(type='camera') if node.getAttr('renderable')] if any(map(lambda x: x.name() in wrong_camera_names, renderable_cameras)): response = pm.confirmDialog( title='Rendering with Persp?', message='You are rendering with <b>Persp Camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return if len(renderable_cameras) > 1: response = pm.confirmDialog( title='Rendering more than one Camera?', message='You are rendering <b>more than one camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return elif len(renderable_cameras) == 0: pm.confirmDialog( title='No <b>Renderable</b> camera!!!', message='There is no <b>renderable camera<b>!!!', button=['Ok'], defaultButton='Ok', cancelButton='Ok', dismissString='Ok' ) return except pm.MayaNodeError: # no default render globals node pass # get values start_frame = pm.intField('cgru_afanasy__start_frame', q=1, v=1) end_frame = pm.intField('cgru_afanasy__end_frame', q=1, v=1) frames_per_task = \ pm.intField('cgru_afanasy__frames_per_task', q=1, v=1) by_frame = pm.intField('cgru_afanasy__by_frame', q=1, v=1) hosts_mask = pm.textField('cgru_afanasy__hosts_mask', q=1, text=True) hosts_exclude = pm.textField('cgru_afanasy__hosts_exclude', q=1, text=True) separate_layers = \ pm.checkBox('cgru_afanasy__separate_layers', q=1, v=1) pause = pm.checkBox('cgru_afanasy__paused', q=1, v=1) life_time = pm.intField('cgru_afanasy__life_time', q=1, v=1) # check values if start_frame > end_frame: temp = end_frame end_frame = start_frame start_frame = temp frames_per_task = max(1, frames_per_task) by_frame = max(1, by_frame) # store without quota sign hosts_mask = hosts_mask.replace('"', '') hosts_exclude = hosts_exclude.replace('"', '') # store field values pm.optionVar['cgru_afanasy__start_frame_ov'] = start_frame pm.optionVar['cgru_afanasy__end_frame_ov'] = end_frame pm.optionVar['cgru_afanasy__frames_per_task_ov'] = frames_per_task pm.optionVar['cgru_afanasy__by_frame_ov'] = by_frame pm.optionVar['cgru_afanasy__hosts_mask_ov'] = hosts_mask pm.optionVar['cgru_afanasy__hosts_exclude_ov'] = hosts_exclude pm.optionVar['cgru_afanasy__separate_layers_ov'] = separate_layers pm.optionVar['cgru_afanasy__life_time_ov'] = life_time # get paths scene_name = pm.sceneName() datetime = '%s%s' % ( time.strftime('%y%m%d-%H%M%S-'), str(time.time() - int(time.time()))[2:5] ) filename = '%s.%s.mb' % (scene_name, datetime) project_path = pm.workspace(q=1, rootDirectory=1) # get output paths, set the RenderPass token to Beauty, # this will at least guarantee to get something outputs = \ pm.renderSettings( fullPath=1, firstImageName=1, lastImageName=1, leaveUnmatchedTokens=1, customTokenString="RenderPass=Beauty" ) job_name = os.path.basename(scene_name) logger.debug('%ss %se %sr' % (start_frame, end_frame, by_frame)) logger.debug('scene = %s' % scene_name) logger.debug('file = %s' % filename) logger.debug('job_name = %s' % job_name) logger.debug('project_path = %s' % project_path) logger.debug('outputs = %s' % outputs) if pm.checkBox('cgru_afanasy__close', q=1, v=1): pm.deleteUI(self.window) drg = pm.PyNode('defaultRenderGlobals') render_engine = drg.getAttr('currentRenderer') job = af.Job(job_name) stored_log_level = None if render_engine == 'arnold': # set the verbosity level to warning+info aro = pm.PyNode('defaultArnoldRenderOptions') stored_log_level = aro.getAttr('log_verbosity') aro.setAttr('log_verbosity', 1) # set output to console aro.setAttr("log_to_console", 1) elif render_engine == 'redshift': # set the verbosity level to detailed+info redshift = pm.PyNode('redshiftOptions') stored_log_level = redshift.logLevel.get() redshift.logLevel.set(2) # save file pm.saveAs( filename, force=1, type='mayaBinary' ) # rename back to original name pm.renameFile(scene_name) # create the render command mrc = MayaRenderCommandBuilder( name=job_name, file_full_path=filename, render_engine=render_engine, project=project_path, by_frame=by_frame ) # submit renders blocks = [] if separate_layers: # render each layer separately rlm = pm.PyNode('renderLayerManager') layers = [layer for layer in rlm.connections() if layer.renderable.get()] for layer in layers: mrc_layer = copy.copy(mrc) layer_name = layer.name() mrc_layer.name = layer_name mrc_layer.render_layer = layer_name # create a new block for this layer block = af.Block( layer_name, renderer_to_block_type.get(render_engine, 'maya') ) block.setFiles( afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths(outputs[0], outputs[1]) ) ).split(';') ) block.setNumeric( start_frame, end_frame, frames_per_task, by_frame ) block.setCommand(mrc_layer.build_command()) blocks.append(block) else: # create only one block block = af.Block( 'All Layers', renderer_to_block_type.get(render_engine, 'maya') ) block.setFiles( afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths(outputs[0], outputs[1]) ) ).split(';') ) block.setNumeric( start_frame, end_frame, frames_per_task, by_frame ) block.setCommand(mrc.build_command()) blocks.append(block) job.setFolder('input', os.path.dirname(filename)) job.setFolder('output', os.path.dirname(outputs[0])) job.setHostsMask(hosts_mask) job.setHostsMaskExclude(hosts_exclude) if life_time > 0: job.setTimeLife(life_time * 3600) job.setCmdPost('deletefiles "%s"' % os.path.abspath(filename)) if pause: job.offline() # add blocks job.blocks.extend(blocks) status, data = job.send() if not status: pm.PopupError('Something went wrong!') print('data: %s' % data) # restore log level if render_engine == 'arnold': aro = pm.PyNode('defaultArnoldRenderOptions') aro.setAttr('log_verbosity', stored_log_level) # disable set output to console aro.setAttr("log_to_console", 0) elif render_engine == 'redshift': redshift = pm.PyNode('redshiftOptions') redshift.logLevel.set(stored_log_level)
def launch(self, *args, **kwargs): """launch renderer command """ # do nothing if there is no window (called externally) if not self.window: return # warn the user about the ignore settings try: dAO = pm.PyNode('defaultArnoldRenderOptions') ignore_attrs = [ 'ignoreSubdivision', 'ignoreDisplacement', 'ignoreBump', 'ignoreMotionBlur' ] attr_values = [ (attr, dAO.getAttr(attr)) for attr in ignore_attrs if dAO.getAttr(attr) is True ] if any(attr_values): msg_text = '<br>'.join( map( lambda x: '%s: %s' % (x[0], x[1]), attr_values ) ) response = pm.confirmDialog( title='Ignore These Settings?', message='You have ignored:<br><br>%s<br><br><b>Is that ok?</b>' % msg_text, button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return except pm.MayaNodeError: # no Arnold pass # check if rendering with persp camera try: wrong_camera_names = [ 'perspShape', 'topShape', 'sideShape', 'fontShape', 'persp1Shape', 'perspShape1', ] renderable_cameras = [node for node in pm.ls(type='camera') if node.getAttr('renderable')] if any(map(lambda x: x.name() in wrong_camera_names, renderable_cameras)): response = pm.confirmDialog( title='Rendering with Persp?', message='You are rendering with <b>Persp Camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return if len(renderable_cameras) > 1: response = pm.confirmDialog( title='Rendering more than one Camera?', message='You are rendering <b>more than one camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return elif len(renderable_cameras) == 0: pm.confirmDialog( title='No <b>Renderable</b> camera!!!', message='There is no <b>renderable camera<b>!!!', button=['Ok'], defaultButton='Ok', cancelButton='Ok', dismissString='Ok' ) return except pm.MayaNodeError: # no default render globals node pass drg = pm.PyNode('defaultRenderGlobals') render_engine = drg.getAttr('currentRenderer') # RENDERER SPECIFIC CHECKS if render_engine == 'redshift': # if the renderer is RedShift # check if unifiedDisableDivision is 1 which will take too much time # to render dro = pm.PyNode('redshiftOptions') if dro.unifiedDisableDivision.get() == 1: response = pm.confirmDialog( title="Enabled **Don't Automatically Reduce Samples of Other Effects**", message='It is not allowed to render with the following option is enabled:<br>' '<br>' "Don't Automatically Reduce Samples of Other Effects: Enabled<br>" "<br>" "Please DISABLE it!", button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # Check dome light backgrounds domes_to_fix = [] rs_domes = pm.ls(type='RedshiftDomeLight') if rs_domes: for rs_dome in rs_domes: if rs_dome.getAttr('background_enable') == 1 \ or rs_dome.getAttr('backPlateEnabled') == 1: domes_to_fix.append(rs_dome.name()) if domes_to_fix: message = 'Some DomeLights have <b>BackGround Render ' \ 'Enabled</b>:' \ '<br><br>%s<br><br>' \ 'Are you Sure?' % '<br>'.join(domes_to_fix) response = pm.confirmDialog( title='Dome Lights with Background Enabled?', message=message, button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return # abort on license fail dro.abortOnLicenseFail.set(1) elif render_engine == 'arnold': # check if the samples are too high dAO = pm.PyNode('defaultArnoldRenderOptions') aa_samples = dAO.AASamples.get() diff_samples = dAO.GIDiffuseSamples.get() try: glossy_samples = dAO.GIGlossySamples.get() except AttributeError: glossy_samples = dAO.GISpecularSamples.get() if int(pm.about(v=1)) >= 2017: sss_samples = dAO.GISssSamples.get() else: sss_samples = dAO.sssBssrdfSamples.get() total_diff_samples = aa_samples**2 * diff_samples**2 total_glossy_samples = aa_samples**2 * glossy_samples**2 total_sss_samples = aa_samples**2 * sss_samples**2 max_allowed_diff_samples = 225 max_allowed_glossy_samples = 100 max_allowed_sss_samples = 800 if total_diff_samples > max_allowed_diff_samples: pm.confirmDialog( title="Too Much Diffuse Samples!!!", message='You are using too much DIFFUSE SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of Diffuse ' 'Samples!!!' % max_allowed_diff_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return if total_glossy_samples > max_allowed_glossy_samples: pm.confirmDialog( title="Too Much Glossy Samples!!!", message='You are using too much GLOSSY SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of Glossy ' 'Samples!!!' % max_allowed_glossy_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return if total_sss_samples > max_allowed_sss_samples: pm.confirmDialog( title="Too Much SSS Samples!!!", message='You are using too much SSS SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of SSS ' 'Samples!!!' % max_allowed_sss_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # check Light Samples # check point lights with zero radius but more than one samples all_point_lights = pm.ls(type='pointLight') ridiculous_point_lights = [] for point_light in all_point_lights: if point_light.aiRadius.get() < 0.1 and point_light.aiSamples.get() > 1: ridiculous_point_lights.append(point_light) if ridiculous_point_lights: pm.confirmDialog( title="Unnecessary Samples on Point Lights!!!", message='You are using too much SAMPLES (>1)<br>' '<br>' 'on <b>Point lights with zero radius</b><br>' '<br>' 'Please reduce the samples to 1', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # Check area lights with more than 2 samples all_area_lights = pm.ls(type=['areaLight', 'aiAreaLight']) ridiculous_area_lights = [] for area_light in all_area_lights: if area_light.aiSamples.get() > 2: ridiculous_area_lights.append(area_light) if ridiculous_area_lights: pm.confirmDialog( title="Unnecessary Samples on Area Lights!!!", message='You are using too much SAMPLES (>2) on<br>' '<br>' '<b>Area Lights</b><br>' '<br>' 'Please reduce the samples to 2', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # Check directional lights with angle == 0 and samples > 1 all_directional_lights = pm.ls(type='directionalLight') ridiculous_directional_lights = [] dir_sample_attr_name = 'aiSamples' # if pm.about(v=1) == "2014": # dir_sample_attr_name = 'aiSamples' for directional_light in all_directional_lights: if directional_light.aiAngle.get() == 0 and directional_light.attr(dir_sample_attr_name).get() > 1: ridiculous_directional_lights.append(directional_light) if ridiculous_directional_lights: pm.confirmDialog( title="Unnecessary Samples on Directional Lights!!!", message='You are using too much SAMPLES (>1) on <br>' '<br>' '<b>Directional lights with zero angle</b><br>' '<br>' 'Please reduce the samples to 1', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # get values start_frame = pm.intField('cgru_afanasy__start_frame', q=1, v=1) end_frame = pm.intField('cgru_afanasy__end_frame', q=1, v=1) frames_per_task = \ pm.intField('cgru_afanasy__frames_per_task', q=1, v=1) by_frame = pm.intField('cgru_afanasy__by_frame', q=1, v=1) hosts_mask = pm.textField('cgru_afanasy__hosts_mask', q=1, text=True) hosts_exclude = pm.textField('cgru_afanasy__hosts_exclude', q=1, text=True) separate_layers = \ pm.radioButtonGrp('cgru_afanasy__separate_layers', q=1, sl=1) pause = pm.checkBox('cgru_afanasy__paused', q=1, v=1) life_time = pm.intField('cgru_afanasy__life_time', q=1, v=1) annotation = pm.textField('cgru_afanasy__annotation', q=1, text=True) submit_multiple_times = pm.intField('cgru_afanasy__submit_multiple_times', q=1, v=1) errors_avoid_host = pm.intField('cgru_afanasy__errors_avoid_host', q=1, v=1) errors_retries = pm.intField('cgru_afanasy__errors_retries', q=1, v=1) errors_task_same_host = pm.intField('cgru_afanasy__errors_task_same_host', q=1, v=1) errors_forgive_time = pm.intField('cgru_afanasy__errors_forgive_time', q=1, v=1) # check values if start_frame > end_frame: temp = end_frame end_frame = start_frame start_frame = temp frames_per_task = max(1, frames_per_task) by_frame = max(1, by_frame) # store without quota sign hosts_mask = hosts_mask.replace('"', '') hosts_exclude = hosts_exclude.replace('"', '') # store field values pm.optionVar['cgru_afanasy__start_frame_ov'] = start_frame pm.optionVar['cgru_afanasy__end_frame_ov'] = end_frame pm.optionVar['cgru_afanasy__frames_per_task_ov'] = frames_per_task pm.optionVar['cgru_afanasy__by_frame_ov'] = by_frame pm.optionVar['cgru_afanasy__hosts_mask_ov'] = hosts_mask pm.optionVar['cgru_afanasy__hosts_exclude_ov'] = hosts_exclude pm.optionVar['cgru_afanasy__separate_layers_ov'] = separate_layers pm.optionVar['cgru_afanasy__life_time_ov'] = life_time pm.optionVar['cgru_afanasy__annotation_ov'] = annotation pm.optionVar['cgru_afanasy__submit_multiple_times_ov'] = submit_multiple_times pm.optionVar['cgru_afanasy__errors_avoid_host_ov'] = errors_avoid_host pm.optionVar['cgru_afanasy__errors_retries_ov'] = errors_retries pm.optionVar['cgru_afanasy__errors_task_same_host_ov'] = errors_task_same_host pm.optionVar['cgru_afanasy__errors_errors_forgive_time_ov'] = errors_forgive_time # get paths scene_name = pm.sceneName() datetime = '%s%s' % ( time.strftime('%y%m%d-%H%M%S-'), str(time.time() - int(time.time()))[2:5] ) filename = '%s.%s.mb' % (scene_name, datetime) project_path = pm.workspace(q=1, rootDirectory=1) # outputs = \ # pm.renderSettings(fullPath=1, firstImageName=1, lastImageName=1) # get output paths, set the RenderPass token to Beauty, # this will at least guarantee to get something outputs = \ pm.renderSettings( fullPath=1, firstImageName=1, lastImageName=1, leaveUnmatchedTokens=1, customTokenString="RenderPass=Beauty" ) # job_name = os.path.basename(scene_name) job_name = self.generate_job_name() logger.debug('%ss %se %sr' % (start_frame, end_frame, by_frame)) logger.debug('scene = %s' % scene_name) logger.debug('file = %s' % filename) logger.debug('job_name = %s' % job_name) logger.debug('project_path = %s' % project_path) logger.debug('outputs = %s' % outputs) logger.debug('annotation = %s' % annotation) logger.debug('separate_layers = %s' % separate_layers) logger.debug('errors_avoid_host = %s' % errors_avoid_host) logger.debug('errors_retries = %s' % errors_retries) logger.debug('errors_task_same_host = %s' % errors_task_same_host) logger.debug('errors_forgive_time = %s' % errors_forgive_time) if pm.checkBox('cgru_afanasy__close', q=1, v=1): pm.deleteUI(self.window) stored_log_level = None if render_engine == 'arnold': # set the verbosity level to warning+info aro = pm.PyNode('defaultArnoldRenderOptions') stored_log_level = aro.getAttr('log_verbosity') aro.setAttr('log_verbosity', 2) # set output to console aro.setAttr("log_to_console", 1) elif render_engine == 'redshift': # set the verbosity level to detailed+info redshift = pm.PyNode('redshiftOptions') stored_log_level = redshift.logLevel.get() redshift.logLevel.set(2) # save file pm.saveAs( filename, force=1, type='mayaBinary' ) # rename back to original name pm.renameFile(scene_name) # create the render command mrc = MayaRenderCommandBuilder( name=job_name, file_full_path=filename, render_engine=render_engine, project=project_path, by_frame=by_frame ) # submit renders jobs = [] blocks = [] # # separate_layers: # 1 -> None -> submit one job with a single block with all layers # 2 -> Block -> submit one job with multiple blocks # 3 -> Job -> submit multiple jobs with a single block per layer # if separate_layers in [1, 2]: job = af.Job(job_name) jobs.append(job) if separate_layers in [2, 3]: # render each layer separately rlm = pm.PyNode('renderLayerManager') layers = [layer for layer in rlm.connections() if layer.renderable.get()] for layer in layers: mrc_layer = copy.copy(mrc) layer_name = layer.name() mrc_layer.name = layer_name mrc_layer.render_layer = layer_name # create a new block for this layer block = af.Block( layer_name, renderer_to_block_type.get(render_engine, 'maya') ) # Fix the output path for this layer # by replacing the "masterLayer" with the layer name # without rs_ at the beginning layer_outputs = outputs if layer_name != 'defaultRenderLayer': layer_outputs[0] = outputs[0].replace( 'masterLayer', layer_name.replace('rs_', '') ) layer_outputs[1] = outputs[1].replace( 'masterLayer', layer_name.replace('rs_', '') ) outputs_split = afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths( layer_outputs[0], layer_outputs[1] ) ) ).split(';') block.setFiles(outputs_split) block.setNumeric( start_frame, end_frame, frames_per_task, by_frame ) command = mrc_layer.build_command() block.setErrorsAvoidHost(errors_avoid_host) block.setErrorsRetries(errors_retries) block.setErrorsTaskSameHost(errors_task_same_host) block.setErrorsForgiveTime(errors_forgive_time) block.setCommand(command) if separate_layers == 2: blocks.append(block) else: job = af.Job('%s - %s' % (job_name, layer_name)) # add blocks job.blocks = [block] jobs.append(job) else: # create only one block block = af.Block( 'All Layers', renderer_to_block_type.get(render_engine, 'maya') ) block.setFiles( afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths(outputs[0], outputs[1]) ) ).split(';') ) block.setNumeric( start_frame, end_frame, frames_per_task, by_frame ) command = mrc.build_command() block.setCommand(command) blocks.append(block) for job in jobs: job.setAnnotation(annotation) job.setFolder('input', os.path.dirname(filename)) job.setFolder('output', os.path.dirname(outputs[0])) job.setHostsMask(hosts_mask) job.setHostsMaskExclude(hosts_exclude) if life_time > 0: job.setTimeLife(life_time * 3600) else: job.setTimeLife(240 * 3600) job.setCmdPost('deletefiles -s "%s"' % os.path.abspath(filename)) if pause: job.offline() # add blocks if separate_layers in [1, 2]: job.blocks.extend(blocks) for i in range(submit_multiple_times): orig_job_name = job.data['name'] job.setName('%s - %03i' % (orig_job_name, i + 1)) status, data = job.send() # restore job name job.setName(orig_job_name) if not status: pm.PopupError('Something went wrong!') # restore log level if render_engine == 'arnold': aro = pm.PyNode('defaultArnoldRenderOptions') aro.setAttr('log_verbosity', stored_log_level) # disable set output to console aro.setAttr("log_to_console", 0) elif render_engine == 'redshift': redshift = pm.PyNode('redshiftOptions') redshift.logLevel.set(stored_log_level) # disable abort on license fail redshift.abortOnLicenseFail.set(0)
def getBlockParameters(afnode, ropnode, subblock, prefix, frame_range): params = [] if ropnode is not None and ropnode.type().name() == 'ifd' and afnode.parm('sep_enable').eval(): # Case mantra separate render: block_generate = \ BlockParameters(afnode, ropnode, subblock, prefix, frame_range) blockname = block_generate.name block_generate.name += '-G' if not block_generate.valid: block_generate.doPost() return None run_rop = afnode.parm('sep_run_rop').eval() read_rop = afnode.parm('sep_read_rop_params').eval() join_render = afnode.parm('sep_join').eval() tile_render = afnode.parm('sep_tile').eval() tile_divx = afnode.parm('sep_tile_divx').eval() tile_divy = afnode.parm('sep_tile_divy').eval() use_tmp_img_folder = afnode.parm('sep_use_tmp_img_folder').eval() del_rop_files = afnode.parm('sep_del_rop_files').eval() if read_rop or run_rop: if not block_generate.ropnode: hou.ui.displayMessage( 'Can`t find ROP for processing "%s"' % afnode.path() ) if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage( '"%s" is not a ROP node' % block_generate.ropnode.path() ) if not run_rop: join_render = False if join_render: tile_render = False else: if block_generate.ropnode.parm('soho_outputmode').eval() == 0: # Set output mode to produce ifd files: block_generate.ropnode.parm('soho_outputmode').set(1) block_generate.soho_outputmode = 0 block_generate.ropnode.parm('soho_diskfile').set( block_generate.ropnode.parm( 'vm_picture').unexpandedString() + '.ifd' ) if read_rop: parm_images = ropnode.parm('vm_picture') parm_files = ropnode.parm('soho_diskfile') else: parm_images = afnode.parm('sep_images') parm_files = afnode.parm('sep_files') images = afcommon.patternFromPaths( parm_images.evalAsStringAtFrame( block_generate.frame_first), parm_images.evalAsStringAtFrame( block_generate.frame_last)) files = afcommon.patternFromPaths( parm_files.evalAsStringAtFrame( block_generate.frame_first), parm_files.evalAsStringAtFrame( block_generate.frame_last)) if run_rop: if join_render: block_generate.preview = images if not join_render: block_generate.service = 'hbatch' else: block_generate.service = 'hbatch_mantra' block_generate.cmd = block_generate.cmd.replace( 'hrender_af', 'hrender_separate' ) if use_tmp_img_folder: block_generate.cmd += ' --tmpimg' if not join_render: tiles = tile_divx * tile_divy block_render = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_render.name = blockname + '-R' block_render.cmd = 'mantra' block_render.service = block_render.cmd if run_rop: block_render.dependmask = block_generate.name if tile_render or del_rop_files or use_tmp_img_folder: block_render.cmd = 'mantrarender ' if del_rop_files: block_render.delete_files.append(files) if use_tmp_img_folder: block_render.cmd += 't' if tile_render: block_render.numeric = False block_render.cmd += 'c %(tile_divx)d %(tile_divy)d' % vars() block_render.cmd += ' @#@' block_render.frame_pertask = -tiles for frame in range(block_generate.frame_first, block_generate.frame_last + 1, block_generate.frame_inc): arguments = afnode.parm( 'sep_render_arguments').evalAsStringAtFrame(frame) arguments = arguments.replace( '@FILES@', parm_files.evalAsStringAtFrame( frame)) for tile in range(0, tiles): block_render.tasks_names.append( '%d tile %d' % (frame, tile)) block_render.tasks_cmds.append( '%d -R %s' % (tile, arguments)) else: if del_rop_files or use_tmp_img_folder: block_render.cmd += ' -R ' else: block_render.cmd += ' -V a ' block_render.cmd += afcommon.patternFromPaths( afnode.parm('sep_render_arguments').evalAsStringAtFrame(block_generate.frame_first), afnode.parm('sep_render_arguments').evalAsStringAtFrame(block_generate.frame_last) ).replace('@FILES@', files) block_render.preview = images if tile_render: cmd = 'exrjoin %(tile_divx)d %(tile_divy)d %(images)s d' % vars() block_join = BlockParameters( afnode, ropnode, subblock, prefix, frame_range ) block_join.name = blockname + '-J' block_join.service = 'generic' block_join.dependmask = block_render.name block_join.cmd = cmd block_join.cmd_useprefix = False block_join.preview = images if tile_render: params.append(block_join) if not join_render: params.append(block_render) if run_rop: params.append(block_generate) elif len(str(afnode.parm('ds_node').eval())): # Case distribute simulation: ds_node_path = str(afnode.parm('ds_node').eval()) ds_node = hou.node(ds_node_path) if not ds_node: hou.ui.displayMessage('No such control node: "%s"' % ds_node_path) return parms = ['address', 'port', 'slice'] for parm in parms: if not ds_node.parm(parm): hou.ui.displayMessage('Control node "%s" does not have "%s" parameter' % (ds_node_path, parm)) return enable_tracker = not afnode.parm('ds_tracker_manual').eval() if enable_tracker: # Tracker block: par_start = getTrackerParameters(afnode, ropnode, subblock, prefix, frame_range, True) params.append(par_start) # A block for each slice: ds_num_slices = int(afnode.parm('ds_num_slices').eval()) for s in range(0, ds_num_slices): par = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) sim_blocks_mask = par.name + '.*' par.name += '-s%d' % s par.frame_pertask = par.frame_last - par.frame_first + 1 if enable_tracker: par.addDependMask(par_start.name) par.fullrangedepend = True par.auxargs = ' --ds_node "%s"' % ds_node_path par.auxargs += ' --ds_address "%s"' % str(afnode.parm('ds_address').eval()) par.auxargs += ' --ds_port %d' % int(afnode.parm('ds_port').eval()) par.auxargs += ' --ds_slice %d' % s params.append(par) if enable_tracker: # Stop tracker block: par_stop = getTrackerParameters(afnode, ropnode, subblock, prefix, frame_range, False) par_stop.addDependMask(sim_blocks_mask) params.append(par_stop) # Set other block names for start tracker block. # As start tracker block will set other block environment # to specify started tracker and port. par_start.cmd += ' --envblocks "%s|%s"' % (sim_blocks_mask, par_stop.name) # On this block depend mask will be reset on tracker start: par_start.cmd += ' --depblocks "%s"' % sim_blocks_mask else: params.append( BlockParameters(afnode, ropnode, subblock, prefix, frame_range) ) return params
def __init__(self, afnode, ropnode, subblock, prefix, frame_range, for_job_only=False): if VERBOSE == 2: if ropnode: print('Initializing block parameters for "%s" from "%s"' % (ropnode.path(), afnode.path())) else: print('Initializing command block parameters from "%s"' % afnode.path()) # Init parameters: self.valid = False self.afnode = afnode self.ropnode = None self.subblock = subblock self.prefix = prefix self.preview = '' self.name = '' self.type = '' self.cmd = '' self.cmd_useprefix = True self.dependmask = '' self.fullrangedepend = False self.numeric = True self.frame_first, self.frame_last, \ self.frame_inc, self.frame_pertask = frame_range self.tasks_names = [] self.tasks_cmds = [] self.tasks_previews = [] # Parameters to restore ROP changes: self.soho_foreground = None self.soho_outputmode = None # Get parameters: self.job_name = str(afnode.parm('job_name').eval()) self.start_paused = int(afnode.parm('start_paused').eval()) self.platform = str(afnode.parm('platform').eval()) self.subtaskdepend = int(afnode.parm('subtaskdepend').eval()) self.priority = -1 self.max_runtasks = -1 self.maxperhost = -1 self.maxruntime = -1 self.capacity = -1 self.capacity_min = -1 self.capacity_max = -1 self.hosts_mask = '' self.hosts_mask_exclude = '' self.depend_mask = '' self.depend_mask_global = '' if afnode.parm('enable_extended_parameters').eval(): self.priority = int(afnode.parm('priority').eval()) self.max_runtasks = int(afnode.parm('max_runtasks').eval()) self.maxperhost = int(afnode.parm('maxperhost').eval()) self.maxruntime = int(afnode.parm('maxruntime').eval()) self.capacity = int(afnode.parm('capacity').eval()) self.capacity_min = int( afnode.parm('capacity_coefficient1').eval()) self.capacity_max = int( afnode.parm('capacity_coefficient2').eval()) self.hosts_mask = str(afnode.parm('hosts_mask').eval()) self.hosts_mask_exclude = str( afnode.parm('hosts_mask_exclude').eval()) self.depend_mask = str(afnode.parm('depend_mask').eval()) self.depend_mask_global = str( afnode.parm('depend_mask_global').eval()) # Process frame range: opname = afnode.path() if afnode.parm('trange').eval() > 1: self.fullrangedepend = True if ropnode: opname = ropnode.path() trange = ropnode.parm('trange') if trange is not None: if int(trange.eval()) > 0: if ropnode.parm('f1') is not None: self.frame_first = int(ropnode.parm('f1').eval()) if ropnode.parm('f2') is not None: self.frame_last = int(ropnode.parm('f2').eval()) if ropnode.parm('f3') is not None: self.frame_inc = int(ropnode.parm('f3').eval()) if int(trange.eval()) > 1: self.fullrangedepend = True if self.frame_last < self.frame_first: hou.ui.displayMessage('Last frame < first frame for "%s"' % opname) return if self.frame_inc < 1: hou.ui.displayMessage('Frame increment < 1 for "%s"' % opname) return if self.frame_pertask < 1: hou.ui.displayMessage('Frames per task < 1 for "%s"' % opname) return # Process output driver type to construct a command: if ropnode: self.type = 'hbatch' if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % ropnode.path()) return self.ropnode = ropnode self.name = str(ropnode.name()) if self.prefix != '': self.name = '%s_%s' % (self.prefix, self.name) # Block type and preview: roptype = ropnode.type().name() if roptype == 'ifd': if not ropnode.parm('soho_outputmode').eval(): self.type = 'hbatch_mantra' vm_picture = ropnode.parm('vm_picture') if vm_picture is not None: self.preview = \ afcommon.patternFromPaths( vm_picture.evalAsStringAtFrame(self.frame_first), vm_picture.evalAsStringAtFrame(self.frame_last) ) elif roptype == 'rib': self.type = 'hbatch_prman' # Block command: self.cmd = 'hrender_af' if afnode.parm('ignore_inputs').eval(): self.cmd += ' -i' if self.capacity_min != -1 or self.capacity_max != -1: self.cmd += ' --numcpus ' + services.service.str_capacity self.cmd += ' -s @#@ -e @#@ --by %d -t "%s"' % ( self.frame_inc, afnode.parm('take').eval()) self.cmd += ' "%(hipfilename)s"' self.cmd += ' "%s"' % ropnode.path() else: # Custom command driver: if int(afnode.parm('cmd_add').eval()): # Command: cmd = self.afnode.parm('cmd_cmd') self.cmd = afcommon.patternFromPaths( cmd.evalAsStringAtFrame(self.frame_first), cmd.evalAsStringAtFrame(self.frame_last)) # Name: self.name = self.afnode.parm('cmd_name').eval() if self.name is None or self.name == '': self.name = self.cmd.split(' ')[0] # Service: self.type = self.afnode.parm('cmd_service').eval() if self.type is None or self.type == '': self.type = self.cmd.split(' ')[0] # Prefix: self.cmd_useprefix = \ int(self.afnode.parm('cmd_use_afcmdprefix').eval()) elif not for_job_only: hou.ui.displayMessage('Can\'t process "%s"' % afnode.path()) return # Try to set driver foreground mode if ropnode: trange = ropnode.parm('trange') soho_foreground = ropnode.parm('soho_foreground') if trange is not None and int(trange.eval()) == 0: if soho_foreground is not None: if soho_foreground.eval() == 0: try: soho_foreground.set(1) self.soho_foreground = 0 except: # TODO: too broad exception clause hou.ui.displayMessage( 'Set "Block Until Render Complete" on "%s" ' 'node' % ropnode.path()) return self.valid = True
def __init__(self, afnode, ropnode, subblock, prefix, frame_range, for_job_only=False): if VERBOSE == 2: if ropnode: print('Initializing block parameters for "%s" from "%s"' % (ropnode.path(), afnode.path())) else: print('Initializing command block parameters from "%s"' % afnode.path()) # Init parameters: self.valid = False self.afnode = afnode self.ropnode = None self.subblock = subblock self.frame_pertask = 1 self.frame_sequential = 1 self.prefix = prefix self.preview = '' self.name = '' self.service = '' self.parser = '' self.cmd = '' self.cmd_useprefix = True self.dependmask = '' self.fullrangedepend = False self.numeric = True self.frame_first, self.frame_last, self.frame_inc = frame_range self.auxargs = '' self.tasks_names = [] self.tasks_cmds = [] self.tasks_previews = [] # Fill in this array with files to delete in a block post command. # Files should have a common afanasy "@#*@" pattern, # it will be replaced with "*" for shell. self.delete_files = [] # Parameters to restore ROP changes: self.soho_foreground = None self.soho_outputmode = None # Get parameters: self.frame_pertask = int(afnode.parm('frame_pertask').eval()) self.frame_sequential = int(afnode.parm('frame_sequential').eval()) self.job_name = str(afnode.parm('job_name').eval()) self.job_branch = '' self.start_paused = int(afnode.parm('start_paused').eval()) self.platform = str(afnode.parm('platform').eval()) self.subtaskdepend = int(afnode.parm('subtaskdepend').eval()) self.priority = -1 self.max_runtasks = -1 self.maxperhost = -1 self.maxruntime = -1 self.minruntime = -1 self.capacity = -1 self.capacity_min = -1 self.capacity_max = -1 self.hosts_mask = '' self.hosts_mask_exclude = '' self.depend_mask = '' self.depend_mask_global = '' self.min_memory = -1 self.preview_approval = afnode.parm('preview_approval').eval() if afnode.parm('enable_extended_parameters').eval(): self.job_branch = self.afnode.parm('job_branch').eval() self.parser = self.afnode.parm('override_parser').eval() self.priority = int(afnode.parm('priority').eval()) self.max_runtasks = int(afnode.parm('max_runtasks').eval()) self.maxperhost = int(afnode.parm('maxperhost').eval()) self.maxruntime = int(afnode.parm('maxruntime').eval()) self.minruntime = int(afnode.parm('minruntime').eval()) self.min_memory = int(afnode.parm('min_memory').eval()) self.capacity = int(afnode.parm('capacity').eval()) self.capacity_min = int( afnode.parm('capacity_coefficient1').eval()) self.capacity_max = int( afnode.parm('capacity_coefficient2').eval()) self.hosts_mask = str(afnode.parm('hosts_mask').eval()) self.hosts_mask_exclude = str( afnode.parm('hosts_mask_exclude').eval()) self.depend_mask = str(afnode.parm('depend_mask').eval()) self.depend_mask_global = str( afnode.parm('depend_mask_global').eval()) # Process frame range: opname = afnode.path() if afnode.parm('trange').eval() > 1: self.fullrangedepend = True if ropnode: opname = ropnode.path() trange = ropnode.parm('trange') if trange is not None: if int(trange.eval()) > 0: if ropnode.parm('f1') is not None: self.frame_first = int(ropnode.parm('f1').eval()) if ropnode.parm('f2') is not None: self.frame_last = int(ropnode.parm('f2').eval()) if ropnode.parm('f3') is not None: self.frame_inc = int(ropnode.parm('f3').eval()) if int(trange.eval()) > 1: self.fullrangedepend = True if self.frame_last < self.frame_first: hou.ui.displayMessage('Last frame < first frame for "%s"' % opname) return if self.frame_inc < 1: hou.ui.displayMessage('Frame increment < 1 for "%s"' % opname) return if self.frame_pertask < 1: hou.ui.displayMessage('Frames per task < 1 for "%s"' % opname) return # Process output driver type to construct a command: if ropnode: self.service = 'hbatch' if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % ropnode.path()) return self.ropnode = ropnode self.name = str(ropnode.name()) if self.prefix != '': self.name = '%s_%s' % (self.prefix, self.name) # Block type and preview: roptype = ropnode.type().name() if roptype == 'ifd': if ropnode.node(ropnode.parm('camera').eval()) == None: hou.ui.displayMessage("Camera in " + ropnode.name() + " is not valid", severity=hou.severityType.Error) return if not ropnode.parm('soho_outputmode').eval(): self.service = 'hbatch_mantra' vm_picture = ropnode.parm('vm_picture') if vm_picture is not None: self.preview = \ afcommon.patternFromPaths( vm_picture.evalAsStringAtFrame(self.frame_first), vm_picture.evalAsStringAtFrame(self.frame_last) ) elif roptype == 'rib': self.service = 'hbatch_prman' elif roptype == 'arnold': if not ropnode.parm('soho_outputmode').eval(): self.service = 'houdinitoarnold' ar_picture = ropnode.parm('ar_picture') if ar_picture is not None: self.preview = \ afcommon.patternFromPaths( ar_picture.evalAsStringAtFrame(self.frame_first), ar_picture.evalAsStringAtFrame(self.frame_last) ) elif roptype == 'alembic': self.numeric = False taskname = ropnode.name() taskname += ' ' + str(self.frame_first) taskname += '-' + str(self.frame_last) self.tasks_names.append(taskname) self.tasks_cmds.append(self.frame_first) elif roptype == 'Redshift_ROP': self.service = 'hbatch_redshift' rs_picture = ropnode.parm('RS_outputFileNamePrefix') if rs_picture is not None: self.preview = \ afcommon.patternFromPaths( rs_picture.evalAsStringAtFrame(self.frame_first), rs_picture.evalAsStringAtFrame(self.frame_last) ) # Block command: self.cmd = 'hrender_af' if afnode.parm('ignore_inputs').eval(): self.cmd += ' -i' if self.capacity_min != -1 or self.capacity_max != -1: self.cmd += ' --numcpus ' + services.service.str_capacity self.cmd += ' -s @#@ -e @#@ --by %d -t "%s"' % ( self.frame_inc, afnode.parm('take').eval()) # numWedges = computeWedge(ropnode, roptype) # if numWedges: # self.frame_first = 0 # self.frame_last = numWedges - 1 # self.frame_inc = 1 # self.frame_pertask = 1 # self.parser = "mantra" self.cmd += '%(auxargs)s' self.cmd += ' "%(hipfilename)s"' self.cmd += ' "%s"' % ropnode.path() if afnode.parm('enable_extended_parameters').eval(): # Override service: override_service = self.afnode.parm('override_service').eval() if override_service is not None and len(override_service): self.service = override_service else: # Custom command driver: if int(afnode.parm('cmd_mode').eval()): # Command: cmd = self.afnode.parm('cmd_cmd') self.cmd = afcommon.patternFromPaths( cmd.evalAsStringAtFrame(self.frame_first), cmd.evalAsStringAtFrame(self.frame_last)) # Name: self.name = self.afnode.parm('cmd_name').eval() if self.name is None or self.name == '': self.name = self.cmd.split(' ')[0] # Service: self.service = self.afnode.parm('cmd_service').eval() if self.service is None or self.service == '': self.service = self.cmd.split(' ')[0] # Parser: self.parser = self.afnode.parm('cmd_parser').eval() # Prefix: self.cmd_useprefix = \ int(self.afnode.parm('cmd_use_afcmdprefix').eval()) # Delete files on job deletion: if self.afnode.parm('cmd_delete_files').eval(): cmd_files = self.afnode.parm('cmd_files') self.delete_files.append( afcommon.patternFromPaths( cmd_files.evalAsStringAtFrame(self.frame_first), cmd_files.evalAsStringAtFrame(self.frame_last))) elif not for_job_only: hou.ui.displayMessage('Can\'t process "%s"' % afnode.path()) return # Try to set driver foreground mode if ropnode: trange = ropnode.parm('trange') soho_foreground = ropnode.parm('soho_foreground') if trange is not None and int(trange.eval()) == 0: if soho_foreground is not None: if soho_foreground.eval() == 0: try: soho_foreground.set(1) self.soho_foreground = 0 except: # TODO: too broad exception clause hou.ui.displayMessage( 'Set "Block Until Render Complete" on "%s" ' 'node' % ropnode.path()) return # Try to create output folder: if self.preview != '' and afnode.parm('check_output_folder').eval(): folder = os.path.dirname(self.preview) if not os.path.isdir(folder): if hou.ui.displayMessage(folder, buttons=('Create', 'Abort'), default_choice=0, close_choice=1, title='Output Folder Does Not Exist', details=folder) == 0: try: os.makedirs(folder) except Exception as e: hou.ui.displayMessage( folder, buttons=('Abort', ), default_choice=0, close_choice=1, title='Error Creating Output Folder', details=str(e)) return if not os.path.isdir(folder): hou.ui.displayMessage( folder, buttons=('Abort', ), default_choice=0, close_choice=1, title='Can`t Create Output Folder', details=folder) return else: return self.valid = True
cmd += ' -s @#@ -e @#@ -b %d' % by else: cmd += ' -an 1 -s @#@ -e @#@ -inc %d' % by if node != '': cmd += ' -cam "%s"' % node if take != '': if scenetype == 'maya_delight': cmd += ' -rp "%s"' % take else: cmd += ' -rl "%s"' % take if images != '': images = images.split(',') if len(images) > 1: images = afcommon.patternFromPaths(images[0], images[1]) else: images = afcommon.patternFromFile(images[0]) if proj: cmd += ' -proj "%s"' % os.path.normpath(proj) # else: # if pwd != '': # cmd += ' -proj "%s"' % os.path.normpath(pwd) # else: # cmd += ' -proj "%s"' % os.path.normpath(os.path.dirname(scene)) if output != '': cmd += ' -rd "%s"' % os.path.normpath(output) if scenetype == 'maya_mental':
import os import sys import afcommon if len(sys.argv) < 2: print('\nUsage: To check common functions class launch:') print('%s [func] [args...]\n' % os.path.basename(sys.argv[0])) sys.exit(1) if sys.argv[1] == 'pat2': if len(sys.argv) < 4: print('Usage: %s %s str1 str2' % (sys.argv[0], sys.argv[1])) else: print(afcommon.patternFromPaths(sys.argv[2], sys.argv[3])) elif sys.argv[1] == 'fillnum': if len(sys.argv) < 5: print('Usage: %s %s pattern start end' % (sys.argv[0], sys.argv[1])) else: print(afcommon.fillNumbers(sys.argv[2], int(sys.argv[3]), int(sys.argv[4]))) elif sys.argv[1] == 'patc': if len(sys.argv) < 3: print('Usage: %s %s str' % (sys.argv[0], sys.argv[1])) else: print(afcommon.patternFromStdC(sys.argv[2], True)) elif sys.argv[1] == 'patd': if len(sys.argv) < 3: print('Usage: %s %s str' % (sys.argv[0], sys.argv[1])) else: print(afcommon.patternFromDigits(sys.argv[2], True))
def __init__(self, afnode, ropnode, subblock, prefix, frame_range, for_job_only=False): if VERBOSE == 2: if ropnode: print('Initializing block parameters for "%s" from "%s"' % (ropnode.path(), afnode.path())) else: print('Initializing command block parameters from "%s"' % afnode.path()) # Init parameters: self.valid = False self.afnode = afnode self.ropnode = None self.subblock = subblock self.single_task = False self.local_render = False self.frame_pertask = 1 self.frame_sequential = 1 self.prefix = prefix self.preview = '' self.name = '' self.service = '' self.tickets = dict() self.parser = '' self.cmd = '' self.cmd_useprefix = True self.dependmask = '' self.fullrangedepend = False self.numeric = True self.frame_first, self.frame_last, self.frame_inc = frame_range self.auxargs = '' self.tasks_names = [] self.tasks_cmds = [] self.tasks_previews = [] self.file_check_enable = False self.file_check_size_mb_min = -1 self.file_check_size_mb_max = -1 self.file_check_skip_existing = True # Fill in this array with files to delete in a block post command. # Files should have a common afanasy "@#*@" pattern, # it will be replaced with "*" for shell. self.delete_files = [] # Parameters to restore ROP changes: self.soho_foreground = None self.soho_outputmode = None self.pre_submit_script = None self.post_submit_script = None # Get parameters: self.single_task = bool(afnode.parm('single_task').eval()) self.local_render = bool(afnode.parm('local_render').eval()) self.job_name = str(afnode.parm('job_name').eval()) self.job_branch = '' self.start_paused = int(afnode.parm('start_paused').eval()) self.platform = str(afnode.parm('platform').eval()) self.subtaskdepend = int(afnode.parm('subtaskdepend').eval()) self.priority = -1 self.max_runtasks = -1 self.maxperhost = -1 self.maxruntime = -1 self.minruntime = -1 self.progress_timeout = -1 self.capacity = -1 self.capacity_min = -1 self.capacity_max = -1 self.hosts_mask = '' self.hosts_mask_exclude = '' self.depend_mask = '' self.depend_mask_global = '' self.min_memory = -1 self.min_gpu_mem = -1 self.min_cpu_freq = -1 self.min_cpu_cores = -1 self.min_cpu_cores_freq = -1 self.tickets_use = int(afnode.parm('tickets_use').eval()) self.tickets_auto = int(afnode.parm('tickets_auto').eval()) self.ticket_mem = int(afnode.parm('ticket_mem').eval()) self.tickets_aux_use = int(afnode.parm('tickets_aux_use').eval()) self.tickets_aux_data = afnode.parm('tickets_aux_data').eval() self.pools_use = int(afnode.parm('pools_use').eval()) self.pools_data = afnode.parm('pools_data').eval() self.generate_previews = self.afnode.parm('generate_previews').eval() self.life_time = -1 self.preview_approval = afnode.parm('preview_approval').eval() if afnode.parm('enable_extended_parameters').eval(): self.job_branch = self.afnode.parm('job_branch').eval() self.parser = self.afnode.parm('override_parser').eval() self.priority = int(afnode.parm('priority').eval()) self.max_runtasks = int(afnode.parm('max_runtasks').eval()) self.maxperhost = int(afnode.parm('maxperhost').eval()) self.maxruntime = float(afnode.parm('maxruntime').eval()) self.minruntime = int(afnode.parm('minruntime').eval()) self.progress_timeout = float( afnode.parm('progress_timeout').eval()) self.min_memory = int(afnode.parm('min_memory').eval()) self.min_gpu_mem = float(afnode.parm('min_gpu_mem').eval()) self.min_cpu_freq = float(afnode.parm('min_cpu_freq').eval()) self.min_cpu_cores = int(afnode.parm('min_cpu_cores').eval()) self.min_cpu_cores_freq = float( afnode.parm('min_cpu_cores_freq').eval()) self.capacity = int(afnode.parm('capacity').eval()) self.capacity_min = int( afnode.parm('capacity_coefficient1').eval()) self.capacity_max = int( afnode.parm('capacity_coefficient2').eval()) self.hosts_mask = str(afnode.parm('hosts_mask').eval()) self.hosts_mask_exclude = str( afnode.parm('hosts_mask_exclude').eval()) self.depend_mask = str(afnode.parm('depend_mask').eval()) self.depend_mask_global = str( afnode.parm('depend_mask_global').eval()) self.life_time = self.afnode.parm('life_time').eval() if afnode.parm('file_check_enable').eval(): self.file_check_enable = True self.file_check_size_mb_min = int( 1024.0 * 1024.0 * afnode.parm('file_check_size_mb_min').eval()) self.file_check_size_mb_max = int( 1024.0 * 1024.0 * afnode.parm('file_check_size_mb_max').eval()) self.file_check_skip_existing = afnode.parm( 'file_check_skip_existing').eval() if self.local_render: self.hosts_mask = str(socket.gethostname()) # Process frame range: opname = afnode.path() if afnode.parm('trange').eval() > 1: self.fullrangedepend = True if ropnode: opname = ropnode.path() trange = ropnode.parm('trange') if trange is not None: if int(trange.eval()) > 0: if ropnode.parm('f1') is not None: self.frame_first = int(ropnode.parm('f1').eval()) if ropnode.parm('f2') is not None: self.frame_last = int(ropnode.parm('f2').eval()) if ropnode.parm('f3') is not None: self.frame_inc = int(ropnode.parm('f3').eval()) if int(trange.eval()) > 1: self.fullrangedepend = True if self.frame_last < self.frame_first: hou.ui.displayMessage('Last frame < first frame for "%s"' % opname) return if self.frame_inc < 1: hou.ui.displayMessage('Frame increment < 1 for "%s"' % opname) return if self.frame_pertask < 1: hou.ui.displayMessage('Frames per task < 1 for "%s"' % opname) return if self.single_task: self.frame_pertask = self.frame_last - self.frame_first + 1 self.frame_sequential = 1 else: self.frame_pertask = int(afnode.parm('frame_pertask').eval()) self.frame_sequential = int(afnode.parm('frame_sequential').eval()) # Process output driver type to construct a command: if ropnode: self.service = 'hbatch' self.tickets['HYTHON'] = 1 if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % ropnode.path()) return self.ropnode = ropnode self.name = str(ropnode.name()) if self.prefix != '': self.name = '%s_%s' % (self.prefix, self.name) # Block type and preview: roptype = ropnode.type().name() if roptype == 'ifd': if ropnode.node(ropnode.parm('camera').eval()) is None: hou.ui.displayMessage("Camera in %s is not valid" % ropnode.name(), severity=hou.severityType.Error) return if not ropnode.parm('soho_outputmode').eval(): self.service = 'hbatch_mantra' self.tickets['MANTRA'] = 1 vm_picture = ropnode.parm('vm_picture') if vm_picture is not None: self.preview = \ afcommon.patternFromPaths( vm_picture.evalAsStringAtFrame(self.frame_first), vm_picture.evalAsStringAtFrame(self.frame_last) ) # TODO karma hydra delegate. elif roptype == 'rib': self.service = 'hbatch_prman' self.tickets['PRMAN'] = 1 # TODO renderman hydra delegate. elif roptype == 'arnold': if not ropnode.parm('soho_outputmode').eval(): self.service = 'houdinitoarnold' ar_picture = ropnode.parm('ar_picture') if ar_picture is not None: self.preview = \ afcommon.patternFromPaths( ar_picture.evalAsStringAtFrame(self.frame_first), ar_picture.evalAsStringAtFrame(self.frame_last) ) # Solaris. Arnold. elif roptype == 'usdrender_rop' and ropnode.parm( 'renderer').eval() == 'HdArnoldRendererPlugin': self.service = 'houdinitoarnold' ar_picture = ropnode.parm('outputimage') if ar_picture is not None: self.preview = \ afcommon.patternFromPaths( ar_picture.evalAsStringAtFrame(self.frame_first), ar_picture.evalAsStringAtFrame(self.frame_last) ) elif roptype in ['alembic', 'usd_rop']: self.numeric = False taskname = ropnode.name() taskname += ' ' + str(self.frame_first) taskname += '-' + str(self.frame_last) self.tasks_names.append(taskname) self.tasks_cmds.append(self.frame_first) elif roptype == 'Redshift_ROP': self.service = 'hbatch_redshift' self.tickets['REDSHIFT'] = 1 rs_picture = ropnode.parm('RS_outputFileNamePrefix') if rs_picture is not None: self.preview = \ afcommon.patternFromPaths( rs_picture.evalAsStringAtFrame(self.frame_first), rs_picture.evalAsStringAtFrame(self.frame_last) ) # TODO redshift hydra delegate. # For files menu in watcher elif roptype == 'geometry': file_geo = ropnode.parm('sopoutput') if file_geo is not None: self.preview = \ afcommon.patternFromPaths( file_geo.evalAsStringAtFrame(self.frame_first), file_geo.evalAsStringAtFrame(self.frame_last) ) # Block command: self.cmd = 'hrender_af' # If this is a "rez" configured environment supply the same environment to # the render command if "REZ_USED_REQUEST" in os.environ: self.cmd = 'rez-env {} -- {}'.format( os.environ["REZ_USED_REQUEST"], self.cmd) if self.single_task: # On a single task we can see progress as job report self.cmd += ' --report' if afnode.parm('ignore_inputs').eval(): self.cmd += ' -i' if self.capacity_min != -1 or self.capacity_max != -1: self.cmd += ' --numcpus ' + services.service.str_capacity self.cmd += ' -s @#@ -e @#@ --by %d -t "%s"' % ( self.frame_inc, afnode.parm('take').eval()) self.cmd += '%(auxargs)s' self.cmd += ' "%(hipfilename)s"' self.cmd += ' "%s"' % ropnode.path() if afnode.parm('enable_extended_parameters').eval(): # Override service: override_service = self.afnode.parm('override_service').eval() if override_service is not None and len(override_service): self.service = override_service else: # Custom command driver: if int(afnode.parm('cmd_mode').eval()): # Command: cmd = self.afnode.parm('cmd_cmd') self.cmd = afcommon.patternFromPaths( cmd.evalAsStringAtFrame(self.frame_first), cmd.evalAsStringAtFrame(self.frame_last)) # Name: self.name = self.afnode.parm('cmd_name').eval() if self.name is None or self.name == '': self.name = self.cmd.split(' ')[0] if self.prefix != '': self.name = '%s_%s' % (self.prefix, self.name) # Service: self.service = self.afnode.parm('cmd_service').eval() if self.service is None or self.service == '': self.service = self.cmd.split(' ')[0] # Parser: self.parser = self.afnode.parm('cmd_parser').eval() # Prefix: self.cmd_useprefix = \ int(self.afnode.parm('cmd_use_afcmdprefix').eval()) # Delete files on job deletion: if self.afnode.parm('cmd_delete_files').eval(): cmd_files = self.afnode.parm('cmd_files') self.delete_files.append( afcommon.patternFromPaths( cmd_files.evalAsStringAtFrame(self.frame_first), cmd_files.evalAsStringAtFrame(self.frame_last))) elif not for_job_only: hou.ui.displayMessage('Can\'t process "%s"' % afnode.path()) return # Try to set driver foreground mode if ropnode: trange = ropnode.parm('trange') soho_foreground = ropnode.parm('soho_foreground') if trange is not None and int(trange.eval()) == 0: if soho_foreground is not None: if soho_foreground.eval() == 0: try: soho_foreground.set(1) self.soho_foreground = 0 except: # TODO: too broad exception clause hou.ui.displayMessage( 'Set "Block Until Render Complete" on "%s" ' 'node' % ropnode.path()) return # Try to create output folder: if self.preview != '' and afnode.parm('check_output_folder').eval(): folder = os.path.dirname(self.preview) if not os.path.isdir(folder): if hou.ui.displayMessage(folder, buttons=('Create', 'Abort'), default_choice=0, close_choice=1, title='Output Folder Does Not Exist', details=folder) == 0: try: os.makedirs(folder) except Exception as e: hou.ui.displayMessage( folder, buttons=('Abort', ), default_choice=0, close_choice=1, title='Error Creating Output Folder', details=str(e)) return if not os.path.isdir(folder): hou.ui.displayMessage( folder, buttons=('Abort', ), default_choice=0, close_choice=1, title='Can`t Create Output Folder', details=folder) return else: return self.valid = True
def getBlockParameters(afnode, ropnode, subblock, prefix, frame_range): params = [] if ropnode is not None and ropnode.type().name() == 'ifd' and afnode.parm( 'sep_enable').eval(): # Case mantra separate render: run_rop = afnode.parm('sep_run_rop').eval() read_rop = afnode.parm('sep_read_rop_params').eval() join_render = afnode.parm('sep_join').eval() tile_render = afnode.parm('sep_tile').eval() tile_divx = afnode.parm('sep_tile_divx').eval() tile_divy = afnode.parm('sep_tile_divy').eval() tiles_count = tile_divx * tile_divy tiles_stitch_service = afnode.parm('tiles_stitch_service').eval() tiles_stitch_capacity = afnode.parm('tiles_stitch_capacity').eval() del_rop_files = afnode.parm('sep_del_rop_files').eval() if not run_rop: join_render = False block_generate = BlockParameters(afnode, ropnode, join_render == False, prefix, frame_range) blockname = block_generate.name if not block_generate.valid: block_generate.doPost() return None if read_rop or run_rop: if not block_generate.ropnode: hou.ui.displayMessage('Can`t find ROP for processing "%s"' % afnode.path()) if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % block_generate.ropnode.path()) if join_render: block_generate.name += '-Separate' tile_render = False else: block_generate.name += '-GenIFD' # Get some generation specific parameters: capacity = int(afnode.parm('sep_gen_capacity').eval()) hosts_mask = str(afnode.parm('sep_gen_hosts_mask').eval()) hosts_exclude = str( afnode.parm('sep_gen_hosts_mask_exclude').eval()) max_runtasks = int(afnode.parm('sep_gen_max_runtasks').eval()) maxperhost = int(afnode.parm('sep_gen_maxperhost').eval()) min_memory = int(afnode.parm('sep_gen_min_memory').eval()) if capacity > 0: block_generate.capacity = capacity if hosts_mask != '': block_generate.hosts_mask = hosts_mask if hosts_exclude != '': block_generate.hosts_mask_exclude = hosts_exclude if max_runtasks > -1: block_generate.max_runtasks = max_runtasks if maxperhost > -1: block_generate.maxperhost = maxperhost if min_memory > -1: block_generate.min_memory = min_memory if block_generate.ropnode.parm('soho_outputmode').eval() == 0: # Set output mode to produce ifd files: block_generate.ropnode.parm('soho_outputmode').set(1) block_generate.soho_outputmode = 0 # We use unexpandedString() here to keep $F4 as expression. # If we eval() the value, # we will 'bake' the frame number when user submit the job. block_generate.ropnode.parm('soho_diskfile').set( block_generate.ropnode.parm( 'vm_picture').unexpandedString() + '.ifd') if read_rop: parm_images = ropnode.parm('vm_picture') parm_files = ropnode.parm('soho_diskfile') else: parm_images = afnode.parm('sep_images') parm_files = afnode.parm('sep_files') images = afcommon.patternFromPaths( parm_images.evalAsStringAtFrame(block_generate.frame_first), parm_images.evalAsStringAtFrame(block_generate.frame_last)) files = afcommon.patternFromPaths( parm_files.evalAsStringAtFrame(block_generate.frame_first), parm_files.evalAsStringAtFrame(block_generate.frame_last)) if run_rop: if join_render: block_generate.preview = images if not join_render: block_generate.service = 'hbatch' block_generate.tickets = {'HYTHON': 1} else: block_generate.service = 'hbatch_mantra' block_generate.tickets = {'HYTHON': 1, 'MANTRA': 1} block_generate.cmd = block_generate.cmd.replace( 'hrender_af', 'hrender_separate') if not join_render: block_render = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_render.cmd = 'mantra' block_render.service = 'mantra' block_render.tickets = {'MANTRA': 1} if run_rop: block_render.dependmask = block_generate.name if del_rop_files: block_render.delete_files.append(files) if tile_render: block_render.name = blockname + '-TileRender' block_render.numeric = False block_render.cmd += ' -t count=%(tile_divx)dx%(tile_divy)d,index=@#@' % vars( ) block_render.frame_pertask = -tiles_count for frame in range(block_generate.frame_first, block_generate.frame_last + 1, block_generate.frame_inc): arguments = afnode.parm( 'sep_render_arguments').evalAsStringAtFrame(frame) arguments = arguments.replace( '@FILES@', parm_files.evalAsStringAtFrame(frame)) for tile in range(0, tiles_count): block_render.tasks_names.append('frame %d tile %d' % (frame, tile)) block_render.tasks_cmds.append('%d %s' % (tile, arguments)) else: block_render.name = blockname + '-Render' block_render.cmd += ' ' + afcommon.patternFromPaths( afnode.parm('sep_render_arguments').evalAsStringAtFrame( block_generate.frame_first), afnode.parm('sep_render_arguments').evalAsStringAtFrame( block_generate.frame_last)).replace('@FILES@', files) block_render.preview = images if tile_render: cmd = 'itilestitch "%s"' % images tile_suffix = '_tile%02d_' timg = os.path.relpath(images) # Now we should find a dot before frame number, # as matra places tile_suffix there. tpos = timg.find('@') if tpos > 0: # We found Afanasy digits pattern start tpos -= 1 else: # We do not have Afanay numeric pattern. # May be aftist sent just one frame to render. name, ext = os.path.splitext(timg) # Shitf to name w/o extension tpos = len(name) - 1 # Shift frame digits while name[tpos].isdigit() and tpos > 0: tpos -= 1 # Shitf a dot before frame digits if name[tpos] == '.': tpos -= 1 # It will be used as a length to cut, not as index tpos += 1 # Insert tile suffix timg = timg[:tpos] + tile_suffix + timg[tpos:] # List all tiles in the command for i in range(0, tiles_count): cmd += ' "%s"' % (timg % i) block_join = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_join.name = blockname + '-TilesStitch' block_join.service = tiles_stitch_service block_join.capacity = tiles_stitch_capacity block_join.tickets = dict() # block render might be referenced before assignment block_join.dependmask = block_render.name block_join.cmd = cmd block_join.cmd_useprefix = False block_join.preview = images # Disable minimum running time as it can be set on Afanasy ROP. # As tile stich can be much fast block_join.minruntime = 0 params.append(block_join) if not join_render: params.append(block_render) if run_rop: params.append(block_generate) elif len(str(afnode.parm('ds_node').eval())): # Case distribute simulation: ds_node_path = str(afnode.parm('ds_node').eval()) ds_node = hou.node(ds_node_path) if not ds_node: hou.ui.displayMessage('No such control node: "%s"' % ds_node_path) return parms = ['address', 'port', 'slice'] for parm in parms: if not ds_node.parm(parm): hou.ui.displayMessage( 'Control node "%s" does not have "%s" parameter' % (ds_node_path, parm)) return enable_tracker = not afnode.parm('ds_tracker_manual').eval() if enable_tracker: # Tracker block: par_start = getTrackerParameters(afnode, ropnode, subblock, prefix, frame_range, True) params.append(par_start) # A block for each slice: ds_num_slices = int(afnode.parm('ds_num_slices').eval()) for s in range(0, ds_num_slices): par = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) sim_blocks_mask = par.name + '.*' par.name += '-s%d' % s par.frame_pertask = par.frame_last - par.frame_first + 1 if enable_tracker: par.addDependMask(par_start.name) par.fullrangedepend = True par.auxargs = ' --ds_node "%s"' % ds_node_path par.auxargs += ' --ds_address "%s"' % str( afnode.parm('ds_address').eval()) par.auxargs += ' --ds_port %d' % int(afnode.parm('ds_port').eval()) par.auxargs += ' --ds_slice %d' % s params.append(par) if enable_tracker: # Stop tracker block: par_stop = getTrackerParameters(afnode, ropnode, subblock, prefix, frame_range, False) par_stop.addDependMask(sim_blocks_mask) params.append(par_stop) # Set other block names for start tracker block. # As start tracker block will set other block environment # to specify started tracker and port. par_start.cmd += ' --envblocks "%s|%s"' % (sim_blocks_mask, par_stop.name) # On this block depend mask will be reset on tracker start: par_start.cmd += ' --depblocks "%s"' % sim_blocks_mask else: params.append( BlockParameters(afnode, ropnode, subblock, prefix, frame_range)) return params
def launch(self, *args, **kwargs): """launch renderer command """ # do nothing if there is no window (called externally) if not self.window: return # warn the user about the ignore settings try: dAO = pm.PyNode('defaultArnoldRenderOptions') ignore_attrs = [ 'ignoreSubdivision', 'ignoreDisplacement', 'ignoreBump', 'ignoreMotionBlur' ] attr_values = [ (attr, dAO.getAttr(attr)) for attr in ignore_attrs if dAO.getAttr(attr) is True ] if any(attr_values): msg_text = '<br>'.join( map( lambda x: '%s: %s' % (x[0], x[1]), attr_values ) ) response = pm.confirmDialog( title='Ignore These Settings?', message='You have ignored:<br><br>%s<br><br><b>Is that ok?</b>' % msg_text, button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return except pm.MayaNodeError: # no Arnold pass # check if rendering with persp camera try: wrong_camera_names = [ 'perspShape', 'topShape', 'sideShape', 'fontShape', 'persp1Shape', 'perspShape1', ] renderable_cameras = [node for node in pm.ls(type='camera') if node.getAttr('renderable')] if any(map(lambda x: x.name() in wrong_camera_names, renderable_cameras)): response = pm.confirmDialog( title='Rendering with Persp?', message='You are rendering with <b>Persp Camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return if len(renderable_cameras) > 1: response = pm.confirmDialog( title='Rendering more than one Camera?', message='You are rendering <b>more than one camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No' ) if response == 'No': return elif len(renderable_cameras) == 0: pm.confirmDialog( title='No <b>Renderable</b> camera!!!', message='There is no <b>renderable camera<b>!!!', button=['Ok'], defaultButton='Ok', cancelButton='Ok', dismissString='Ok' ) return except pm.MayaNodeError: # no default render globals node pass drg = pm.PyNode('defaultRenderGlobals') render_engine = drg.getAttr('currentRenderer') # RENDERER SPECIFIC CHECKS if render_engine == 'redshift': # if the renderer is RedShift # check if unifiedDisableDivision is 1 which will take too much time # to render dro = pm.PyNode('redshiftOptions') if dro.unifiedDisableDivision.get() == 1: response = pm.confirmDialog( title="Enabled **Don't Automatically Reduce Samples of Other Effects**", message='It is not allowed to render with the following option is enabled:<br>' '<br>' "Don't Automatically Reduce Samples of Other Effects: Enabled<br>" "<br>" "Please DISABLE it!", button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return elif render_engine == 'arnold': # check if the samples are too high dAO = pm.PyNode('defaultArnoldRenderOptions') aa_samples = dAO.AASamples.get() diff_samples = dAO.GIDiffuseSamples.get() glossy_samples = dAO.GIGlossySamples.get() if int(pm.about(v=1)) >= 2017: sss_samples = dAO.GISssSamples.get() else: sss_samples = dAO.sssBssrdfSamples.get() total_diff_samples = aa_samples**2 * diff_samples**2 total_glossy_samples = aa_samples**2 * glossy_samples**2 total_sss_samples = aa_samples**2 * sss_samples**2 max_allowed_diff_samples = 225 max_allowed_glossy_samples = 100 max_allowed_sss_samples = 450 if total_diff_samples > max_allowed_diff_samples: pm.confirmDialog( title="Too Much Diffuse Samples!!!", message='You are using too much DIFFUSE SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of Diffuse ' 'Samples!!!' % max_allowed_diff_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return if total_glossy_samples > max_allowed_glossy_samples: pm.confirmDialog( title="Too Much Glossy Samples!!!", message='You are using too much GLOSSY SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of Glossy ' 'Samples!!!' % max_allowed_glossy_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return if total_sss_samples > max_allowed_sss_samples: pm.confirmDialog( title="Too Much SSS Samples!!!", message='You are using too much SSS SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of SSS ' 'Samples!!!' % max_allowed_sss_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # check Light Samples # check point lights with zero radius but more than one samples all_point_lights = pm.ls(type='pointLight') ridiculous_point_lights = [] for point_light in all_point_lights: if point_light.aiRadius.get() < 0.1 and point_light.aiSamples.get() > 1: ridiculous_point_lights.append(point_light) if ridiculous_point_lights: pm.confirmDialog( title="Unnecessary Samples on Point Lights!!!", message='You are using too much SAMPLES (>1)<br>' '<br>' 'on <b>Point lights with zero radius</b><br>' '<br>' 'Please reduce the samples to 1', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # Check area lights with more than 2 samples all_area_lights = pm.ls(type=['areaLight', 'aiAreaLight']) ridiculous_area_lights = [] for area_light in all_area_lights: if area_light.aiSamples.get() > 2: ridiculous_area_lights.append(area_light) if ridiculous_area_lights: pm.confirmDialog( title="Unnecessary Samples on Area Lights!!!", message='You are using too much SAMPLES (>2) on<br>' '<br>' '<b>Area Lights</b><br>' '<br>' 'Please reduce the samples to 2', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # Check directional lights with angle == 0 and samples > 1 all_directional_lights = pm.ls(type='directionalLight') ridiculous_directional_lights = [] for directional_light in all_directional_lights: if directional_light.aiAngle.get() == 0 and directional_light.aiSample.get() > 1: ridiculous_directional_lights.append(directional_light) if ridiculous_directional_lights: pm.confirmDialog( title="Unnecessary Samples on Directional Lights!!!", message='You are using too much SAMPLES (>1) on <br>' '<br>' '<b>Directional lights with zero angle</b><br>' '<br>' 'Please reduce the samples to 1', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK' ) return # get values start_frame = pm.intField('cgru_afanasy__start_frame', q=1, v=1) end_frame = pm.intField('cgru_afanasy__end_frame', q=1, v=1) frames_per_task = \ pm.intField('cgru_afanasy__frames_per_task', q=1, v=1) by_frame = pm.intField('cgru_afanasy__by_frame', q=1, v=1) hosts_mask = pm.textField('cgru_afanasy__hosts_mask', q=1, text=True) hosts_exclude = pm.textField('cgru_afanasy__hosts_exclude', q=1, text=True) separate_layers = \ pm.checkBox('cgru_afanasy__separate_layers', q=1, v=1) pause = pm.checkBox('cgru_afanasy__paused', q=1, v=1) life_time = pm.intField('cgru_afanasy__life_time', q=1, v=1) # check values if start_frame > end_frame: temp = end_frame end_frame = start_frame start_frame = temp frames_per_task = max(1, frames_per_task) by_frame = max(1, by_frame) # store without quota sign hosts_mask = hosts_mask.replace('"', '') hosts_exclude = hosts_exclude.replace('"', '') # store field values pm.optionVar['cgru_afanasy__start_frame_ov'] = start_frame pm.optionVar['cgru_afanasy__end_frame_ov'] = end_frame pm.optionVar['cgru_afanasy__frames_per_task_ov'] = frames_per_task pm.optionVar['cgru_afanasy__by_frame_ov'] = by_frame pm.optionVar['cgru_afanasy__hosts_mask_ov'] = hosts_mask pm.optionVar['cgru_afanasy__hosts_exclude_ov'] = hosts_exclude pm.optionVar['cgru_afanasy__separate_layers_ov'] = separate_layers pm.optionVar['cgru_afanasy__life_time_ov'] = life_time # get paths scene_name = pm.sceneName() datetime = '%s%s' % ( time.strftime('%y%m%d-%H%M%S-'), str(time.time() - int(time.time()))[2:5] ) filename = '%s.%s.mb' % (scene_name, datetime) project_path = pm.workspace(q=1, rootDirectory=1) outputs = \ pm.renderSettings(fullPath=1, firstImageName=1, lastImageName=1) # job_name = os.path.basename(scene_name) job_name = self.generate_job_name() logger.debug('%ss %se %sr' % (start_frame, end_frame, by_frame)) logger.debug('scene = %s' % scene_name) logger.debug('file = %s' % filename) logger.debug('job_name = %s' % job_name) logger.debug('project_path = %s' % project_path) logger.debug('outputs = %s' % outputs) if pm.checkBox('cgru_afanasy__close', q=1, v=1): pm.deleteUI(self.window) job = af.Job(job_name) stored_log_level = None if render_engine == 'arnold': # set the verbosity level to warning+info aro = pm.PyNode('defaultArnoldRenderOptions') stored_log_level = aro.getAttr('log_verbosity') aro.setAttr('log_verbosity', 1) # set output to console aro.setAttr("log_to_console", 1) elif render_engine == 'redshift': # set the verbosity level to detailed+info redshift = pm.PyNode('redshiftOptions') stored_log_level = redshift.logLevel.get() redshift.logLevel.set(2) # save file pm.saveAs( filename, force=1, type='mayaBinary' ) # rename back to original name pm.renameFile(scene_name) # create the render command mrc = MayaRenderCommandBuilder( name=job_name, file_full_path=filename, render_engine=render_engine, project=project_path, by_frame=by_frame ) # submit renders blocks = [] if separate_layers: # render each layer separately rlm = pm.PyNode('renderLayerManager') layers = [layer for layer in rlm.connections() if layer.renderable.get()] for layer in layers: mrc_layer = copy.copy(mrc) layer_name = layer.name() mrc_layer.name = layer_name mrc_layer.render_layer = layer_name # create a new block for this layer block = af.Block( layer_name, renderer_to_block_type.get(render_engine, 'maya') ) block.setFiles( afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths(outputs[0], outputs[1]) ) ).split(';') ) block.setNumeric( start_frame, end_frame, frames_per_task, by_frame ) block.setCommand(mrc_layer.build_command()) blocks.append(block) else: # create only one block block = af.Block( 'All Layers', renderer_to_block_type.get(render_engine, 'maya') ) block.setFiles( afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths(outputs[0], outputs[1]) ) ).split(';') ) block.setNumeric( start_frame, end_frame, frames_per_task, by_frame ) block.setCommand(mrc.build_command()) blocks.append(block) job.setFolder('input', os.path.dirname(filename)) job.setFolder('output', os.path.dirname(outputs[0])) job.setHostsMask(hosts_mask) job.setHostsMaskExclude(hosts_exclude) if life_time > 0: job.setTimeLife(life_time * 3600) job.setCmdPost('deletefiles "%s"' % os.path.abspath(filename)) if pause: job.offline() # add blocks job.blocks.extend(blocks) status, data = job.send() if not status: pm.PopupError('Something went wrong!') print('data: %s' % data) # restore log level if render_engine == 'arnold': aro = pm.PyNode('defaultArnoldRenderOptions') aro.setAttr('log_verbosity', stored_log_level) # disable set output to console aro.setAttr("log_to_console", 0) elif render_engine == 'redshift': redshift = pm.PyNode('redshiftOptions') redshift.logLevel.set(stored_log_level)
def getBlockParameters(afnode, ropnode, subblock, prefix, frame_range): params = [] if ropnode is not None and ropnode.type().name() == "ifd" and afnode.parm("sep_enable").eval(): # Case mantra separate render: block_generate = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) blockname = block_generate.name block_generate.name += "-G" if not block_generate.valid: return None run_rop = afnode.parm("sep_run_rop").eval() read_rop = afnode.parm("sep_read_rop_params").eval() join_render = afnode.parm("sep_join").eval() tile_render = afnode.parm("sep_tile").eval() tile_divx = afnode.parm("sep_tile_divx").eval() tile_divy = afnode.parm("sep_tile_divy").eval() use_tmp_img_folder = afnode.parm("sep_use_tmp_img_folder").eval() del_rop_files = afnode.parm("sep_del_rop_files").eval() if read_rop or run_rop: if not block_generate.ropnode: hou.ui.displayMessage('Can`t find ROP for processing "%s"' % afnode.path()) if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % block_generate.ropnode.path()) if not run_rop: join_render = False if join_render: tile_render = False else: if block_generate.ropnode.parm("soho_outputmode").eval() == 0: # Set output mode to produce ifd files: block_generate.ropnode.parm("soho_outputmode").set(1) block_generate.soho_outputmode = 0 block_generate.ropnode.parm("soho_diskfile").set( block_generate.ropnode.parm("vm_picture").unexpandedString() + ".ifd" ) if read_rop: images = ropnode.parm("vm_picture") files = ropnode.parm("soho_diskfile") afnode.parm("sep_images").set(images.unexpandedString()) afnode.parm("sep_files").set(files.unexpandedString()) images = afcommon.patternFromPaths( afnode.parm("sep_images").evalAsStringAtFrame(block_generate.frame_first), afnode.parm("sep_images").evalAsStringAtFrame(block_generate.frame_last), ) files = afcommon.patternFromPaths( afnode.parm("sep_files").evalAsStringAtFrame(block_generate.frame_first), afnode.parm("sep_files").evalAsStringAtFrame(block_generate.frame_last), ) if run_rop: if join_render: block_generate.preview = images if not join_render: block_generate.service = "hbatch" else: block_generate.service = "hbatch_mantra" block_generate.cmd = block_generate.cmd.replace("hrender_af", "hrender_separate") if use_tmp_img_folder: block_generate.cmd += " --tmpimg" if not join_render: tiles = tile_divx * tile_divy block_render = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_render.name = blockname + "-R" block_render.cmd = "mantra" block_render.service = block_render.cmd if run_rop: block_render.dependmask = block_generate.name if tile_render or del_rop_files or use_tmp_img_folder: block_render.cmd = "mantrarender " if del_rop_files: block_render.delete_files.append(files) if use_tmp_img_folder: block_render.cmd += "t" if tile_render: block_render.numeric = False block_render.cmd += "c %(tile_divx)d %(tile_divy)d" % vars() block_render.cmd += " @#@" block_render.frame_pertask = -tiles for frame in range(block_generate.frame_first, block_generate.frame_last + 1, block_generate.frame_inc): arguments = afnode.parm("sep_render_arguments").evalAsStringAtFrame(frame) for tile in range(0, tiles): block_render.tasks_names.append("%d tile %d" % (frame, tile)) block_render.tasks_cmds.append("%d -R %s" % (tile, arguments)) else: if del_rop_files or use_tmp_img_folder: block_render.cmd += " -R " else: block_render.cmd += " -V a " block_render.cmd += afcommon.patternFromPaths( afnode.parm("sep_render_arguments").evalAsStringAtFrame(block_generate.frame_first), afnode.parm("sep_render_arguments").evalAsStringAtFrame(block_generate.frame_last), ) block_render.preview = images if tile_render: cmd = "exrjoin %(tile_divx)d %(tile_divy)d %(images)s d" % vars() block_join = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_join.name = blockname + "-J" block_join.service = "generic" block_join.dependmask = block_render.name block_join.cmd = cmd block_join.cmd_useprefix = False block_join.preview = images if read_rop: afnode.parm("sep_images").set("") afnode.parm("sep_files").set("") if tile_render: params.append(block_join) if not join_render: params.append(block_render) if run_rop: params.append(block_generate) elif len(str(afnode.parm("ds_node").eval())): # Case distribute simulation: ds_node_path = str(afnode.parm("ds_node").eval()) ds_node = hou.node(ds_node_path) if not ds_node: hou.ui.displayMessage('No such control node: "%s"' % ds_node_path) return parms = ["address", "port", "slice"] for parm in parms: if not ds_node.parm(parm): hou.ui.displayMessage('Control node "%s" does not have "%s" parameter' % (ds_node_path, parm)) return enable_tracker = not afnode.parm("ds_tracker_manual").eval() if enable_tracker: # Tracker block: par_start = getTrackerParameters(afnode, ropnode, subblock, prefix, frame_range, True) params.append(par_start) # A block for each slice: ds_num_slices = int(afnode.parm("ds_num_slices").eval()) stop_dep_mask = None for s in range(0, ds_num_slices): par = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) sim_blocks_mask = par.name + ".*" par.name += "-s%d" % s par.frame_pertask = par.frame_last - par.frame_first + 1 if enable_tracker: par.addDependMask(par_start.name) par.fullrangedepend = True par.auxargs = ' --ds_node "%s"' % ds_node_path par.auxargs += ' --ds_address "%s"' % str(afnode.parm("ds_address").eval()) par.auxargs += " --ds_port %d" % int(afnode.parm("ds_port").eval()) par.auxargs += " --ds_slice %d" % s params.append(par) if enable_tracker: # Stop tracker block: par_stop = getTrackerParameters(afnode, ropnode, subblock, prefix, frame_range, False) par_stop.addDependMask(sim_blocks_mask) params.append(par_stop) # Set other block names for start tracker block. # As start tracker block will set other block environment # to specify started tracker and port. par_start.cmd += ' --envblocks "%s|%s"' % (sim_blocks_mask, par_stop.name) # On this block depend mask will be reset on tracker start: par_start.cmd += ' --depblocks "%s"' % sim_blocks_mask else: params.append(BlockParameters(afnode, ropnode, subblock, prefix, frame_range)) return params
def __init__(self, afnode, ropnode, subblock, prefix, frame_range, for_job_only=False): if VERBOSE == 2: if ropnode: print('Initializing block parameters for "%s" from "%s"' % (ropnode.path(), afnode.path())) else: print('Initializing command block parameters from "%s"' % afnode.path()) # Init parameters: self.valid = False self.afnode = afnode self.ropnode = None self.subblock = subblock self.frame_pertask = 1 self.frame_sequential = 1 self.prefix = prefix self.preview = "" self.name = "" self.service = "" self.parser = "" self.cmd = "" self.cmd_useprefix = True self.dependmask = "" self.fullrangedepend = False self.numeric = True self.frame_first, self.frame_last, self.frame_inc = frame_range self.auxargs = "" self.tasks_names = [] self.tasks_cmds = [] self.tasks_previews = [] # Fill in this array with files to delete in a block post command. # Files should have a common afanasy "@#*@" pattern, # it will be replaced with "*" for shell. self.delete_files = [] # Parameters to restore ROP changes: self.soho_foreground = None self.soho_outputmode = None # Get parameters: self.frame_pertask = int(afnode.parm("frame_pertask").eval()) self.frame_sequential = int(afnode.parm("frame_sequential").eval()) self.job_name = str(afnode.parm("job_name").eval()) self.start_paused = int(afnode.parm("start_paused").eval()) self.platform = str(afnode.parm("platform").eval()) self.subtaskdepend = int(afnode.parm("subtaskdepend").eval()) self.priority = -1 self.max_runtasks = -1 self.maxperhost = -1 self.maxruntime = -1 self.capacity = -1 self.capacity_min = -1 self.capacity_max = -1 self.hosts_mask = "" self.hosts_mask_exclude = "" self.depend_mask = "" self.depend_mask_global = "" self.min_memory = -1 self.preview_approval = afnode.parm("preview_approval").eval() if afnode.parm("enable_extended_parameters").eval(): self.parser = self.afnode.parm("override_parser").eval() self.priority = int(afnode.parm("priority").eval()) self.max_runtasks = int(afnode.parm("max_runtasks").eval()) self.maxperhost = int(afnode.parm("maxperhost").eval()) self.maxruntime = int(afnode.parm("maxruntime").eval()) self.min_memory = int(afnode.parm("min_memory").eval()) self.capacity = int(afnode.parm("capacity").eval()) self.capacity_min = int(afnode.parm("capacity_coefficient1").eval()) self.capacity_max = int(afnode.parm("capacity_coefficient2").eval()) self.hosts_mask = str(afnode.parm("hosts_mask").eval()) self.hosts_mask_exclude = str(afnode.parm("hosts_mask_exclude").eval()) self.depend_mask = str(afnode.parm("depend_mask").eval()) self.depend_mask_global = str(afnode.parm("depend_mask_global").eval()) # Process frame range: opname = afnode.path() if afnode.parm("trange").eval() > 1: self.fullrangedepend = True if ropnode: opname = ropnode.path() trange = ropnode.parm("trange") if trange is not None: if int(trange.eval()) > 0: if ropnode.parm("f1") is not None: self.frame_first = int(ropnode.parm("f1").eval()) if ropnode.parm("f2") is not None: self.frame_last = int(ropnode.parm("f2").eval()) if ropnode.parm("f3") is not None: self.frame_inc = int(ropnode.parm("f3").eval()) if int(trange.eval()) > 1: self.fullrangedepend = True if self.frame_last < self.frame_first: hou.ui.displayMessage('Last frame < first frame for "%s"' % opname) return if self.frame_inc < 1: hou.ui.displayMessage('Frame increment < 1 for "%s"' % opname) return if self.frame_pertask < 1: hou.ui.displayMessage('Frames per task < 1 for "%s"' % opname) return # Process output driver type to construct a command: if ropnode: self.service = "hbatch" if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % ropnode.path()) return self.ropnode = ropnode self.name = str(ropnode.name()) if self.prefix != "": self.name = "%s_%s" % (self.prefix, self.name) # Block type and preview: roptype = ropnode.type().name() if roptype == "ifd": if not ropnode.parm("soho_outputmode").eval(): self.service = "hbatch_mantra" vm_picture = ropnode.parm("vm_picture") if vm_picture is not None: self.preview = afcommon.patternFromPaths( vm_picture.evalAsStringAtFrame(self.frame_first), vm_picture.evalAsStringAtFrame(self.frame_last), ) elif roptype == "rib": self.service = "hbatch_prman" # Block command: self.cmd = "hrender_af" if afnode.parm("ignore_inputs").eval(): self.cmd += " -i" if self.capacity_min != -1 or self.capacity_max != -1: self.cmd += " --numcpus " + services.service.str_capacity self.cmd += ' -s @#@ -e @#@ --by %d -t "%s"' % (self.frame_inc, afnode.parm("take").eval()) numWedges = computeWedge(ropnode, roptype) if numWedges: self.frame_first = 0 self.frame_last = numWedges - 1 self.frame_inc = 1 self.frame_pertask = 1 self.parser = "mantra" self.cmd += "%(auxargs)s" self.cmd += ' "%(hipfilename)s"' self.cmd += ' "%s"' % ropnode.path() if afnode.parm("enable_extended_parameters").eval(): # Override service: override_service = self.afnode.parm("override_service").eval() if override_service is not None and len(override_service): self.service = override_service else: # Custom command driver: if int(afnode.parm("cmd_mode").eval()): # Command: cmd = self.afnode.parm("cmd_cmd") self.cmd = afcommon.patternFromPaths( cmd.evalAsStringAtFrame(self.frame_first), cmd.evalAsStringAtFrame(self.frame_last) ) # Name: self.name = self.afnode.parm("cmd_name").eval() if self.name is None or self.name == "": self.name = self.cmd.split(" ")[0] # Service: self.service = self.afnode.parm("cmd_service").eval() if self.service is None or self.service == "": self.service = self.cmd.split(" ")[0] # Parser: self.parser = self.afnode.parm("cmd_parser").eval() # Prefix: self.cmd_useprefix = int(self.afnode.parm("cmd_use_afcmdprefix").eval()) # Delete files on job deletion: if self.afnode.parm("cmd_delete_files").eval(): cmd_files = self.afnode.parm("cmd_files") self.delete_files.append( afcommon.patternFromPaths( cmd_files.evalAsStringAtFrame(self.frame_first), cmd_files.evalAsStringAtFrame(self.frame_last), ) ) elif not for_job_only: hou.ui.displayMessage('Can\'t process "%s"' % afnode.path()) return # Try to set driver foreground mode if ropnode: trange = ropnode.parm("trange") soho_foreground = ropnode.parm("soho_foreground") if trange is not None and int(trange.eval()) == 0: if soho_foreground is not None: if soho_foreground.eval() == 0: try: soho_foreground.set(1) self.soho_foreground = 0 except: # TODO: too broad exception clause hou.ui.displayMessage('Set "Block Until Render Complete" on "%s" ' "node" % ropnode.path()) return # Try to create output folder: if self.preview != "" and afnode.parm("check_output_folder").eval(): folder = os.path.dirname(self.preview) if not os.path.isdir(folder): if ( hou.ui.displayMessage( folder, buttons=("Create", "Abort"), default_choice=0, close_choice=1, title="Output Folder Does Not Exist", details=folder, ) == 0 ): try: os.makedirs(folder) except Exception as e: hou.ui.displayMessage( folder, buttons=("Abort",), default_choice=0, close_choice=1, title="Error Creating Output Folder", details=str(e), ) return if not os.path.isdir(folder): hou.ui.displayMessage( folder, buttons=("Abort",), default_choice=0, close_choice=1, title="Can`t Create Output Folder", details=folder, ) return else: return self.valid = True
import os import sys import afcommon if len(sys.argv) < 2: print('\nUsage: To check common functions class launch:') print('%s [func] [args...]\n' % os.path.basename(sys.argv[0])) sys.exit(1) if sys.argv[1] == 'pat2': if len(sys.argv) < 4: print('Usage: %s %s str1 str2' % (sys.argv[0], sys.argv[1])) else: print(afcommon.patternFromPaths(sys.argv[2], sys.argv[3])) elif sys.argv[1] == 'fillnum': if len(sys.argv) < 5: print('Usage: %s %s pattern start end' % (sys.argv[0], sys.argv[1])) else: print( afcommon.fillNumbers(sys.argv[2], int(sys.argv[3]), int(sys.argv[4]))) elif sys.argv[1] == 'patc': if len(sys.argv) < 3: print('Usage: %s %s str' % (sys.argv[0], sys.argv[1])) else: print(afcommon.patternFromStdC(sys.argv[2], True)) elif sys.argv[1] == 'patd': if len(sys.argv) < 3: print('Usage: %s %s str' % (sys.argv[0], sys.argv[1]))
def __init__(self, afnode, ropnode, subblock, prefix, frame_range, for_job_only=False): if VERBOSE == 2: if ropnode: print('Initializing block parameters for "%s" from "%s"' % (ropnode.path(), afnode.path())) else: print('Initializing command block parameters from "%s"' % afnode.path()) # Init parameters: self.valid = False self.afnode = afnode self.ropnode = None self.subblock = subblock self.frame_pertask = 1 self.frame_sequential = 1 self.prefix = prefix self.preview = '' self.name = '' self.type = '' self.parser = '' self.cmd = '' self.cmd_useprefix = True self.dependmask = '' self.fullrangedepend = False self.numeric = True self.frame_first, self.frame_last, self.frame_inc = frame_range self.tasks_names = [] self.tasks_cmds = [] self.tasks_previews = [] # Parameters to restore ROP changes: self.soho_foreground = None self.soho_outputmode = None # ############################################################################ # Dict of parameters to restore ROP changes: added by DavidPower self.param_restoreList = {} # ############################################################################ # Get parameters: self.frame_pertask = int(afnode.parm('frame_pertask').eval()) self.frame_sequential = int(afnode.parm('frame_sequential').eval()) self.job_name = str(afnode.parm('job_name').eval()) self.start_paused = int(afnode.parm('start_paused').eval()) self.platform = str(afnode.parm('platform').eval()) self.subtaskdepend = int(afnode.parm('subtaskdepend').eval()) self.parser = self.afnode.parm('override_parser').eval() self.priority = -1 self.max_runtasks = -1 self.maxperhost = -1 self.maxruntime = -1 self.capacity = -1 self.capacity_min = -1 self.capacity_max = -1 self.hosts_mask = '' self.hosts_mask_exclude = '' self.depend_mask = '' self.depend_mask_global = '' if afnode.parm('enable_extended_parameters').eval(): self.priority = int(afnode.parm('priority').eval()) self.max_runtasks = int(afnode.parm('max_runtasks').eval()) self.maxperhost = int(afnode.parm('maxperhost').eval()) self.maxruntime = int(afnode.parm('maxruntime').eval()) self.capacity = int(afnode.parm('capacity').eval()) self.capacity_min = int( afnode.parm('capacity_coefficient1').eval()) self.capacity_max = int( afnode.parm('capacity_coefficient2').eval()) self.hosts_mask = str(afnode.parm('hosts_mask').eval()) self.hosts_mask_exclude = str( afnode.parm('hosts_mask_exclude').eval()) self.depend_mask = str(afnode.parm('depend_mask').eval()) self.depend_mask_global = str( afnode.parm('depend_mask_global').eval()) # Process frame range: opname = afnode.path() if afnode.parm('trange').eval() > 1: self.fullrangedepend = True if ropnode: opname = ropnode.path() trange = ropnode.parm('trange') if trange is not None: if int(trange.eval()) > 0: if ropnode.parm('f1') is not None: self.frame_first = int(ropnode.parm('f1').eval()) if ropnode.parm('f2') is not None: self.frame_last = int(ropnode.parm('f2').eval()) if ropnode.parm('f3') is not None: self.frame_inc = int(ropnode.parm('f3').eval()) if int(trange.eval()) > 1: self.fullrangedepend = True if self.frame_last < self.frame_first: hou.ui.displayMessage('Last frame < first frame for "%s"' % opname) return if self.frame_inc < 1: hou.ui.displayMessage('Frame increment < 1 for "%s"' % opname) return if self.frame_pertask < 1: hou.ui.displayMessage('Frames per task < 1 for "%s"' % opname) return # Process output driver type to construct a command: if ropnode: self.type = 'hbatch' if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage( '"%s" is not a ROP node' % ropnode.path() ) return self.ropnode = ropnode self.name = str(ropnode.name()) if self.prefix != '': self.name = '%s_%s' % (self.prefix, self.name) # Block type and preview: roptype = ropnode.type().name() if roptype == 'ifd': if not ropnode.parm('soho_outputmode').eval(): self.type = 'hbatch_mantra' vm_picture = ropnode.parm('vm_picture') if vm_picture is not None: self.preview = \ afcommon.patternFromPaths( vm_picture.evalAsStringAtFrame(self.frame_first), vm_picture.evalAsStringAtFrame(self.frame_last) ) elif roptype == 'rib': self.type = 'hbatch_prman' # Block command: self.cmd = 'hrender_af' if afnode.parm('ignore_inputs').eval(): self.cmd += ' -i' if self.capacity_min != -1 or self.capacity_max != -1: self.cmd += ' --numcpus ' + services.service.str_capacity self.cmd += ' -s @#@ -e @#@ --by %d -t "%s"' % ( self.frame_inc, afnode.parm('take').eval() ) self.cmd += ' "%(hipfilename)s"' self.cmd += ' "%s"' % ropnode.path() # Override service: override_service = self.afnode.parm('override_service').eval() if override_service is not None and len(override_service): self.type = override_service else: # Custom command driver: if int(afnode.parm('cmd_mode').eval()): # Command: cmd = self.afnode.parm('cmd_cmd') self.cmd = afcommon.patternFromPaths( cmd.evalAsStringAtFrame(self.frame_first), cmd.evalAsStringAtFrame(self.frame_last) ) # Name: self.name = self.afnode.parm('cmd_name').eval() if self.name is None or self.name == '': self.name = self.cmd.split(' ')[0] # Service: self.type = self.afnode.parm('cmd_service').eval() if self.type is None or self.type == '': self.type = self.cmd.split(' ')[0] # Parser: self.parser = self.afnode.parm('cmd_parser').eval() # Prefix: self.cmd_useprefix = \ int(self.afnode.parm('cmd_use_afcmdprefix').eval()) elif not for_job_only: hou.ui.displayMessage('Can\'t process "%s"' % afnode.path()) return # Try to set driver foreground mode if ropnode: trange = ropnode.parm('trange') soho_foreground = ropnode.parm('soho_foreground') if trange is not None and int(trange.eval()) == 0: # ############################################################################ # fixed [Render Current Frame] error # added by DavidPower # ############################################################################ self.frame_first = int(hou.frame()) self.frame_last = int(hou.frame()) # ############################################################################ if soho_foreground is not None: if soho_foreground.eval() == 0: try: soho_foreground.set(1) self.soho_foreground = 0 except: # TODO: too broad exception clause hou.ui.displayMessage( 'Set "Block Until Render Complete" on "%s" ' 'node' % ropnode.path() ) return # Try to create output folder: if self.preview != '' and afnode.parm('check_output_folder').eval(): folder = os.path.dirname( self.preview) if not os.path.isdir( folder): if hou.ui.displayMessage( folder, buttons=('Create','Abort'),default_choice=0,close_choice=1, title='Output Folder Does Not Exist',details=folder) == 0: try: os.makedirs(folder) except Exception as e: hou.ui.displayMessage( folder, buttons=('Abort',),default_choice=0,close_choice=1, title='Error Creating Output Folder',details=str(e)) return if not os.path.isdir( folder): hou.ui.displayMessage( folder, buttons=('Abort',),default_choice=0,close_choice=1, title='Can`t Create Output Folder',details=folder) return else: return self.valid = True
def launch(self, *args, **kwargs): """launch renderer command """ # do nothing if there is no window (called externally) if not self.window: return # warn the user about the ignore settings try: dAO = pm.PyNode('defaultArnoldRenderOptions') ignore_attrs = [ 'ignoreSubdivision', 'ignoreDisplacement', 'ignoreBump', 'ignoreMotionBlur' ] attr_values = [(attr, dAO.getAttr(attr)) for attr in ignore_attrs if dAO.getAttr(attr) is True] if any(attr_values): msg_text = '<br>'.join( map(lambda x: '%s: %s' % (x[0], x[1]), attr_values)) response = pm.confirmDialog( title='Ignore These Settings?', message= 'You have ignored:<br><br>%s<br><br><b>Is that ok?</b>' % msg_text, button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if response == 'No': return except pm.MayaNodeError: # no Arnold pass # check if rendering with persp camera try: wrong_camera_names = [ 'perspShape', 'topShape', 'sideShape', 'fontShape', 'persp1Shape', 'perspShape1', ] renderable_cameras = [ node for node in pm.ls(type='camera') if node.getAttr('renderable') ] if any( map(lambda x: x.name() in wrong_camera_names, renderable_cameras)): response = pm.confirmDialog( title='Rendering with Persp?', message= 'You are rendering with <b>Persp Camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if response == 'No': return if len(renderable_cameras) > 1: response = pm.confirmDialog( title='Rendering more than one Camera?', message= 'You are rendering <b>more than one camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if response == 'No': return elif len(renderable_cameras) == 0: pm.confirmDialog( title='No <b>Renderable</b> camera!!!', message='There is no <b>renderable camera<b>!!!', button=['Ok'], defaultButton='Ok', cancelButton='Ok', dismissString='Ok') return except pm.MayaNodeError: # no default render globals node pass # get values start_frame = pm.intField('cgru_afanasy__start_frame', q=1, v=1) end_frame = pm.intField('cgru_afanasy__end_frame', q=1, v=1) frames_per_task = \ pm.intField('cgru_afanasy__frames_per_task', q=1, v=1) by_frame = pm.intField('cgru_afanasy__by_frame', q=1, v=1) hosts_mask = pm.textField('cgru_afanasy__hosts_mask', q=1, text=True) hosts_exclude = pm.textField('cgru_afanasy__hosts_exclude', q=1, text=True) separate_layers = \ pm.checkBox('cgru_afanasy__separate_layers', q=1, v=1) pause = pm.checkBox('cgru_afanasy__paused', q=1, v=1) life_time = pm.intField('cgru_afanasy__life_time', q=1, v=1) # check values if start_frame > end_frame: temp = end_frame end_frame = start_frame start_frame = temp frames_per_task = max(1, frames_per_task) by_frame = max(1, by_frame) # store without quota sign hosts_mask = hosts_mask.replace('"', '') hosts_exclude = hosts_exclude.replace('"', '') # store field values pm.optionVar['cgru_afanasy__start_frame_ov'] = start_frame pm.optionVar['cgru_afanasy__end_frame_ov'] = end_frame pm.optionVar['cgru_afanasy__frames_per_task_ov'] = frames_per_task pm.optionVar['cgru_afanasy__by_frame_ov'] = by_frame pm.optionVar['cgru_afanasy__hosts_mask_ov'] = hosts_mask pm.optionVar['cgru_afanasy__hosts_exclude_ov'] = hosts_exclude pm.optionVar['cgru_afanasy__separate_layers_ov'] = separate_layers pm.optionVar['cgru_afanasy__life_time_ov'] = life_time # get paths scene_name = pm.sceneName() datetime = '%s%s' % (time.strftime('%y%m%d-%H%M%S-'), str(time.time() - int(time.time()))[2:5]) filename = '%s.%s.mb' % (scene_name, datetime) project_path = pm.workspace(q=1, rootDirectory=1) # get output paths, set the RenderPass token to Beauty, # this will at least guarantee to get something outputs = \ pm.renderSettings( fullPath=1, firstImageName=1, lastImageName=1, leaveUnmatchedTokens=1, customTokenString="RenderPass=Beauty" ) job_name = os.path.basename(scene_name) logger.debug('%ss %se %sr' % (start_frame, end_frame, by_frame)) logger.debug('scene = %s' % scene_name) logger.debug('file = %s' % filename) logger.debug('job_name = %s' % job_name) logger.debug('project_path = %s' % project_path) logger.debug('outputs = %s' % outputs) if pm.checkBox('cgru_afanasy__close', q=1, v=1): pm.deleteUI(self.window) drg = pm.PyNode('defaultRenderGlobals') render_engine = drg.getAttr('currentRenderer') job = af.Job(job_name) stored_log_level = None if render_engine == 'arnold': # set the verbosity level to warning+info aro = pm.PyNode('defaultArnoldRenderOptions') stored_log_level = aro.getAttr('log_verbosity') aro.setAttr('log_verbosity', 1) # set output to console aro.setAttr("log_to_console", 1) elif render_engine == 'redshift': # set the verbosity level to detailed+info redshift = pm.PyNode('redshiftOptions') stored_log_level = redshift.logLevel.get() redshift.logLevel.set(2) # save file pm.saveAs(filename, force=1, type='mayaBinary') # rename back to original name pm.renameFile(scene_name) # create the render command mrc = MayaRenderCommandBuilder(name=job_name, file_full_path=filename, render_engine=render_engine, project=project_path, by_frame=by_frame) # submit renders blocks = [] if separate_layers: # render each layer separately rlm = pm.PyNode('renderLayerManager') layers = [ layer for layer in rlm.connections() if layer.renderable.get() ] for layer in layers: mrc_layer = copy.copy(mrc) layer_name = layer.name() mrc_layer.name = layer_name mrc_layer.render_layer = layer_name # create a new block for this layer block = af.Block( layer_name, renderer_to_block_type.get(render_engine, 'maya')) block.setFiles( afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths(outputs[0], outputs[1]))).split(';')) block.setNumeric(start_frame, end_frame, frames_per_task, by_frame) block.setCommand(mrc_layer.build_command()) blocks.append(block) else: # create only one block block = af.Block('All Layers', renderer_to_block_type.get(render_engine, 'maya')) block.setFiles( afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths(outputs[0], outputs[1]))).split(';')) block.setNumeric(start_frame, end_frame, frames_per_task, by_frame) block.setCommand(mrc.build_command()) blocks.append(block) job.setFolder('input', os.path.dirname(filename)) job.setFolder('output', os.path.dirname(outputs[0])) job.setHostsMask(hosts_mask) job.setHostsMaskExclude(hosts_exclude) if life_time > 0: job.setTimeLife(life_time * 3600) job.setCmdPost('deletefiles "%s"' % os.path.abspath(filename)) if pause: job.offline() # add blocks job.blocks.extend(blocks) status, data = job.send() if not status: pm.PopupError('Something went wrong!') print('data: %s' % data) # restore log level if render_engine == 'arnold': aro = pm.PyNode('defaultArnoldRenderOptions') aro.setAttr('log_verbosity', stored_log_level) # disable set output to console aro.setAttr("log_to_console", 0) elif render_engine == 'redshift': redshift = pm.PyNode('redshiftOptions') redshift.logLevel.set(stored_log_level)
def __init__( self, afnode, ropnode, subblock, prefix, frame_range, for_job_only = False): if VERBOSE == 2: if ropnode: print 'Initializing block parameters for "%s" from "%s"' % (ropnode.path(), afnode.path()) else: print 'Initializing command block parameters from "%s"' % (afnode.path()) # Init parameters: self.valid = False self.afnode = afnode self.ropnode = None self.subblock = subblock self.prefix = prefix self.preview = '' self.name = '' self.type = '' self.cmd = '' self.cmd_useprefix = True self.dependmask = '' self.fullrangedepend = False self.numeric = True self.frame_first, self.frame_last, self.frame_inc, self.frame_pertask = frame_range self.tasks_names = [] self.tasks_cmds = [] self.tasks_previews = [] # Parameters to restore ROP changes: self.soho_foreground = None self.soho_outputmode = None # Get parameters: self.job_name = str( afnode.parm('job_name').eval()) self.start_paused = int( afnode.parm('start_paused').eval()) self.platform = str( afnode.parm('platform').eval()) self.subtaskdepend = int( afnode.parm('subtaskdepend').eval()) self.priority = -1 self.max_runtasks = -1 self.capacity = -1 self.capacity_min = -1 self.capacity_max = -1 self.hosts_mask = '' self.hosts_mask_exclude = '' self.depend_mask = '' self.depend_mask_global = '' if afnode.parm('enable_extended_parameters').eval(): self.priority = int( afnode.parm('priority').eval()) self.max_runtasks = int( afnode.parm('max_runtasks').eval()) self.capacity = int( afnode.parm('capacity').eval()) self.capacity_min = int( afnode.parm('capacity_coefficient1').eval()) self.capacity_max = int( afnode.parm('capacity_coefficient2').eval()) self.hosts_mask = str( afnode.parm('hosts_mask').eval()) self.hosts_mask_exclude = str( afnode.parm('hosts_mask_exclude').eval()) self.depend_mask = str( afnode.parm('depend_mask').eval()) self.depend_mask_global = str( afnode.parm('depend_mask_global').eval()) # Process frame range: opname = afnode.path() if afnode.parm('trange').eval() > 1: self.fullrangedepend = True if ropnode: opname = ropnode.path() trange = ropnode.parm('trange') if trange is not None: if int(trange.eval()) > 0: if ropnode.parm('f1') is not None: self.frame_first = int( ropnode.parm('f1').eval()) if ropnode.parm('f2') is not None: self.frame_last = int( ropnode.parm('f2').eval()) if ropnode.parm('f3') is not None: self.frame_inc = int( ropnode.parm('f3').eval()) if int(trange.eval()) > 1: self.fullrangedepend = True if self.frame_last < self.frame_first: hou.ui.displayMessage('Last frame < first frame for "%s"' % opname) return if self.frame_inc < 1: hou.ui.displayMessage('Frame increment < 1 for "%s"' % opname) return if self.frame_pertask < 1: hou.ui.displayMessage('Frames per task < 1 for "%s"' % opname) return # Process output driver type to construct a command: if ropnode: self.type = 'hbatch' if not isinstance( ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % ropnode.path()) return self.ropnode = ropnode self.name = str( ropnode.name()) if self.prefix != '': self.name = self.prefix + '_' + self.name # Block type and preview: roptype = ropnode.type().name() if roptype == 'ifd': if not ropnode.parm('soho_outputmode').eval(): self.type = 'hbatch_mantra' vm_picture = ropnode.parm('vm_picture') if vm_picture != None: self.preview = afcommon.patternFromPaths( vm_picture.evalAsStringAtFrame( self.frame_first), vm_picture.evalAsStringAtFrame( self.frame_last)) elif roptype == 'rib': self.type = 'hbatch_prman' # Block command: self.cmd = 'hrender_af' if afnode.parm('ignore_inputs').eval(): self.cmd += ' -i' if self.capacity_min != -1 or self.capacity_max != -1: self.cmd += ' --numcpus '+ services.service.str_capacity self.cmd += ' -s @#@ -e @#@ --by %d -t "%s"' % (self.frame_inc, afnode.parm('take').eval()) self.cmd += ' "%(hipfilename)s"' self.cmd += ' "%s"' % ropnode.path() else: # Custom command driver: if int( afnode.parm('cmd_add').eval()): # Command: cmd = self.afnode.parm('cmd_cmd') self.cmd = afcommon.patternFromPaths( cmd.evalAsStringAtFrame( self.frame_first), cmd.evalAsStringAtFrame( self.frame_last)) # Name: self.name = self.afnode.parm('cmd_name').eval() if self.name is None or self.name == '': self.name = self.cmd.split(' ')[0] # Service: self.type = self.afnode.parm('cmd_service').eval() if self.type is None or self.type == '': self.type = self.cmd.split(' ')[0] # Prefix: self.cmd_useprefix = int( self.afnode.parm('cmd_use_afcmdprefix').eval()) elif not for_job_only: hou.ui.displayMessage('Can\'t process "%s"' % str(afnode.path())) return # Try to set driver foreground mode if ropnode: trange = ropnode.parm('trange') soho_foreground = ropnode.parm('soho_foreground') if trange != None and int(trange.eval()) == 0: if soho_foreground != None: if soho_foreground.eval() == 0: try: soho_foreground.set( 1) self.soho_foreground = 0 except: hou.ui.displayMessage('Set "Block Until Render Complete" on "%s" node' % ropnode.path()) return self.valid = True
def launch(self, *args, **kwargs): """launch renderer command """ # do nothing if there is no window (called externally) if not self.window: return # warn the user about the ignore settings try: dAO = pm.PyNode('defaultArnoldRenderOptions') ignore_attrs = [ 'ignoreSubdivision', 'ignoreDisplacement', 'ignoreBump', 'ignoreMotionBlur' ] attr_values = [(attr, dAO.getAttr(attr)) for attr in ignore_attrs if dAO.getAttr(attr) is True] if any(attr_values): msg_text = '<br>'.join( map(lambda x: '%s: %s' % (x[0], x[1]), attr_values)) response = pm.confirmDialog( title='Ignore These Settings?', message= 'You have ignored:<br><br>%s<br><br><b>Is that ok?</b>' % msg_text, button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if response == 'No': return except (pm.MayaNodeError, pm.MayaAttributeError): # no Arnold pass # check if rendering with persp camera try: wrong_camera_names = [ 'perspShape', 'topShape', 'sideShape', 'fontShape', 'persp1Shape', 'perspShape1', ] renderable_cameras = [ node for node in pm.ls(type='camera') if node.getAttr('renderable') ] if any( map(lambda x: x.name() in wrong_camera_names, renderable_cameras)): response = pm.confirmDialog( title='Rendering with Persp?', message= 'You are rendering with <b>Persp Camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if response == 'No': return if len(renderable_cameras) > 1: response = pm.confirmDialog( title='Rendering more than one Camera?', message= 'You are rendering <b>more than one camera<b><br><br>Is that ok?</b>', button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if response == 'No': return elif len(renderable_cameras) == 0: pm.confirmDialog( title='No <b>Renderable</b> camera!!!', message='There is no <b>renderable camera<b>!!!', button=['Ok'], defaultButton='Ok', cancelButton='Ok', dismissString='Ok') return except pm.MayaNodeError: # no default render globals node pass drg = pm.PyNode('defaultRenderGlobals') render_engine = drg.getAttr('currentRenderer') # RENDERER SPECIFIC CHECKS if render_engine == 'redshift': # if the renderer is RedShift # check if unifiedDisableDivision is 1 which will take too much time # to render dro = pm.PyNode('redshiftOptions') if dro.unifiedDisableDivision.get() == 1: response = pm.confirmDialog( title= "Enabled **Don't Automatically Reduce Samples of Other Effects**", message= 'It is not allowed to render with the following option is enabled:<br>' '<br>' "Don't Automatically Reduce Samples of Other Effects: Enabled<br>" "<br>" "Please DISABLE it!", button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK') return # Check dome light backgrounds domes_to_fix = [] rs_domes = pm.ls(type='RedshiftDomeLight') if rs_domes: for rs_dome in rs_domes: if rs_dome.getAttr('background_enable') == 1 \ or rs_dome.getAttr('backPlateEnabled') == 1: domes_to_fix.append(rs_dome.name()) if domes_to_fix: message = 'Some DomeLights have <b>BackGround Render ' \ 'Enabled</b>:' \ '<br><br>%s<br><br>' \ 'Are you Sure?' % '<br>'.join(domes_to_fix) response = pm.confirmDialog( title='Dome Lights with Background Enabled?', message=message, button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No') if response == 'No': return # abort on license fail dro.abortOnLicenseFail.set(1) elif render_engine == 'arnold': # check if the samples are too high dAO = pm.PyNode('defaultArnoldRenderOptions') aa_samples = dAO.AASamples.get() diff_samples = dAO.GIDiffuseSamples.get() try: glossy_samples = dAO.GIGlossySamples.get() except AttributeError: glossy_samples = dAO.GISpecularSamples.get() if int(pm.about(v=1)) >= 2017: sss_samples = dAO.GISssSamples.get() else: sss_samples = dAO.sssBssrdfSamples.get() total_diff_samples = aa_samples**2 * diff_samples**2 total_glossy_samples = aa_samples**2 * glossy_samples**2 total_sss_samples = aa_samples**2 * sss_samples**2 max_allowed_diff_samples = 225 max_allowed_glossy_samples = 100 max_allowed_sss_samples = 800 if total_diff_samples > max_allowed_diff_samples: pm.confirmDialog( title="Too Much Diffuse Samples!!!", message='You are using too much DIFFUSE SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of Diffuse ' 'Samples!!!' % max_allowed_diff_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK') return if total_glossy_samples > max_allowed_glossy_samples: pm.confirmDialog( title="Too Much Glossy Samples!!!", message='You are using too much GLOSSY SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of Glossy ' 'Samples!!!' % max_allowed_glossy_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK') return if total_sss_samples > max_allowed_sss_samples: pm.confirmDialog( title="Too Much SSS Samples!!!", message='You are using too much SSS SAMPLES (>%s)<br>' '<br>' 'Please either reduce AA samples of SSS ' 'Samples!!!' % max_allowed_sss_samples, button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK') return # check Light Samples # check point lights with zero radius but more than one samples all_point_lights = pm.ls(type='pointLight') ridiculous_point_lights = [] for point_light in all_point_lights: if point_light.aiRadius.get( ) < 0.1 and point_light.aiSamples.get() > 1: ridiculous_point_lights.append(point_light) if ridiculous_point_lights: pm.confirmDialog( title="Unnecessary Samples on Point Lights!!!", message='You are using too much SAMPLES (>1)<br>' '<br>' 'on <b>Point lights with zero radius</b><br>' '<br>' 'Please reduce the samples to 1', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK') return # Check area lights with more than 2 samples all_area_lights = pm.ls(type=['areaLight', 'aiAreaLight']) ridiculous_area_lights = [] for area_light in all_area_lights: if area_light.aiSamples.get() > 2: ridiculous_area_lights.append(area_light) if ridiculous_area_lights: pm.confirmDialog( title="Unnecessary Samples on Area Lights!!!", message='You are using too much SAMPLES (>2) on<br>' '<br>' '<b>Area Lights</b><br>' '<br>' 'Please reduce the samples to 2', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK') return # Check directional lights with angle == 0 and samples > 1 all_directional_lights = pm.ls(type='directionalLight') ridiculous_directional_lights = [] dir_sample_attr_name = 'aiSamples' # if pm.about(v=1) == "2014": # dir_sample_attr_name = 'aiSamples' for directional_light in all_directional_lights: if directional_light.aiAngle.get( ) == 0 and directional_light.attr( dir_sample_attr_name).get() > 1: ridiculous_directional_lights.append(directional_light) if ridiculous_directional_lights: pm.confirmDialog( title="Unnecessary Samples on Directional Lights!!!", message='You are using too much SAMPLES (>1) on <br>' '<br>' '<b>Directional lights with zero angle</b><br>' '<br>' 'Please reduce the samples to 1', button=['OK'], defaultButton='OK', cancelButton='OK', dismissString='OK') return # get values start_frame = pm.intField('cgru_afanasy__start_frame', q=1, v=1) end_frame = pm.intField('cgru_afanasy__end_frame', q=1, v=1) frames_per_task = \ pm.intField('cgru_afanasy__frames_per_task', q=1, v=1) by_frame = pm.intField('cgru_afanasy__by_frame', q=1, v=1) depend_mask_global = pm.textField('cgru_afanasy__depend_mask_global', q=1, text=True) hosts_mask = pm.textField('cgru_afanasy__hosts_mask', q=1, text=True) hosts_exclude = pm.textField('cgru_afanasy__hosts_exclude', q=1, text=True) separate_layers = \ pm.radioButtonGrp('cgru_afanasy__separate_layers', q=1, sl=1) pause = pm.checkBox('cgru_afanasy__paused', q=1, v=1) life_time = pm.intField('cgru_afanasy__life_time', q=1, v=1) annotation = pm.textField('cgru_afanasy__annotation', q=1, text=True) submit_multiple_times = pm.intField( 'cgru_afanasy__submit_multiple_times', q=1, v=1) errors_avoid_host = pm.intField('cgru_afanasy__errors_avoid_host', q=1, v=1) errors_retries = pm.intField('cgru_afanasy__errors_retries', q=1, v=1) errors_task_same_host = pm.intField( 'cgru_afanasy__errors_task_same_host', q=1, v=1) errors_forgive_time = pm.intField('cgru_afanasy__errors_forgive_time', q=1, v=1) generate_previews = pm.checkBox('cgru_afanasy__generate_previews', q=1, v=1) # check values if start_frame > end_frame: temp = end_frame end_frame = start_frame start_frame = temp frames_per_task = max(1, frames_per_task) by_frame = max(1, by_frame) # store without quota sign depend_mask_global = depend_mask_global.replace('"', '') hosts_mask = hosts_mask.replace('"', '') hosts_exclude = hosts_exclude.replace('"', '') # store field values pm.optionVar['cgru_afanasy__start_frame_ov'] = start_frame pm.optionVar['cgru_afanasy__end_frame_ov'] = end_frame pm.optionVar['cgru_afanasy__frames_per_task_ov'] = frames_per_task pm.optionVar['cgru_afanasy__by_frame_ov'] = by_frame pm.optionVar['cgru_afanasy__depend_mask_global_ov'] = \ depend_mask_global pm.optionVar['cgru_afanasy__hosts_mask_ov'] = hosts_mask pm.optionVar['cgru_afanasy__hosts_exclude_ov'] = hosts_exclude pm.optionVar['cgru_afanasy__separate_layers_ov'] = separate_layers pm.optionVar['cgru_afanasy__life_time_ov'] = life_time pm.optionVar['cgru_afanasy__annotation_ov'] = annotation pm.optionVar[ 'cgru_afanasy__submit_multiple_times_ov'] = submit_multiple_times pm.optionVar['cgru_afanasy__errors_avoid_host_ov'] = errors_avoid_host pm.optionVar['cgru_afanasy__errors_retries_ov'] = errors_retries pm.optionVar[ 'cgru_afanasy__errors_task_same_host_ov'] = errors_task_same_host pm.optionVar[ 'cgru_afanasy__errors_errors_forgive_time_ov'] = errors_forgive_time pm.optionVar['cgru_afanasy__paused_ov'] = pause pm.optionVar['cgru_afanasy__generate_previews_ov'] = generate_previews # get paths scene_name = pm.sceneName() datetime = '%s%s' % (time.strftime('%y%m%d-%H%M%S-'), str(time.time() - int(time.time()))[2:5]) filename = '%s.%s.mb' % (scene_name, datetime) project_path = pm.workspace(q=1, rootDirectory=1) # outputs = \ # pm.renderSettings(fullPath=1, firstImageName=1, lastImageName=1) # get output paths, set the RenderPass token to Beauty, # this will at least guarantee to get something outputs = \ pm.renderSettings( fullPath=1, firstImageName=1, lastImageName=1, leaveUnmatchedTokens=1, customTokenString="RenderPass=Beauty" ) # job_name = os.path.basename(scene_name) job_name = self.generate_job_name() logger.debug('%ss %se %sr' % (start_frame, end_frame, by_frame)) logger.debug('scene = %s' % scene_name) logger.debug('file = %s' % filename) logger.debug('job_name = %s' % job_name) logger.debug('project_path = %s' % project_path) logger.debug('outputs = %s' % outputs) logger.debug('annotation = %s' % annotation) logger.debug('separate_layers = %s' % separate_layers) logger.debug('errors_avoid_host = %s' % errors_avoid_host) logger.debug('errors_retries = %s' % errors_retries) logger.debug('errors_task_same_host = %s' % errors_task_same_host) logger.debug('errors_forgive_time = %s' % errors_forgive_time) logger.debug('generate_previews = %s' % generate_previews) if pm.checkBox('cgru_afanasy__close', q=1, v=1): pm.deleteUI(self.window) stored_log_level = None if render_engine == 'arnold': # set the verbosity level to warning+info aro = pm.PyNode('defaultArnoldRenderOptions') stored_log_level = aro.getAttr('log_verbosity') aro.setAttr('log_verbosity', 2) # set output to console aro.setAttr("log_to_console", 1) elif render_engine == 'redshift': # set the verbosity level to detailed+info redshift = pm.PyNode('redshiftOptions') stored_log_level = redshift.logLevel.get() redshift.logLevel.set(2) # save file pm.saveAs(filename, force=1, type='mayaBinary') # rename back to original name pm.renameFile(scene_name) # create the render command mrc = MayaRenderCommandBuilder(name=job_name, file_full_path=filename, render_engine=render_engine, project=project_path, by_frame=by_frame) # submit renders jobs = [] blocks = [] # # separate_layers: # 1 -> None -> submit one job with a single block with all layers # 2 -> Block -> submit one job with multiple blocks # 3 -> Job -> submit multiple jobs with a single block per layer # if separate_layers in [1, 2]: job = af.Job(job_name) jobs.append(job) if separate_layers in [2, 3]: # render each layer separately rlm = pm.PyNode('renderLayerManager') layers = [ layer for layer in rlm.connections(type=pm.nt.RenderLayer) if layer.renderable.get() ] for layer in layers: mrc_layer = copy.copy(mrc) layer_name = layer.name() mrc_layer.name = layer_name mrc_layer.render_layer = layer_name # create a new block for this layer block = af.Block( layer_name, renderer_to_block_type.get(render_engine, 'maya')) # Fix the output path for this layer # by replacing the "masterLayer" with the layer name # without rs_ at the beginning layer_outputs = outputs if layer_name != 'defaultRenderLayer': layer_outputs[0] = outputs[0].replace( 'masterLayer', layer_name.replace('rs_', '')) layer_outputs[1] = outputs[1].replace( 'masterLayer', layer_name.replace('rs_', '')) if generate_previews: outputs_split = afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths( layer_outputs[0], layer_outputs[1]))).split(';') block.setFiles(outputs_split) block.setNumeric(start_frame, end_frame, frames_per_task, by_frame) command = mrc_layer.build_command() block.setErrorsAvoidHost(errors_avoid_host) block.setErrorsRetries(errors_retries) block.setErrorsTaskSameHost(errors_task_same_host) block.setErrorsForgiveTime(errors_forgive_time) block.setCommand(command) if separate_layers == 2: blocks.append(block) else: job = af.Job('%s - %s' % (job_name, layer_name)) # add blocks job.blocks = [block] jobs.append(job) else: # create only one block block = af.Block('All Layers', renderer_to_block_type.get(render_engine, 'maya')) if generate_previews: block.setFiles( afcommon.patternFromDigits( afcommon.patternFromStdC( afcommon.patternFromPaths(outputs[0], outputs[1]))).split(';')) block.setNumeric(start_frame, end_frame, frames_per_task, by_frame) command = mrc.build_command() block.setCommand(command) blocks.append(block) for job in jobs: job.setAnnotation(annotation) job.setFolder('input', os.path.dirname(filename)) job.setFolder('output', os.path.dirname(outputs[0])) job.setDependMaskGlobal(depend_mask_global) job.setHostsMask(hosts_mask) job.setHostsMaskExclude(hosts_exclude) if life_time > 0: job.setTimeLife(life_time * 3600) else: job.setTimeLife(240 * 3600) job.setCmdPost('deletefiles -s "%s"' % os.path.abspath(filename)) if pause: job.offline() # add blocks if separate_layers in [1, 2]: job.blocks.extend(blocks) for i in range(submit_multiple_times): orig_job_name = job.data['name'] job.setName('%s - %03i' % (orig_job_name, i + 1)) status, data = job.send() # restore job name job.setName(orig_job_name) if not status: pm.PopupError('Something went wrong!') # restore log level if render_engine == 'arnold': aro = pm.PyNode('defaultArnoldRenderOptions') aro.setAttr('log_verbosity', stored_log_level) # disable set output to console aro.setAttr("log_to_console", 0) elif render_engine == 'redshift': redshift = pm.PyNode('redshiftOptions') redshift.logLevel.set(stored_log_level) # disable abort on license fail redshift.abortOnLicenseFail.set(0)
def getBlockParameters( afnode, ropnode, subblock, prefix, frame_range): params = [] if ropnode is not None and ropnode.type().name() == 'ifd' and afnode.parm('sep_enable').eval(): # Mantra separate render: block_generate = BlockParameters( afnode, ropnode, subblock, prefix, frame_range) blockname = block_generate.name block_generate.name += '-G' if not block_generate.valid: return None run_rop = afnode.parm('sep_run_rop').eval() read_rop = afnode.parm('sep_read_rop_params').eval() join_render = afnode.parm('sep_join').eval() tile_render = afnode.parm('sep_tile').eval() tile_divx = afnode.parm('sep_tile_divx').eval() tile_divy = afnode.parm('sep_tile_divy').eval() use_tmp_img_folder = afnode.parm('sep_use_tmp_img_folder').eval() del_rop_files = afnode.parm('sep_del_rop_files').eval() if read_rop or run_rop: if not block_generate.ropnode: hou.ui.displayMessage('Can`t find ROP for processing "%s"' % afnode.path()) if not isinstance( ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % block_generate.ropnode.path()) if not run_rop: join_render = False if join_render: tile_render = False delete_files = True else: if block_generate.ropnode.parm('soho_outputmode').eval() == 0: # Set output mode to produce ifd files: block_generate.ropnode.parm('soho_outputmode').set(1) block_generate.soho_outputmode = 0 block_generate.ropnode.parm('soho_diskfile').set( block_generate.ropnode.parm('vm_picture').unexpandedString() + '.ifd') if read_rop: images = ropnode.parm('vm_picture') files = ropnode.parm('soho_diskfile') afnode.parm('sep_images').set(images.unexpandedString()) afnode.parm('sep_files' ).set( files.unexpandedString()) images = afcommon.patternFromPaths( afnode.parm('sep_images').evalAsStringAtFrame(block_generate.frame_first), afnode.parm('sep_images').evalAsStringAtFrame(block_generate.frame_last)) files = afcommon.patternFromPaths( afnode.parm('sep_files' ).evalAsStringAtFrame(block_generate.frame_first), afnode.parm('sep_files' ).evalAsStringAtFrame(block_generate.frame_last)) if run_rop: if join_render: block_generate.preview = images if not join_render: block_generate.type = 'hbatch' else: block_generate.type = 'hbatch_mantra' block_generate.cmd = block_generate.cmd.replace( 'hrender_af', 'hrender_separate') if use_tmp_img_folder: block_generate.cmd += ' --tmpimg' if not join_render: tiles = tile_divx * tile_divy block_render = BlockParameters( afnode, ropnode, subblock, prefix, frame_range) block_render.name = blockname + '-R' block_render.cmd = 'mantra' block_render.type = block_render.cmd if run_rop: block_render.dependmask = block_generate.name if tile_render or del_rop_files or use_tmp_img_folder: block_render.cmd = 'mantrarender ' if del_rop_files and not tile_render: block_render.cmd += 'd' if use_tmp_img_folder: block_render.cmd += 't' if tile_render: block_render.numeric = False block_render.cmd += 'c %(tile_divx)d %(tile_divy)d' % vars() block_render.cmd += ' @#@' block_render.frame_pertask = -tiles for frame in range( block_generate.frame_first, block_generate.frame_last + 1, block_generate.frame_inc): arguments = afnode.parm('sep_render_arguments').evalAsStringAtFrame( frame) for tile in range( 0, tiles): block_render.tasks_names.append('%d tile %d' % ( frame, tile)) block_render.tasks_cmds.append('%d -R %s' % ( tile, arguments)) else: if del_rop_files or use_tmp_img_folder: block_render.cmd += ' -R ' else: block_render.cmd += ' -V a ' block_render.cmd += afcommon.patternFromPaths( afnode.parm('sep_render_arguments').evalAsStringAtFrame(block_generate.frame_first), afnode.parm('sep_render_arguments').evalAsStringAtFrame(block_generate.frame_last)) block_render.previw = images if tile_render: cmd = 'exrjoin %(tile_divx)d %(tile_divy)d %(images)s d' % vars() if del_rop_files: cmd += ' && deletefiles -s "%s"' % files block_join = BlockParameters( afnode, ropnode, subblock, prefix, frame_range) block_join.name = blockname + '-J' block_join.type = 'generic' block_join.dependmask = block_render.name block_join.cmd = cmd block_join.cmd_useprefix = False block_join.preview = images if read_rop: afnode.parm('sep_images').set('') afnode.parm('sep_files' ).set('') if tile_render: params.append( block_join) if not join_render: params.append( block_render) if run_rop: params.append( block_generate) else: params.append( BlockParameters( afnode, ropnode, subblock, prefix, frame_range)) return params
def getBlockParameters(afnode, ropnode, subblock, prefix, frame_range): params = [] if ropnode is not None \ and ropnode.type().name() == 'ifd' \ and afnode.parm('sep_enable').eval(): # Mantra separate render: block_generate = \ BlockParameters(afnode, ropnode, subblock, prefix, frame_range) blockname = block_generate.name block_generate.name += '-G' if not block_generate.valid: return None run_rop = afnode.parm('sep_run_rop').eval() read_rop = afnode.parm('sep_read_rop_params').eval() join_render = afnode.parm('sep_join').eval() tile_render = afnode.parm('sep_tile').eval() tile_divx = afnode.parm('sep_tile_divx').eval() tile_divy = afnode.parm('sep_tile_divy').eval() use_tmp_img_folder = afnode.parm('sep_use_tmp_img_folder').eval() del_rop_files = afnode.parm('sep_del_rop_files').eval() if read_rop or run_rop: if not block_generate.ropnode: hou.ui.displayMessage('Can`t find ROP for processing "%s"' % afnode.path()) if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % block_generate.ropnode.path()) if not run_rop: join_render = False if join_render: tile_render = False delete_files = True # This variable seems not used else: if block_generate.ropnode.parm('soho_outputmode').eval() == 0: # Set output mode to produce ifd files: block_generate.ropnode.parm('soho_outputmode').set(1) block_generate.soho_outputmode = 0 block_generate.ropnode.parm('soho_diskfile').set( block_generate.ropnode.parm( 'vm_picture').unexpandedString() + '.ifd') if read_rop: images = ropnode.parm('vm_picture') files = ropnode.parm('soho_diskfile') afnode.parm('sep_images').set(images.unexpandedString()) afnode.parm('sep_files').set(files.unexpandedString()) images = afcommon.patternFromPaths( afnode.parm('sep_images').evalAsStringAtFrame( block_generate.frame_first), afnode.parm('sep_images').evalAsStringAtFrame( block_generate.frame_last)) files = afcommon.patternFromPaths( afnode.parm('sep_files').evalAsStringAtFrame( block_generate.frame_first), afnode.parm('sep_files').evalAsStringAtFrame( block_generate.frame_last)) if run_rop: if join_render: block_generate.preview = images if not join_render: block_generate.type = 'hbatch' else: block_generate.type = 'hbatch_mantra' block_generate.cmd = block_generate.cmd.replace( 'hrender_af', 'hrender_separate') if use_tmp_img_folder: block_generate.cmd += ' --tmpimg' if not join_render: tiles = tile_divx * tile_divy block_render = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_render.name = blockname + '-R' block_render.cmd = 'mantra' block_render.type = block_render.cmd if run_rop: block_render.dependmask = block_generate.name if tile_render or del_rop_files or use_tmp_img_folder: block_render.cmd = 'mantrarender ' if del_rop_files and not tile_render: block_render.cmd += 'd' if use_tmp_img_folder: block_render.cmd += 't' if tile_render: block_render.numeric = False block_render.cmd += 'c %(tile_divx)d %(tile_divy)d' % vars() block_render.cmd += ' @#@' block_render.frame_pertask = -tiles for frame in range(block_generate.frame_first, block_generate.frame_last + 1, block_generate.frame_inc): arguments = afnode.parm( 'sep_render_arguments').evalAsStringAtFrame(frame) for tile in range(0, tiles): block_render.tasks_names.append('%d tile %d' % (frame, tile)) block_render.tasks_cmds.append('%d -R %s' % (tile, arguments)) else: if del_rop_files or use_tmp_img_folder: block_render.cmd += ' -R ' else: block_render.cmd += ' -V a ' block_render.cmd += afcommon.patternFromPaths( afnode.parm('sep_render_arguments').evalAsStringAtFrame( block_generate.frame_first), afnode.parm('sep_render_arguments').evalAsStringAtFrame( block_generate.frame_last)) block_render.preview = images if tile_render: cmd = 'exrjoin %(tile_divx)d %(tile_divy)d %(images)s d' % vars() if del_rop_files: cmd += ' && deletefiles -s "%s"' % files block_join = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_join.name = blockname + '-J' block_join.type = 'generic' block_join.dependmask = block_render.name block_join.cmd = cmd block_join.cmd_useprefix = False block_join.preview = images if read_rop: afnode.parm('sep_images').set('') afnode.parm('sep_files').set('') if tile_render: params.append(block_join) if not join_render: params.append(block_render) if run_rop: params.append(block_generate) else: params.append( BlockParameters(afnode, ropnode, subblock, prefix, frame_range)) return params
def __init__(self, afnode, ropnode, subblock, prefix, frame_range, for_job_only=False): if VERBOSE == 2: if ropnode: print('Initializing block parameters for "%s" from "%s"' % (ropnode.path(), afnode.path())) else: print('Initializing command block parameters from "%s"' % afnode.path()) # Init parameters: self.valid = False self.afnode = afnode self.ropnode = None self.subblock = subblock self.frame_pertask = 1 self.frame_sequential = 1 self.prefix = prefix self.preview = '' self.name = '' self.service = '' self.parser = '' self.cmd = '' self.cmd_useprefix = True self.dependmask = '' self.fullrangedepend = False self.numeric = True self.frame_first, self.frame_last, self.frame_inc = frame_range self.auxargs = '' self.tasks_names = [] self.tasks_cmds = [] self.tasks_previews = [] # Fill in this array with files to delete in a block post command. # Files should have a common afanasy "@#*@" pattern, # it will be replaced with "*" for shell. self.delete_files = [] # Parameters to restore ROP changes: self.soho_foreground = None self.soho_outputmode = None # Get parameters: self.frame_pertask = int(afnode.parm('frame_pertask').eval()) self.frame_sequential = int(afnode.parm('frame_sequential').eval()) self.job_name = str(afnode.parm('job_name').eval()) self.job_branch = '' self.start_paused = int(afnode.parm('start_paused').eval()) self.platform = str(afnode.parm('platform').eval()) self.subtaskdepend = int(afnode.parm('subtaskdepend').eval()) self.priority = -1 self.max_runtasks = -1 self.maxperhost = -1 self.maxruntime = -1 self.minruntime = -1 self.capacity = -1 self.capacity_min = -1 self.capacity_max = -1 self.hosts_mask = '' self.hosts_mask_exclude = '' self.depend_mask = '' self.depend_mask_global = '' self.min_memory = -1 self.preview_approval = afnode.parm('preview_approval').eval() if afnode.parm('enable_extended_parameters').eval(): self.job_branch = self.afnode.parm('job_branch').eval() self.parser = self.afnode.parm('override_parser').eval() self.priority = int(afnode.parm('priority').eval()) self.max_runtasks = int(afnode.parm('max_runtasks').eval()) self.maxperhost = int(afnode.parm('maxperhost').eval()) self.maxruntime = int(afnode.parm('maxruntime').eval()) self.minruntime = int(afnode.parm('minruntime').eval()) self.min_memory = int(afnode.parm('min_memory').eval()) self.capacity = int(afnode.parm('capacity').eval()) self.capacity_min = int( afnode.parm('capacity_coefficient1').eval()) self.capacity_max = int( afnode.parm('capacity_coefficient2').eval()) self.hosts_mask = str(afnode.parm('hosts_mask').eval()) self.hosts_mask_exclude = str( afnode.parm('hosts_mask_exclude').eval()) self.depend_mask = str(afnode.parm('depend_mask').eval()) self.depend_mask_global = str( afnode.parm('depend_mask_global').eval()) # Process frame range: opname = afnode.path() if afnode.parm('trange').eval() > 1: self.fullrangedepend = True if ropnode: opname = ropnode.path() trange = ropnode.parm('trange') if trange is not None: if int(trange.eval()) > 0: if ropnode.parm('f1') is not None: self.frame_first = int(ropnode.parm('f1').eval()) if ropnode.parm('f2') is not None: self.frame_last = int(ropnode.parm('f2').eval()) if ropnode.parm('f3') is not None: self.frame_inc = int(ropnode.parm('f3').eval()) if int(trange.eval()) > 1: self.fullrangedepend = True if self.frame_last < self.frame_first: hou.ui.displayMessage('Last frame < first frame for "%s"' % opname) return if self.frame_inc < 1: hou.ui.displayMessage('Frame increment < 1 for "%s"' % opname) return if self.frame_pertask < 1: hou.ui.displayMessage('Frames per task < 1 for "%s"' % opname) return # Process output driver type to construct a command: if ropnode: self.service = 'hbatch' if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage( '"%s" is not a ROP node' % ropnode.path() ) return self.ropnode = ropnode self.name = str(ropnode.name()) if self.prefix != '': self.name = '%s_%s' % (self.prefix, self.name) # Block type and preview: roptype = ropnode.type().name() if roptype == 'ifd': if ropnode.node(ropnode.parm('camera').eval())==None: hou.ui.displayMessage("Camera in "+ropnode.name()+" is not valid",severity = hou.severityType.Error) return if not ropnode.parm('soho_outputmode').eval(): self.service = 'hbatch_mantra' vm_picture = ropnode.parm('vm_picture') if vm_picture is not None: self.preview = \ afcommon.patternFromPaths( vm_picture.evalAsStringAtFrame(self.frame_first), vm_picture.evalAsStringAtFrame(self.frame_last) ) elif roptype == 'rib': self.service = 'hbatch_prman' elif roptype == 'arnold': if not ropnode.parm('soho_outputmode').eval(): self.service = 'houdinitoarnold' ar_picture = ropnode.parm('ar_picture') if ar_picture is not None: self.preview = \ afcommon.patternFromPaths( ar_picture.evalAsStringAtFrame(self.frame_first), ar_picture.evalAsStringAtFrame(self.frame_last) ) elif roptype == 'alembic': self.numeric = False taskname = ropnode.name() taskname += ' ' + str(self.frame_first) taskname += '-' + str(self.frame_last) self.tasks_names.append(taskname) self.tasks_cmds.append(self.frame_first) elif roptype == 'Redshift_ROP': self.service = 'hbatch_redshift' rs_picture = ropnode.parm('RS_outputFileNamePrefix') if rs_picture is not None: self.preview = \ afcommon.patternFromPaths( rs_picture.evalAsStringAtFrame(self.frame_first), rs_picture.evalAsStringAtFrame(self.frame_last) ) # Block command: self.cmd = 'hrender_af' if afnode.parm('ignore_inputs').eval(): self.cmd += ' -i' if self.capacity_min != -1 or self.capacity_max != -1: self.cmd += ' --numcpus ' + services.service.str_capacity self.cmd += ' -s @#@ -e @#@ --by %d -t "%s"' % ( self.frame_inc, afnode.parm('take').eval() ) # numWedges = computeWedge(ropnode, roptype) # if numWedges: # self.frame_first = 0 # self.frame_last = numWedges - 1 # self.frame_inc = 1 # self.frame_pertask = 1 # self.parser = "mantra" self.cmd += '%(auxargs)s' self.cmd += ' "%(hipfilename)s"' self.cmd += ' "%s"' % ropnode.path() if afnode.parm('enable_extended_parameters').eval(): # Override service: override_service = self.afnode.parm('override_service').eval() if override_service is not None and len(override_service): self.service = override_service else: # Custom command driver: if int(afnode.parm('cmd_mode').eval()): # Command: cmd = self.afnode.parm('cmd_cmd') self.cmd = afcommon.patternFromPaths( cmd.evalAsStringAtFrame(self.frame_first), cmd.evalAsStringAtFrame(self.frame_last) ) # Name: self.name = self.afnode.parm('cmd_name').eval() if self.name is None or self.name == '': self.name = self.cmd.split(' ')[0] # Service: self.service = self.afnode.parm('cmd_service').eval() if self.service is None or self.service == '': self.service = self.cmd.split(' ')[0] # Parser: self.parser = self.afnode.parm('cmd_parser').eval() # Prefix: self.cmd_useprefix = \ int(self.afnode.parm('cmd_use_afcmdprefix').eval()) # Delete files on job deletion: if self.afnode.parm('cmd_delete_files').eval(): cmd_files = self.afnode.parm('cmd_files') self.delete_files.append(afcommon.patternFromPaths( cmd_files.evalAsStringAtFrame(self.frame_first), cmd_files.evalAsStringAtFrame(self.frame_last) )) elif not for_job_only: hou.ui.displayMessage('Can\'t process "%s"' % afnode.path()) return # Try to set driver foreground mode if ropnode: trange = ropnode.parm('trange') soho_foreground = ropnode.parm('soho_foreground') if trange is not None and int(trange.eval()) == 0: if soho_foreground is not None: if soho_foreground.eval() == 0: try: soho_foreground.set(1) self.soho_foreground = 0 except: # TODO: too broad exception clause hou.ui.displayMessage( 'Set "Block Until Render Complete" on "%s" ' 'node' % ropnode.path() ) return # Try to create output folder: if self.preview != '' and afnode.parm('check_output_folder').eval(): folder = os.path.dirname(self.preview) if not os.path.isdir(folder): if hou.ui.displayMessage(folder, buttons=('Create', 'Abort'), default_choice=0, close_choice=1, title='Output Folder Does Not Exist', details=folder) == 0: try: os.makedirs(folder) except Exception as e: hou.ui.displayMessage(folder, buttons=('Abort',), default_choice=0, close_choice=1, title='Error Creating Output Folder', details=str(e)) return if not os.path.isdir(folder): hou.ui.displayMessage(folder, buttons=('Abort',), default_choice=0, close_choice=1, title='Can`t Create Output Folder', details=folder) return else: return self.valid = True
def getBlockParameters(afnode, ropnode, subblock, prefix, frame_range): params = [] if ropnode is not None and ropnode.type().name() == 'ifd' and afnode.parm( 'sep_enable').eval(): # Case mantra separate render: block_generate = \ BlockParameters(afnode, ropnode, subblock, prefix, frame_range) blockname = block_generate.name block_generate.name += '-G' if not block_generate.valid: block_generate.doPost() return None run_rop = afnode.parm('sep_run_rop').eval() read_rop = afnode.parm('sep_read_rop_params').eval() join_render = afnode.parm('sep_join').eval() tile_render = afnode.parm('sep_tile').eval() tile_divx = afnode.parm('sep_tile_divx').eval() tile_divy = afnode.parm('sep_tile_divy').eval() use_tmp_img_folder = afnode.parm('sep_use_tmp_img_folder').eval() del_rop_files = afnode.parm('sep_del_rop_files').eval() if read_rop or run_rop: if not block_generate.ropnode: hou.ui.displayMessage('Can`t find ROP for processing "%s"' % afnode.path()) if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % block_generate.ropnode.path()) if not run_rop: join_render = False if join_render: tile_render = False else: if block_generate.ropnode.parm('soho_outputmode').eval() == 0: # Set output mode to produce ifd files: block_generate.ropnode.parm('soho_outputmode').set(1) block_generate.soho_outputmode = 0 block_generate.ropnode.parm('soho_diskfile').set( block_generate.ropnode.parm( 'vm_picture').unexpandedString() + '.ifd') if read_rop: parm_images = ropnode.parm('vm_picture') parm_files = ropnode.parm('soho_diskfile') else: parm_images = afnode.parm('sep_images') parm_files = afnode.parm('sep_files') images = afcommon.patternFromPaths( parm_images.evalAsStringAtFrame(block_generate.frame_first), parm_images.evalAsStringAtFrame(block_generate.frame_last)) files = afcommon.patternFromPaths( parm_files.evalAsStringAtFrame(block_generate.frame_first), parm_files.evalAsStringAtFrame(block_generate.frame_last)) if run_rop: if join_render: block_generate.preview = images if not join_render: block_generate.service = 'hbatch' else: block_generate.service = 'hbatch_mantra' block_generate.cmd = block_generate.cmd.replace( 'hrender_af', 'hrender_separate') if use_tmp_img_folder: block_generate.cmd += ' --tmpimg' if not join_render: tiles = tile_divx * tile_divy block_render = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_render.name = blockname + '-R' block_render.cmd = 'mantra' block_render.service = block_render.cmd if run_rop: block_render.dependmask = block_generate.name if tile_render or del_rop_files or use_tmp_img_folder: block_render.cmd = 'mantrarender ' if del_rop_files: block_render.delete_files.append(files) if use_tmp_img_folder: block_render.cmd += 't' if tile_render: block_render.numeric = False block_render.cmd += 'c %(tile_divx)d %(tile_divy)d' % vars() block_render.cmd += ' @#@' block_render.frame_pertask = -tiles for frame in range(block_generate.frame_first, block_generate.frame_last + 1, block_generate.frame_inc): arguments = afnode.parm( 'sep_render_arguments').evalAsStringAtFrame(frame) arguments = arguments.replace( '@FILES@', parm_files.evalAsStringAtFrame(frame)) for tile in range(0, tiles): block_render.tasks_names.append('%d tile %d' % (frame, tile)) block_render.tasks_cmds.append('%d -R %s' % (tile, arguments)) else: if del_rop_files or use_tmp_img_folder: block_render.cmd += ' -R ' else: block_render.cmd += ' -V a ' block_render.cmd += afcommon.patternFromPaths( afnode.parm('sep_render_arguments').evalAsStringAtFrame( block_generate.frame_first), afnode.parm('sep_render_arguments').evalAsStringAtFrame( block_generate.frame_last)).replace('@FILES@', files) block_render.preview = images if tile_render: cmd = 'exrjoin %(tile_divx)d %(tile_divy)d %(images)s d' % vars() block_join = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_join.name = blockname + '-J' block_join.service = 'generic' block_join.dependmask = block_render.name block_join.cmd = cmd block_join.cmd_useprefix = False block_join.preview = images if tile_render: params.append(block_join) if not join_render: params.append(block_render) if run_rop: params.append(block_generate) elif len(str(afnode.parm('ds_node').eval())): # Case distribute simulation: ds_node_path = str(afnode.parm('ds_node').eval()) ds_node = hou.node(ds_node_path) if not ds_node: hou.ui.displayMessage('No such control node: "%s"' % ds_node_path) return parms = ['address', 'port', 'slice'] for parm in parms: if not ds_node.parm(parm): hou.ui.displayMessage( 'Control node "%s" does not have "%s" parameter' % (ds_node_path, parm)) return enable_tracker = not afnode.parm('ds_tracker_manual').eval() if enable_tracker: # Tracker block: par_start = getTrackerParameters(afnode, ropnode, subblock, prefix, frame_range, True) params.append(par_start) # A block for each slice: ds_num_slices = int(afnode.parm('ds_num_slices').eval()) for s in range(0, ds_num_slices): par = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) sim_blocks_mask = par.name + '.*' par.name += '-s%d' % s par.frame_pertask = par.frame_last - par.frame_first + 1 if enable_tracker: par.addDependMask(par_start.name) par.fullrangedepend = True par.auxargs = ' --ds_node "%s"' % ds_node_path par.auxargs += ' --ds_address "%s"' % str( afnode.parm('ds_address').eval()) par.auxargs += ' --ds_port %d' % int(afnode.parm('ds_port').eval()) par.auxargs += ' --ds_slice %d' % s params.append(par) if enable_tracker: # Stop tracker block: par_stop = getTrackerParameters(afnode, ropnode, subblock, prefix, frame_range, False) par_stop.addDependMask(sim_blocks_mask) params.append(par_stop) # Set other block names for start tracker block. # As start tracker block will set other block environment # to specify started tracker and port. par_start.cmd += ' --envblocks "%s|%s"' % (sim_blocks_mask, par_stop.name) # On this block depend mask will be reset on tracker start: par_start.cmd += ' --depblocks "%s"' % sim_blocks_mask else: params.append( BlockParameters(afnode, ropnode, subblock, prefix, frame_range)) return params
def getBlockParameters(afnode, ropnode, subblock, prefix, frame_range): params = [] if ropnode is not None and ropnode.type().name() == 'ifd' and afnode.parm( 'sep_enable').eval(): # Case mantra separate render: block_generate = \ BlockParameters(afnode, ropnode, subblock, prefix, frame_range) blockname = block_generate.name block_generate.name += '-G' if not block_generate.valid: return None run_rop = afnode.parm('sep_run_rop').eval() read_rop = afnode.parm('sep_read_rop_params').eval() join_render = afnode.parm('sep_join').eval() tile_render = afnode.parm('sep_tile').eval() tile_divx = afnode.parm('sep_tile_divx').eval() tile_divy = afnode.parm('sep_tile_divy').eval() use_tmp_img_folder = afnode.parm('sep_use_tmp_img_folder').eval() del_rop_files = afnode.parm('sep_del_rop_files').eval() if read_rop or run_rop: if not block_generate.ropnode: hou.ui.displayMessage('Can`t find ROP for processing "%s"' % afnode.path()) if not isinstance(ropnode, hou.RopNode): hou.ui.displayMessage('"%s" is not a ROP node' % block_generate.ropnode.path()) if not run_rop: join_render = False if join_render: tile_render = False else: if block_generate.ropnode.parm('soho_outputmode').eval() == 0: # Set output mode to produce ifd files: block_generate.ropnode.parm('soho_outputmode').set(1) block_generate.soho_outputmode = 0 block_generate.ropnode.parm('soho_diskfile').set( block_generate.ropnode.parm( 'vm_picture').unexpandedString() + '.ifd') if read_rop: images = ropnode.parm('vm_picture') files = ropnode.parm('soho_diskfile') afnode.parm('sep_images').set(images.unexpandedString()) afnode.parm('sep_files').set(files.unexpandedString()) images = afcommon.patternFromPaths( afnode.parm('sep_images').evalAsStringAtFrame( block_generate.frame_first), afnode.parm('sep_images').evalAsStringAtFrame( block_generate.frame_last)) files = afcommon.patternFromPaths( afnode.parm('sep_files').evalAsStringAtFrame( block_generate.frame_first), afnode.parm('sep_files').evalAsStringAtFrame( block_generate.frame_last)) if run_rop: if join_render: block_generate.preview = images if not join_render: block_generate.type = 'hbatch' else: block_generate.type = 'hbatch_mantra' block_generate.cmd = block_generate.cmd.replace( 'hrender_af', 'hrender_separate') if use_tmp_img_folder: block_generate.cmd += ' --tmpimg' if not join_render: tiles = tile_divx * tile_divy block_render = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_render.name = blockname + '-R' block_render.cmd = 'mantra' block_render.type = block_render.cmd if run_rop: block_render.dependmask = block_generate.name if tile_render or del_rop_files or use_tmp_img_folder: block_render.cmd = 'mantrarender ' if del_rop_files and not tile_render: block_render.cmd += 'd' if use_tmp_img_folder: block_render.cmd += 't' if tile_render: block_render.numeric = False block_render.cmd += 'c %(tile_divx)d %(tile_divy)d' % vars() block_render.cmd += ' @#@' block_render.frame_pertask = -tiles for frame in range(block_generate.frame_first, block_generate.frame_last + 1, block_generate.frame_inc): arguments = afnode.parm( 'sep_render_arguments').evalAsStringAtFrame(frame) for tile in range(0, tiles): block_render.tasks_names.append('%d tile %d' % (frame, tile)) block_render.tasks_cmds.append('%d -R %s' % (tile, arguments)) else: if del_rop_files or use_tmp_img_folder: block_render.cmd += ' -R ' else: block_render.cmd += ' -V a ' block_render.cmd += afcommon.patternFromPaths( afnode.parm('sep_render_arguments').evalAsStringAtFrame( block_generate.frame_first), afnode.parm('sep_render_arguments').evalAsStringAtFrame( block_generate.frame_last)) block_render.preview = images if tile_render: cmd = 'exrjoin %(tile_divx)d %(tile_divy)d %(images)s d' % vars() if del_rop_files: cmd += ' && deletefiles -s "%s"' % files block_join = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) block_join.name = blockname + '-J' block_join.type = 'generic' block_join.dependmask = block_render.name block_join.cmd = cmd block_join.cmd_useprefix = False block_join.preview = images if read_rop: afnode.parm('sep_images').set('') afnode.parm('sep_files').set('') if tile_render: params.append(block_join) if not join_render: params.append(block_render) if run_rop: params.append(block_generate) elif len(str(afnode.parm('ds_node').eval())): # Case distribute simulation: ds_node_path = str(afnode.parm('ds_node').eval()) ds_node = hou.node(ds_node_path) if not ds_node: hou.ui.displayMessage('No such control node: "%s"' % ds_node_path) return parms = ['address', 'port', 'slice'] for parm in parms: if not ds_node.parm(parm): hou.ui.displayMessage( 'Control node "%s" does not have "%s" parameter' % (ds_node_path, parm)) return ds_num_slices = int(afnode.parm('ds_num_slices').eval()) for s in range(0, ds_num_slices): par = BlockParameters(afnode, ropnode, subblock, prefix, frame_range) par.name += '-s%d' % s par.frame_pertask = par.frame_last - par.frame_first + 1 par.auxargs = ' --ds_node "%s"' % ds_node_path par.auxargs += ' --ds_address "%s"' % str( afnode.parm('ds_address').eval()) par.auxargs += ' --ds_port %d' % int(afnode.parm('ds_port').eval()) par.auxargs += ' --ds_slice %d' % s params.append(par) else: params.append( BlockParameters(afnode, ropnode, subblock, prefix, frame_range)) return params