def init_state(self): """Queries Soho to initialize the attributes of the class""" state_parms = { "rop": soho.SohoParm("object:name", "string", key="rop"), "soho_outputmode": soho.SohoParm( "soho_outputmode", "integer", skipdefault=False, key="output_mode" ), "soho_diskfile": soho.SohoParm( "soho_diskfile", "string", skipdefault=False, key="disk_file" ), "hip": soho.SohoParm("$HIP", "string", key="hip"), "hipname": soho.SohoParm("$HIPNAME", "string", key="hipname"), "hipfile": soho.SohoParm("$HIPFILE", "string", key="hipfile"), "ver": soho.SohoParm( "state:houdiniversion", "string", ["9.0"], False, key="ver" ), "now": soho.SohoParm("state:time", "real", [0], False, key="now"), "fps": soho.SohoParm("state:fps", "real", [24], False, key="fps"), "pbrt_nanovdb_converter": soho.SohoParm( "pbrt_nanovdb_converter", "string", ["nanovdb_convert -z -f {vdb} {nanovdb}"], False, key="nanovdb_converter", ), } rop = soho.getOutputDriver() parms = soho.evaluate(state_parms, None, rop) for parm in parms: setattr(self, parm, parms[parm].Value[0]) if not self.fps: self.fps = 24.0 self.inv_fps = 1.0 / self.fps return
def wrangle_motionblur(obj, now): mb_parms = [soho.SohoParm('allowmotionblur', 'int', [0], False), soho.SohoParm('shutter', 'float', [0.5], False), soho.SohoParm('shutteroffset', 'float', [None], False), soho.SohoParm('motionstyle', 'string', ['trailing'], False), ] eval_mb_parms = obj.evaluate(mb_parms, now) if not eval_mb_parms[0].Value[0]: return None shutter = eval_mb_parms[1].Value[0] * scene_state.inv_fps offset = eval_mb_parms[2].Value[0] style = eval_mb_parms[3].Value[0] # This logic is in part from RIBmisc.py # NOTE: For pbrt output we will keep this limited to just shutter and # shutteroffset, if the need arises we can add in the various # scaling options etc. if style == 'centered': delta = shutter * 0.5 elif style == 'leading': delta = shutter else: # trailing delta = 0.0 delta -= (offset-1.0) * 0.5 * shutter start_time = now - delta end_time = start_time + shutter return ShutterRange(start_time, end_time)
def add_aovs_to_ifd(self, wrangler, cam, now): """Add auto_aovs to the ifd. :param wrangler: A SOHO wrangler. :type wrangler: object :param cam: A SOHO camera. :type cam: soho.SohoObject :param now: The evaluation time. :type now: float :return: """ import IFDapi import IFDsettings import soho # The parameter that defines which automatic aovs to add. parms = { "enable": soho.SohoParm( "enable_auto_aovs", "int", [1], skipdefault=False ), "auto_aovs": soho.SohoParm( "auto_aovs", "str", [""], skipdefault=False ), } # Attempt to evaluate the parameter. plist = cam.wrangle(wrangler, parms, now) if plist: # Adding is disabled so bail out. if plist["enable_auto_aovs"].Value[0] == 0: return aov_str = plist["auto_aovs"].Value[0] # Parse the string to get any aovs/groups. aov_items = self.get_aovs_from_string(aov_str) # Write any found items to the ifd. for item in aov_items: item.write_to_ifd(wrangler, cam, now) # If we are generating the "Op_Id" plane we will need to tell SOHO # to generate these properties when outputting object. Look for # the "Op_Id" variable being exported and if so enable operator id # generation. for aov in flatten_aov_items(aov_items): if aov.variable == "Op_Id": IFDapi.ray_comment("Forcing object id generation") IFDsettings._GenerateOpId = True break
def output_materials(obj, wrangler, now): """Output Materials for an object The shop_materialpath parameter and shop_materialpath prim attribute are both checked for output. """ # We use a shaderhandle instead of a string so Soho instances are properly # resolved when Full Instancing is used. parms = [ soho.SohoParm('shop_materialpath', 'shaderhandle', skipdefault=False) ] eval_parms = obj.evaluate(parms, now) if eval_parms: shop = eval_parms[0].Value[0] if shop: wrangle_shading_network(shop) soppath = [] if not obj.evalString('object:soppath', now, soppath): return soppath = soppath[0] gdp = SohoGeometry(soppath, now) global_material = gdp.globalValue('shop_materialpath') if global_material is not None: wrangle_shading_network(global_material[0]) attrib_h = gdp.attribute('geo:prim', 'shop_materialpath') if attrib_h >= 0: shop_materialpaths = gdp.attribProperty(attrib_h, 'geo:allstrings') for shop in shop_materialpaths: wrangle_shading_network(shop) return
def write_to_ifd(self, wrangler, cam, now): """Output the AOV. :param wrangler: A SOHO wrangler. :type wrangler: object :param cam: A SOHO camera. :type cam: soho.SohoObject :param now: The evaluation time. :type now: float :return: """ import soho # The base data to pass along. data = self.as_data() channel = self.channel # If there is no explicit channel set, use the variable name. if channel is None: channel = self.variable # Handle exporting of multiple components if self.componentexport: components = self.components # If no components are explicitly set on the AOV, use the # vm_exportcomponents parameter from the Mantra ROP. if not components: parms = { "vm_exportcomponents": soho.SohoParm( "vm_exportcomponents", "str", [""], skipdefault=False ), } plist = cam.wrangle(wrangler, parms, now) if plist: components = plist["vm_exportcomponents"].Value[0] components = components.split() # Create a unique channel for each component and output the block. for component in components: comp_data = copy.copy(data) comp_data[consts.CHANNEL_KEY] = "{}_{}".format(channel, component) comp_data[consts.COMPONENT_KEY] = component self._light_export_planes(comp_data, wrangler, cam, now) else: # Update the data with the channel. data[consts.CHANNEL_KEY] = channel self._light_export_planes(data, wrangler, cam, now)
def init_state(self): """Queries Soho to initialize the attributes of the class""" state_parms = { "rop": soho.SohoParm("object:name", "string", key="rop"), "hip": soho.SohoParm("$HIP", "string", key="hip"), "hipname": soho.SohoParm("$HIPNAME", "string", key="hipname"), "hipfile": soho.SohoParm("$HIPFILE", "string", key="hipfile"), "ver": soho.SohoParm("state:houdiniversion", "string", ["9.0"], False, key="ver"), "now": soho.SohoParm("state:time", "real", [0], False, key="now"), "fps": soho.SohoParm("state:fps", "real", [24], False, key="fps"), } rop = soho.getOutputDriver() parms = soho.evaluate(state_parms, None, rop) for parm in parms: setattr(self, parm, parms[parm].Value[0]) if not self.fps: self.fps = 24.0 self.inv_fps = 1.0 / self.fps return
def init_state(self): """Queries Soho to initialize the attributes of the class""" state_parms = { 'rop': soho.SohoParm('object:name', 'string', key='rop'), 'hip': soho.SohoParm('$HIP', 'string', key='hip'), 'hipname': soho.SohoParm('$HIPNAME', 'string', key='hipname'), 'hipfile': soho.SohoParm('$HIPFILE', 'string', key='hipfile'), 'ver': soho.SohoParm('state:houdiniversion', 'string', ["9.0"], False, key='ver'), 'now': soho.SohoParm('state:time', 'real', [0], False, key='now'), 'fps': soho.SohoParm('state:fps', 'real', [24], False, key='fps'), } rop = soho.getOutputDriver() parms = soho.evaluate(state_parms, None, rop) for parm in parms: setattr(self, parm, parms[parm].Value[0]) if not self.fps: self.fps = 24.0 self.inv_fps = 1.0 / self.fps return
def getData(self, wrangler, cam, now): """Get the conditional data to apply. Args: wrangler : (Object) A wrangler object. cam : (soho.SohoObject) The camera being rendered. now : (float) The parameter evaluation time. Raises: N/A Returns: dict A dictionary of plane settings. This function matches the pattern against the specified parameter value and returns the corresponding match data. """ import soho parmName = self.parmData["name"] # Build a dictionary containing the required SohoParm object. We don't # want to skip defaults because if the parm is at its default we won't # be able to check against it. parms = { parmName: soho.SohoParm( parmName, self.parmData["type"], default=[self.parmData["default"]], skipdefault=False ) } # Attempt to evaluate the parameter. plist = cam.wrangle(wrangler, parms, now) # Parameter exists and a value was found. if plist: # Get the parameter value. result = plist[parmName].Value[0] # Match the value against the pattern. Return the corresponding # data. if re.match(self.pattern, result) is not None: return self.match else: return self.nomatch return {}
def addAOVsToIfd(wrangler, cam, now): """Add auto_aovs to the ifd.""" import IFDapi import IFDsettings import soho # The parameter that defines which automatic aovs to add. parms = { "enable": soho.SohoParm("enable_auto_aovs", "int", [1], skipdefault=False), "auto_aovs": soho.SohoParm("auto_aovs", "str", [""], skipdefault=False), } # Attempt to evaluate the parameter. plist = cam.wrangle(wrangler, parms, now) if plist: # Adding is disabled so bail out. if plist["enable_auto_aovs"].Value[0] == 0: return aov_str = plist["auto_aovs"].Value[0] # Construct a manager-laf manager = findOrCreateSessionAOVManager() # Parse the string to get any aovs/groups. aovs = manager.getAOVsFromString(aov_str) # Write any found items to the ifd. for aov in aovs: aov.writeToIfd(wrangler, cam, now) # If we are generating the "Op_Id" plane we will need to tell SOHO # to generate these properties when outputting object. Look for # the "Op_Id" variable being exported and if so enable operator id # generation for aov in flattenedList(aovs): if aov.variable == "Op_Id": IFDapi.ray_comment("Forcing object id generation") IFDsettings._GenerateOpId = True break
def addRenderPlanes(wrangler, cam, now): """Adds deep rasters as defined by a json file. Args: wrangler : (Object) A wrangler object, if any. cam : (soho.SohoObject) The camera being rendered. now : (float) The parameter evaluation time. Raises: N/A Returns: None """ import soho # Check if automatic planes should be disabled. if _disablePlanes(wrangler, cam, now): return # The parameter that defines which automatic planes to add. parms = {"auto_planes": soho.SohoParm("auto_planes", "str", [""])} # Attempt to evaluate the parameter. plist = cam.wrangle(wrangler, parms, now) # Parameter exists. if plist: # Get the string value. planeStr = plist["auto_planes"].Value[0] if planeStr: # Split the string to get the group names. planeList = planeStr.split() # Build all existing groups. groups = buildPlaneGroups() # For each group available, if it matches the selection of groups # to add, write the planes to the ifd. for group in groups: if group.name in planeList: group.writePlanesToIfd(wrangler, cam, now)
def output_materials(obj, wrangler, now): """Output Materials for an object The shop_materialpath parameter and shop_materialpath prim attribute are both checked for output. """ # We use a shaderhandle instead of a string so Soho instances are properly # resolved when Full Instancing is used. parms = [soho.SohoParm('shop_materialpath', 'shaderhandle', skipdefault=False)] eval_parms = obj.evaluate(parms, now) if eval_parms: shop = eval_parms[0].Value[0] if shop: wrangle_shading_network(shop) soppath = [] if not obj.evalString('object:soppath', now, soppath): return soppath = soppath[0] gdp = SohoGeometry(soppath, now) global_material = gdp.globalValue('shop_materialpath') if global_material is not None: wrangle_shading_network(global_material[0]) attrib_h = gdp.attribute('geo:prim', 'shop_materialpath') if attrib_h >= 0: shop_materialpaths = gdp.attribProperty(attrib_h, 'geo:allstrings') for shop in shop_materialpaths: wrangle_shading_network(shop) # TODO / CONSIDER, for very large number of instance objects it might speed things # up to cache the fact we've already visited a source network. Store in scenestate? # (This will avoid much of the below on a per instance basis) instance_info = get_full_instance_info(obj) if instance_info is not None: instance_source = soho.getObject(instance_info.source) sourcesop_path = [] if not instance_source.evalString('object:soppath', now, sourcesop_path): return sourcesop_path = sourcesop_path[0] gdp = SohoGeometry(sourcesop_path, now) attrib_h = gdp.attribute('geo:point', 'shop_materialpath') if attrib_h >= 0: shop_materialpaths = gdp.attribProperty(attrib_h, 'geo:allstrings') for shop in shop_materialpaths: wrangle_shading_network(shop) return
def _disablePlanes(wrangler, cam, now): import soho # The parameter that defines if planes should be disabled or not. parms = {"disable": soho.SohoParm("disable_auto_planes", "int", [False])} # Attempt to evaluate the parameter. plist = cam.wrangle(wrangler, parms, now) # Parameter exists. if plist: # If the parameter is set, return True to disable the planes. if plist["disable"].Value[0] == 1: return True return False
def writeToIfd(self, wrangler, cam, now): """Output the AOV.""" import soho # The base data to pass along. data = self.getData() channel = self.channel # If there is no explicit channel set, use the variable name. if channel is None: channel = self.variable # Handle exporting of multiple components if self.componentexport: components = self.components # If no components are explicitly set on the AOV, use the # vm_exportcomponents parameter from the Mantra ROP. if not components: parms = { "components": soho.SohoParm("vm_exportcomponents", "str", [""], skipdefault=False), } plist = cam.wrangle(wrangler, parms, now) if plist: components = plist["vm_exportcomponents"].Value[0] components = components.split() # Create a unique channel for each component and output the block. for component in components: data["channel"] = "{}_{}".format(channel, component) data["component"] = component self._lightExportPlanes(data, wrangler, cam, now) else: # Update the data with the channel. data["channel"] = channel self._lightExportPlanes(data, wrangler, cam, now)
P *= cam_matrix.inverted() P *= projection_matrix P[0] = (P[0] / (P[3] * 2)) + .5 P[1] = (P[1] / (P[3] * 2)) + .5 P[2] /= P[3] P[3] = 1.0 P = hou.Vector3(P) return P node = hou.pwd() module = node.hm() controlParameters = { 'now': soho.SohoParm('state:time', 'real', [0], False, key='now'), 'fps': soho.SohoParm('state:fps', 'real', [24], False, key='fps'), 'camera': soho.SohoParm('camera', 'string', ['/obj/cam1'], False), 'vm_picture': soho.SohoParm('vm_picture', 'string', ['$HIP/render/$HIPNAME.$OS.$F4.svg'], False), 'render_viewcamera': soho.SohoParm('render_viewcamera', 'bool', [True], False), 'projection_attribute': soho.SohoParm('projection_attribute', 'string', ['uv'], False), 'attribute_rendering_resolution': soho.SohoParm('attribute_rendering_resolution', 'int', [1024, 1024], False), 'attribute_scale_by_resolution':
# # # \file pxh_usdlayeringROP.py # \brief soho script to insert/remove usd sublayers # import hou import os import soho ################################################################################ # parameters ################################################################################ parameterDefines = { 'trange': soho.SohoParm('trange', 'int', [0], False), 'f': soho.SohoParm('f', 'real', [1, 1, 1], False), 'irange': soho.SohoParm('irange', 'int', [0, 0, 1], False), 'now': soho.SohoParm('state:time', 'real', [0], False, key='now'), 'fps': soho.SohoParm('state:fps', 'real', [24.0], False, key='fps'), } for i in range(1, 6): parameterDefines['sourcefile' + str(i)] = soho.SohoParm( 'sourcefile' + str(i), 'string', [''], False) parameterDefines['operation' + str(i)] = soho.SohoParm( 'operation' + str(i), 'int', [0], False) parameterDefines['destfile' + str(i)] = soho.SohoParm( 'destfile' + str(i), 'string', [''], False) ################################################################################ # main
if refLayer.HasDefaultPrim(): defaultPrim = refLayer.defaultPrim if len(refLayer.rootPrims) > 0: firstRoot = refLayer.rootPrims[0].path else: print("opening %s failed" % fileName) return (frameRange, defaultPrim, firstRoot) ############################################################################### # parameters ############################################################################### parameterDefines = { 'f': soho.SohoParm('f', 'real', [1, 1, 1], False), 'now': soho.SohoParm('state:time', 'real', [0], False, key='now'), 'destfile': soho.SohoParm('destfile', 'string', [''], False), 'path': soho.SohoParm('path', 'string', [''], False), 'reffile': soho.SohoParm('reffile', 'string', [''], False), } parameters = soho.evaluate(parameterDefines) # # init soho # now = parameters['now'].Value[0] soho.initialize(now, '') soho.lockObjects(now)
def output_materials(obj, wrangler, now, skip_included=False): """Output Materials for an object The shop_materialpath parameter and shop_materialpath prim attribute are both checked for output. """ # We use a shaderhandle instead of a string so Soho instances are properly # resolved when Full Instancing is used. parms = { "shop_materialpath": soho.SohoParm("shop_materialpath", "shaderhandle", skipdefault=False), "pbrt_include": soho.SohoParm("pbrt_include", "string", [""], skipdefault=True), "pbrt_import": soho.SohoParm("pbrt_import", "string", [""], skipdefault=True), } eval_parms = obj.evaluate(parms, now) if "shop_materialpath" in eval_parms: shop = eval_parms["shop_materialpath"].Value[0] if shop: wrangle_shading_network(shop) # If this object uses either an include or import statement then we assume internal # material definitions are already resolved through other means. if skip_included and ("pbrt_include" in eval_parms or "pbrt_import" in eval_parms): return soppath = [] if not obj.evalString("object:soppath", now, soppath): return soppath = soppath[0] gdp = SohoGeometry(soppath, now) global_material = gdp.globalValue("shop_materialpath") if global_material is not None: wrangle_shading_network(global_material[0]) attrib_h = gdp.attribute("geo:prim", "shop_materialpath") if attrib_h >= 0: shop_materialpaths = gdp.attribProperty(attrib_h, "geo:allstrings") for shop in shop_materialpaths: wrangle_shading_network(shop) # TODO / CONSIDER, for very large number of instance objects it might speed things # up to cache the fact we've already visited a source network. # Store in scenestate? # (This will avoid much of the below on a per instance basis) instance_info = get_full_instance_info(obj, now) if instance_info is None: return attrib_h = instance_info.gdp.attribute("geo:point", "shop_materialpath") if attrib_h >= 0: shop_materialpaths = instance_info.gdp.attribProperty( attrib_h, "geo:allstrings") for shop in shop_materialpaths: wrangle_shading_network(shop) return
p1 = s1.split('/') p2 = s2.split('/') for i, c in enumerate(p1): if c != p2[i]: return '/'.join(p1[:i]) return s1 ############################################################################### # parameters ############################################################################### parameterDefines = { 'ropname': soho.SohoParm('object:name', 'string', key='ropname'), 'trange': soho.SohoParm('trange', 'int', [0], False), 'f': soho.SohoParm('f', 'real', [1, 1, 1], False), 'fps': soho.SohoParm('state:fps', 'real', [24.0], False, key='fps'), 'now': soho.SohoParm('state:time', 'real', [0], False, key='now'), 'sourcefiles': soho.SohoParm('sourcefiles', 'string', [], False), 'outfile': soho.SohoParm('outfile', 'string', [''], False), } def main(): parameters = soho.evaluate(parameterDefines) # # init soho
def wrangle_geo(obj, wrangler, now): parm_selection = { "object:soppath": SohoPBRT("object:soppath", "string", [""], skipdefault=False), "ptinstance": SohoPBRT("ptinstance", "integer", [0], skipdefault=False), # NOTE: In order for shop_materialpath to evaluate correctly when using # (full) instancing shop_materialpath needs to be a 'shaderhandle' # and not a 'string' # NOTE: However this does not seem to apply to shop_materialpaths on the # instance points and has to be done manually "shop_materialpath": SohoPBRT( "shop_materialpath", "shaderhandle", skipdefault=False ), "soho_precision": SohoPBRT("soho_precision", "integer", [9], False), "pbrt_rendersubd": SohoPBRT("pbrt_rendersubd", "bool", [False], False), "pbrt_subdlevels": SohoPBRT( "pbrt_subdlevels", "integer", [3], False, key="levels" ), "pbrt_computeN": SohoPBRT("pbrt_computeN", "bool", [True], False), "pbrt_reverseorientation": SohoPBRT( "pbrt_reverseorientation", "bool", [False], True ), "pbrt_matchhoudiniuv": SohoPBRT("pbrt_matchhoudiniuv", "bool", [True], False), # The combination of None as a default as well as ignore defaults being False # is important. 'None' implying the parm is missing and not available, # and '' meaning a vacuum medium. # We can't ignore defaults since a default might be the only way to set a # medium back to a vacuum. "pbrt_interior": SohoPBRT("pbrt_interior", "string", [None], False), "pbrt_exterior": SohoPBRT("pbrt_exterior", "string", [None], False), "pbrt_ignorevolumes": SohoPBRT("pbrt_ignorevolumes", "bool", [False], True), "pbrt_ignorematerials": SohoPBRT("pbrt_ignorematerials", "bool", [False], True), "pbrt_splitdepth": SohoPBRT( "pbrt_splitdepth", "integer", [3], True, key="splitdepth" ), "pbrt_emissionfilename": SohoPBRT( "pbrt_emissionfilename", "string", [""], True ), "pbrt_curvetype": SohoPBRT("pbrt_curvetype", "string", ["flat"], True), "pbrt_include": SohoPBRT("pbrt_include", "string", [""], False), "pbrt_import": SohoPBRT("pbrt_import", "string", [""], False), "pbrt_alpha_texture": SohoPBRT( "pbrt_alpha_texture", "string", [""], False, key="alpha" ), "pbrt_allow_geofiles": soho.SohoParm( "pbrt_allow_geofiles", "integer", [1], False ), "pbrt_geo_location": soho.SohoParm( "pbrt_geo_location", "string", ["geometry"], False ), "pbrt_geofile_threshold": soho.SohoParm( "pbrt_geofile_threshold", "integer", [10000], False ), "pbrt_renderpoints": soho.SohoParm("pbrt_renderpoints", "bool", [False], False), } properties = obj.evaluate(parm_selection, now) if "shop_materialpath" not in properties: shop = "" else: shop = properties["shop_materialpath"].Value[0] # NOTE: Having to track down shop_materialpaths does not seem to be a requirement # with Mantra or RenderMan. Either its because I'm missing some # logic/initialization either in Soho or in the Shading HDAs. Or there is # some hardcoding in the Houdini libs that know how to translate # shop_materialpath point aassignments to shaders directly through a # SohoParm. Until that is figured out, we'll have to do it manually. interior = None exterior = None if "pbrt_interior" in properties: interior = properties["pbrt_interior"].Value[0] if "pbrt_exterior" in properties: exterior = properties["pbrt_exterior"].Value[0] if "pbrt_reverseorientation" in properties: if properties["pbrt_reverseorientation"].Value[0]: api.ReverseOrientation() pt_shop_found = False if properties["ptinstance"].Value[0] == 1: instance_info = PBRTinstancing.get_full_instance_info(obj, now) properties[".instance_info"] = instance_info if instance_info is not None: pt_shop_found = process_full_pt_instance_material(instance_info) interior, interior_paramset = process_full_pt_instance_medium( instance_info, "interior" ) exterior, exterior_paramset = process_full_pt_instance_medium( instance_info, "exterior" ) if interior_paramset is not None: properties[".interior_overrides"] = interior_paramset # If we found a point shop, don't output the default one here. if shop in scene_state.shading_nodes and not pt_shop_found: api.NamedMaterial(shop) # We only output a MediumInterface if one or both of the parms exist if interior is not None or exterior is not None: interior = "" if interior is None else interior exterior = "" if exterior is None else exterior api.MediumInterface(interior, exterior) alpha_tex = properties["alpha"].Value[0] alpha_node = BaseNode.from_node(alpha_tex) if ( alpha_node and alpha_node.directive == "texture" and alpha_node.output_type == "float" ): if alpha_node.path not in scene_state.shading_nodes: suffix = ":%s" % obj.getName() alpha_tex = "%s%s" % (alpha_tex, suffix) properties["alpha"].Value[0] = alpha_tex wrangle_shading_network( alpha_node.path, name_suffix=suffix, exported_nodes=set() ) else: # If the passed in alpha_texture wasn't valid, clear it so we don't add # it to the geometry if alpha_tex: api.Comment("%s is an invalid float texture" % alpha_tex) properties["alpha"].Value[0] = "" if properties["pbrt_import"].Value[0]: # If we have included a file, skip output any geo. api.Import(properties["pbrt_import"].Value[0]) return if properties["pbrt_include"].Value[0]: # If we have included a file, skip output any geo. api.Include(properties["pbrt_include"].Value[0]) return soppath = properties["object:soppath"].Value[0] if not soppath: api.Comment("Can not find soppath for object") return shutter_times = wrangle_motionblur(obj, now) if shutter_times is not None: times = (shutter_times.open, shutter_times.close) else: times = (now,) if properties["pbrt_renderpoints"].Value[0]: PBRTgeo.output_pts(soppath, times, properties) else: PBRTgeo.output_geo(soppath, now, properties) return