def pack_geo(geo, name=None, xform=None): pack_verb = hou.sopNodeTypeCategory().nodeVerb('pack') pack_verb.setParms({'createpath': 0, 'pivot': 0, 'viewportlod': 'box'}) packed_geo = hou.Geometry() pack_verb.execute(packed_geo, [geo]) name_atr = packed_geo.addAttrib(hou.attribType.Prim, 'name', '', create_local_variable=False) for prim in packed_geo.prims(): if name is not None: prim.setAttribValue(name_atr, name) if xform is not None: prim.setTransform(xform) return packed_geo
def createFrustumGeometry(): geo = hou.Geometry() tube_verb = hou.sopNodeTypeCategory().nodeVerb("tube") hou.SopVerb.setParms( tube_verb, { 'type': 1, 'cap': 1, 'vertexnormals': 1, 't': (0, 0, 0.25), 'r': (-90, 0, 0), 'rad': (0.5, 1), 'height': 0.5, 'cols': 10 }) hou.SopVerb.execute(tube_verb, geo, []) return geo
def load(node, geo, path): nodePath = node.path() function = inspect.stack()[0][3] try: missingframe = node.evalParm("missingframe") try: _geo = hou.Geometry() _geo.loadFromFile(path) geo.merge(_geo) except hou.OperationFailed: print("Could not load: " + path) except hou.GeometryPermissionError: print("Permissions Issue, are the files locked?") except (KeyboardInterrupt, SystemExit): print "Interrupt requested of " + function + " for " + nodePath + "...exiting" return
def createVisPoint(self, i): self.point = hou.Geometry() u = self.node.parm('{}{}pos'.format(self.ramp_name, i + 1)).eval() pos = self.prim.positionAt(u) pt = self.point.createPoint() pt.setPosition(pos) self.point_vis = self.state_gadgets["point_vis"] self.point_vis.setGeometry(self.point) self.point_vis.setParams({ "radius": 10, "draw_color": [1, 1, 0, 1], "locate_color": [1, 0, 0, 1], "pick_color": [1, 1, 0, 1] })
def build_element_geo(self, variant=None): logging.info('Building element geo for %s', self.name) name = self.name element_dict = self.json_data if variant: name = variant logging.info('Constructing variant %s', name) if variant != 'base': element_dict = self.json_data['variants'][variant] else: # We don't need the transform matrix if we are a variant del element_dict['transformMatrix'] geo = self.build_geo(name, element_dict) # If this was a variant exit out as we are done, # other wise keep on building any potential instance copies if variant: return geo out_geo = hou.Geometry() # We merge in the base geo out_geo.merge(geo) # Build instancedCopies for name, instance_dict in self.json_data.get('instancedCopies', {}).iteritems(): logging.info('Creating instance copy for %s', name) if (not instance_dict.get('instancedPrimitiveJsonFiles') and not instance_dict.get('geomObjFile')): # No overrides of instance prims or geom so we can just copy the pack for prim in geo.prims(): prim.setAttribValue('name', name) prim.setTransform(self.get_xform(instance_dict)) out_geo.merge(geo) else: instance_geo = self.build_geo(name, instance_dict) out_geo.merge(instance_geo) instance_geo.clear() geo.clear() return out_geo
def test_copyPointAttributeValues(self): source = getObjGeo("test_copyPointAttributeValues") attribs = source.pointAttribs() geo = hou.Geometry() p1 = geo.createPoint() p2 = geo.createPoint() p1.copyAttribValues(source.iterPoints()[2], attribs) p2.copyAttribValues(source.iterPoints()[6], attribs) # Ensure all the attributes got copied right. self.assertEqual(len(geo.pointAttribs()), len(attribs)) # Ensure P got copied right. self.assertEqual(p1.position(), hou.Vector3(5, 0, -5)) self.assertEqual(p2.position(), hou.Vector3(-5, 0, 5))
def test_copyPrimAttributeValues(self): source = getObjGeo("test_copyPrimAttributeValues") attribs = source.primAttribs() geo = hou.Geometry() p1 = geo.createPolygon() p2 = geo.createPolygon() p1.copyAttribValues(source.iterPrims()[1], attribs) p2.copyAttribValues(source.iterPrims()[4], attribs) # Ensure all the attributes got copied right. self.assertEqual(len(geo.primAttribs()), len(attribs)) # Ensure P got copied right. self.assertEqual(p1.attribValue("prnum"), 1) self.assertEqual(p2.attribValue("prnum"), 4)
def build_instanceprims(self, instance_dict): logging.info('Handling instancedPrimitiveJsonFiles') json_geo = hou.Geometry() for name, instance_prim in instance_dict.iteritems(): logging.info('instancedPrimitiveJsonFiles: %s', name) if instance_prim['type'] == 'archive': json_prim = ArchivePrims(self, name, instance_prim) elif instance_prim['type'] == 'curve': json_prim = CurvePrims(self, name, instance_prim) elif instance_prim['type'] == 'element': json_prim = ElementPrims(self, name, instance_prim) else: logging.info('Unknown instance_prim type, %s, skipping', instance_prim['type']) continue prim_geo = json_prim.build_geo() json_geo.merge(prim_geo) prim_geo.clear() return json_geo
def test_setSharedPointStringAttribGroup(self): TARGET = ["point0"] * 5 + [""] * 5 geo = hou.Geometry() attr = geo.addAttrib(hou.attribType.Point, "test", "") geo.createPoints(5) group = geo.createPointGroup("group1") for point in geo.points(): group.add(point) geo.createPoints(5) geo.setSharedPointStringAttrib(attr.name(), "point0", group) vals = [point.attribValue(attr) for point in geo.points()] self.assertEqual(vals, TARGET)
def createPoints(self): self.point_handle = hou.Geometry() rampKeys = self.ramp_parm.eval().keys() numPoints = len(rampKeys) for i in range(numPoints): u = self.node.parm('{}{}pos'.format(self.ramp_name, i + 1)).eval() pos = self.prim.positionAt(u) pt = self.point_handle.createPoint() pt.setPosition(pos) self.point_gadget = self.state_gadgets["point_gadget"] self.point_gadget.setGeometry(self.point_handle) self.point_gadget.setParams({ "radius": 10, "draw_color": [0, 0.5, 1, 1], "locate_color": [0, 0.5, 1, 1], "pick_color": [0, 0.5, 1, 1] })
def __init__(self, sceneviewer): self.scene_viewer = sceneviewer self.knob_geo = hou.Geometry() self.knob_pt = self.knob_geo.createPoint() self.knob_drawable = hou.GeometryDrawable( self.scene_viewer, hou.drawableGeometryType.Point, "highlighter_knob", params={ 'style': hou.drawableGeometryPointStyle.SmoothCircle, 'color1': hou.Vector4(1.0, 1.0, 1.0, 1.0), 'radius': 8, 'fade_factor': 0.5 }) self.knob_drawable.setGeometry(self.knob_geo) self.show(False)
def highlightPoint(self, point_num, position): ### Display a pystate drawable at a points position if point_num != -1: if point_num != self.currentPoint: ### We're only updating currentPoint when it is different to minimize update calls to Drawables. self.currentPoint = point_num #u = self.geometry.prim(self.currentPrimid).attribValueAtInterior("u", self.currentPrimu, 0, 0) #u = self.geometry.point(self.currentPoint).attribValue("u") #self.cursor_text = "<font size=4,>%f</font>" % (u) new_geo = hou.Geometry() point = new_geo.createPoint() point.setPosition(position) # update the drawable self.poly_guide.setGeometry(new_geo) self.showGuides(True) else: self.currentPoint = -1 self.poly_geo = None self.showGuides(False)
def output_geo(soppath, now, properties=None): """Output the geometry by calling the appropriate wrangler Geometry is partitioned into subparts based on the shop_materialpath and material_override prim attributes. Args: soppath (str): oppath to SOP properties (dict, None): Dictionary of SohoParms (Optional, defaults to None) Returns: None """ # split by material # split by geo type # if mesh type, split by material override # else deal with overrides per prim # # NOTE: We won't be splitting based on medium interior/exterior # those will be left as a object level assignment only. # Note, that in the case of Houdini Volumes they will look # for the appropriate medium parameters as prim vars if properties is None: properties = {} ignore_materials = False if "pbrt_ignorematerials" in properties: ignore_materials = properties["pbrt_ignorematerials"].Value[0] # Houdini / Mantra allows for shop_materialpaths on both prims and details # at the same time. However prims full stomp over detail. If you have a prim # with an empty material assignment, it will NOT fall back to the detail # assignment. (It will fall back to the object since that is further up the # stack). This means if the shop_materialpath exists on the prim, the # detail is ignored entirely. # PBRT allows setting Material parameters on the Shapes in order to # override a material's settings. (Shapes get checked first) # This paramset will be for holding those overrides and passing # them down to the actual shape api calls. # We need the soppath to come along and since we are creating new # hou.Geometry() we'll lose the original sop connection so we need # to stash it here. node = hou.node(soppath) if node is None or node.type().category() != hou.sopNodeTypeCategory(): return input_gdp = node.geometry() if input_gdp is None: return gdp = hou.Geometry() gdp.merge(input_gdp.freeze()) default_material = "" default_override = "" if not ignore_materials: try: default_material = gdp.stringAttribValue("shop_materialpath") except hou.OperationFailed: pass if default_material not in scene_state.shading_nodes: default_material = "" try: default_override = gdp.stringAttribValue("material_override") except hou.OperationFailed: default_override = "" # These handles are only valid until until we clear the geo prim_material_h = gdp.findPrimAttrib("shop_materialpath") prim_override_h = gdp.findPrimAttrib("material_override") has_prim_overrides = bool(not ignore_materials and prim_override_h is not None and prim_material_h is not None) if prim_material_h is not None and not ignore_materials: material_gdps = partition_by_attrib(gdp, prim_material_h) gdp.clear() else: material_gdps = {default_material: gdp} # The gdp these point to may have been cleared del prim_override_h del prim_material_h for material, material_gdp in material_gdps.iteritems(): if material not in scene_state.shading_nodes: material = "" material_node = None else: api.AttributeBegin() api.NamedMaterial(material) material_node = MaterialNode(material) shape_gdps = partition_by_attrib(material_gdp, "typename", intrinsic=True) material_gdp.clear() for shape, shape_gdp in shape_gdps.iteritems(): # Aggregate overrides, instead of per prim if has_prim_overrides and requires_override_partition(shape): override_attrib_h = shape_gdp.findPrimAttrib( "material_override") override_gdps = partition_by_attrib(shape_gdp, override_attrib_h) shape_gdp.clear() del override_attrib_h # We don't the wranglers to handle the overrides since we are doing it # here. So we'll set this to false, which will mean the override_node # is None and not trigger per prim overrides has_prim_overrides = False else: override_gdps = {default_override: shape_gdp} for override, override_gdp in override_gdps.iteritems(): override_paramset = ParamSet() if override and material_node is not None: # material parm overrides are only valid for MaterialNodes override_paramset |= material_node.override_paramset( override) if has_prim_overrides: override_node = material_node else: override_node = None # At this point the gdps are partitioned first by material # then by type. And then if its in requires_override_partition # it has been further partitioned. # The implies that we will NOT have varying types or materials # past this point. The wranglers will need to know the following- # * is there a prim override? # * is the material valid? # * the material_node itself to apply overrides if they exist # # The only case where we *need* to pass down the override info is if # * the material_node is valid # * material_overrides exists # # We don't want to reconstruct a new material_node for every prim # as it will be constant. # # Option 1: <selected> # We can pass a material_node only if we need to apply overrides # but that gives variable dual meaning. # Option 2: # Alternatively we can pass the material_node and also a # prim_overrides flag either in the properties or as its own function # arg. shape_wrangler = shape_wranglers.get(shape, not_supported) if shape_wrangler: shape_wrangler(override_gdp, override_paramset, properties, override_node) override_gdp.clear() if material: api.AttributeEnd() return
def test_setPointStringAttribValuesInvalidAttribute(self): TARGET = ('point0', 'point1', 'point2', 'point3', 'point4') geo = hou.Geometry() self.assertRaises(hou.OperationFailed, geo.setPointStringAttribValues, "test", TARGET)
def onGenerate(self, item_holder, upstream_items, generation_type): # static parms MULTILAYER = ("RGB", "RGBA", "P", "CMYK", "YCbCr", "LAB", "HSV") SINGLELAYER = ("1", "L", "I", "F") BIT32 = ("I", "F") BIT8 = ("L" ,"P", "RGB", "RGBA", "P", "CMYK", "YCbCr", "LAB", "HSV") BIT1 = ("1") CONVERT32 = 65535.0 CONVERT8 = 255.0 node = hou.nodeBySessionId(self.customId) isprintlog = node.parm("isprintlog").eval() issetattribute = node.parm("setattribute").eval() attributeName = node.parm("nofileattribute").evalAsString() hasher = hashlib.md5() def createHeightFieldGeometry(name, size, center, rotate, heightscale=1, moveheight=0, isFileExists=0, filepath="", initval=0): ''' create HeightField Geometry from file ''' # init geometry fileerror = False geo = hou.Geometry().freeze() geo.addAttrib(hou.attribType.Prim, "name", "") halfsize = size * 0.5 bounds = hou.Geometry().boundingBox() bounds.setTo((-halfsize, -halfsize, -0.5, halfsize, halfsize, 0.5)) # init volume vol = geo.createVolume(size, size, 1, bounds) vol.setAttribValue("name", name) im_hash = "-1" if isFileExists: # read landscape/masks try: im = Image.open(filepath) im = im.transpose(Image.TRANSPOSE) # check image size if im.size[0] != size or im.size[1] != size: im = im.resize((size, size)) # save as image numpy array pix im_hash = hashlib.md5(im.tobytes()).hexdigest() im_hash = str(im_hash) immode = im.mode if immode in SINGLELAYER: if immode in BIT32: pix = np.asarray(im) / CONVERT32 elif immode in BIT8: pix = np.asarray(im) / CONVERT8 else: pix = np.asarray(im) # im_hash = str(im_hash) except: fileerror = True pix = np.full((size, size), initval) else: pix = np.full((size, size), initval) # set pix to volume vol.setAllVoxels((pix*heightscale+moveheight).flatten()) # transform geometry rotationMtx = hou.hmath.buildRotate(-90,-90,0) transformMtx = hou.hmath.buildTranslate(center[0],0,center[1]) geo.transform(rotationMtx) geo.transform(transformMtx) return geo, fileerror, im_hash E = lambda p : node.parm(p).eval() # gather parameters size = node.parm("size").evalAsInt() filepath = node.parm("filepath").evalAsString() center = node.parmTuple('t').eval() rotate = E('rotate') heightscale = E('heightscale') moveheight = E('moveheight') iffilenotexist = E('iffilenotexist') # 0 -> report error # 1 -> set black # 2 -> set white # 3 -> set value setvalue = E('setvalue') # only if iffilenotexist == 3 loadtype = E("loadtype") # 0 -> create heightfield from scrach # 1 -> load to upstream heightfield createtype = E("type") # 0 -> heightfield, # 1 -> mask layername = E("layer") # if load to upstream heightfield, set custom mask name layermode = E("layermode") # 0 -> replace # 1 -> add # 2 -> subtract # 3 -> difference # 4 -> multiply # 5 -> maximum # 6 -> minimum bordertype = E("layerborder") # 0 -> constant # 1 -> repeat # 2 -> streak borderval = E("layerborderval") # only if bordertype == 0 is_set_hash = E("issethash") hash_attrib = E("hashattributename") is_add_hash = E("isaddhash") add_hash_attrib = E("addhashattrib") for upstream_item in upstream_items: fileerror = False # check if file exist isfileexists = checkfile(filepath) initval = 0 if not isfileexists: if iffilenotexist == 0: raise IOError("File not found! Please check your file {0}".format(filepath)) elif iffilenotexist == 2: initval = 1 elif iffilenotexist == 3: initval = setvalue # do works ## node verb for border type (primitive node) maskprimitiveVerb = createVolumePrimitiveVerb("mask") im_hash = -1 if loadtype == 0: heightfieldpeimitiveVerb = createVolumePrimitiveVerb("height") if createtype == 0: name = "height" heightfield, fileerror, im_hash = createHeightFieldGeometry(name, size, center, rotate, heightscale, moveheight, isfileexists, filepath, initval) masklayer, maskerror, _ = createHeightFieldGeometry("mask", size, center, rotate) else: name = "mask" masklayer, fileerror, im_hash = createHeightFieldGeometry(name, size, center, rotate, heightscale, moveheight, isfileexists, filepath, initval) heightfield, maskerror, _ = createHeightFieldGeometry("height", size, center, rotate) heightfieldpeimitiveVerb.execute(heightfield, [heightfield]) maskprimitiveVerb.execute(masklayer, [masklayer]) heightfield.merge(masklayer) else: heightfield = hou.Geometry().freeze() heightfield.loadFromFile(upstream_item.resultData[0][0]) name = layername additionallayer, fileerror, im_hash = createHeightFieldGeometry(name, size, center, rotate, heightscale, moveheight, isfileexists, filepath, initval) additionalPrimitiveVerb = createVolumePrimitiveVerb(name, bordertype, borderval) additionalPrimitiveVerb.execute(additionallayer, [additionallayer]) ismergelayer = 0 for layer in heightfield.prims(): if layer.stringAttribValue("name") == name: ismergelayer = 1 voxels = additionallayer.prims()[0] if layermode == 0: # 0 -> replace layer.setAllVoxels(voxels.allVoxels()) else: in_voxelArray = np.asanyarray(layer.allVoxels) blend_voxelArray = np.asanyarray(voxels.allVoxels) if layermode == 1: # 1 -> add layer.setAllVoxels((in_voxelArray+blend_voxelArray).flatten()) elif layermode == 2: # 2 -> subtract layer.setAllVoxels((in_voxelArray-blend_voxelArray).flatten()) elif layermode == 3: # 3 -> difference layer.setAllVoxels(np.absolute(in_voxelArray-blend_voxelArray).flatten()) elif layermode == 4: # 4 -> multiply layer.setAllVoxels((in_voxelArray*blend_voxelArray).flatten()) elif layermode == 5: # 5 -> maximum layer.setAllVoxels(np.maximum(in_voxelArray+blend_voxelArray).flatten()) elif layermode == 6: # 6 -> minimum layer.setAllVoxels(np.minimum(in_voxelArray+blend_voxelArray).flatten()) if ismergelayer == 0: heightfield.merge(additionallayer) ## node verb for visulization (volumevisualization node) heightfieldVisVerb = createHeightFieldVisVerb() heightfieldVisVerb.execute(heightfield, [heightfield]) work_item = item_holder.addWorkItem(cloneResultData=False, preserveType=True, parent=upstream_item) if is_set_hash: if is_add_hash: im_hash = "%x" % (int(im_hash, 16) + int(add_hash_attrib, 16)) work_item.data.setString(hash_attrib, im_hash, 0) outputfile = node.parm('outputfile').unexpandedString() outputfile = outputfile.replace("`@{0}`".format(hash_attrib), im_hash) outputfile = hou.expandString(outputfile) else: outputfile = E('outputfile') # self.scheduler.localizePath(work_item.resultData[0][0]) makeoutputpathsafe(outputfile) heightfield.saveToFile(outputfile) work_item.addResultData(outputfile, "file/geo", 0) if not isfileexists: if isprintlog: print "File not found: {0}".format(filepath) if issetattribute: work_item.data.setInt(attributeName, 1, 0) else: if issetattribute: if fileerror: work_item.data.setInt(attributeName, 1, 0) else: work_item.data.setInt(attributeName, 0, 0) return pdg.result.Success
def output_geo(soppath, now, properties=None): """Output the geometry by calling the appropriate wrangler Geometry is partitioned into subparts based on the shop_materialpath and material_override prim attributes. Args: soppath (str): oppath to SOP properties (dict, None): Dictionary of SohoParms (Optional, defaults to None) Returns: None """ # split by material # split by material override # # split by geo type # NOTE: We won't be splitting based on medium interior/exterior # those will be left as a object level assignment only. # Note, that in the case of Houdini Volumes they will look # for the appropriate medium parameters as prim vars if properties is None: properties = {} ignore_materials = False if 'pbrt_ignorematerials' in properties: ignore_materials = properties['pbrt_ignorematerials'].Value[0] # PBRT allows setting Material parameters on the Shapes in order to # override a material's settings. (Shapes get checked first) # This paramset will be for holding those overrides and passing # them down to the actual shape api calls. material_paramset = ParamSet() # We need the soppath to come along and since we are creating new # hou.Geometry() we'll lose the original sop connection so we need # to stash it here. node = hou.node(soppath) if node is None or node.type().category() != hou.sopNodeTypeCategory(): return input_gdp = node.geometry() if input_gdp is None: return gdp = hou.Geometry() gdp.merge(input_gdp.freeze()) # Partition based on materials global_material = None if not ignore_materials: try: global_material = gdp.stringAttribValue('shop_materialpath') except hou.OperationFailed: pass attrib_h = gdp.findPrimAttrib('shop_materialpath') if attrib_h is not None and not ignore_materials: material_gdps = partition_by_attrib(gdp, attrib_h) else: material_gdps = {global_material: gdp} global_override = None if not ignore_materials: try: global_override = gdp.stringAttribValue('material_override') except hou.OperationFailed: pass # Further partition based on material overrides has_prim_overrides = bool( not ignore_materials and gdp.findPrimAttrib('material_override') is not None) for material in material_gdps: if material: api.AttributeBegin() api.NamedMaterial(material) material_gdp = material_gdps[material] #api.Comment('%s %i' % (material_gdp,len(material_gdp.prims()))) if has_prim_overrides: attrib_h = material_gdp.findPrimAttrib('material_override') override_gdps = partition_by_attrib(material_gdp, attrib_h) # Clean up post partition material_gdp.clear() else: override_gdps = {global_override: material_gdp} for override in override_gdps: override_gdp = override_gdps[override] #api.Comment(' %s %i' % (override_gdp, len(override_gdp.prims()))) shape_gdps = partition_by_attrib(override_gdp, 'typename', intrinsic=True) override_gdp.clear() for shape in shape_gdps: material_paramset = ParamSet() if override and material: material_paramset.update( override_to_paramset(material, override)) shape_gdp = shape_gdps[shape] #api.Comment(' %s %i' % (shape_gdp, len(shape_gdp.prims()))) shape_wrangler = shape_wranglers.get(shape, not_supported) if shape_wrangler: shape_wrangler(shape_gdp, material_paramset, properties) shape_gdp.clear() if material: api.AttributeEnd() return
def test_createPointsInvalidNumber(self): geo = hou.Geometry() self.assertRaises(hou.OperationFailed, geo.createPoints, -4)
def test_createPoints(self): geo = hou.Geometry() points = geo.createPoints(15) self.assertEqual(points, geo.points())
def test_createPoint(self): geo = hou.Geometry() point = geo.createPoint(hou.Vector3(1, 2, 3)) self.assertEqual(point.position(), hou.Vector3(1, 2, 3))
def test_isReadOnlyFalse(self): geo = hou.Geometry() self.assertFalse(geo.isReadOnly())
def createPointGeometry(): geo = hou.Geometry() hou.Geometry.createPoint(geo) return geo
def createLineGeometry(): geo = hou.Geometry() line_verb = hou.sopNodeTypeCategory().nodeVerb("line") hou.SopVerb.setParms(line_verb, {'dir': (0, 0, 1)}) hou.SopVerb.execute(line_verb, geo, []) return geo
def createSphereGeometry(): geo = hou.Geometry() sphere_verb = hou.sopNodeTypeCategory().nodeVerb("sphere") hou.SopVerb.setParms(sphere_verb, {'type': 2, 'rows': 30, 't': (0, 0, 1)}) hou.SopVerb.execute(sphere_verb, geo, []) return geo
def write_ramp_sketch(self): if len(self.positions) < 2: return positions = np.array([(float(p.x()), float(-p.y())) for p in self.positions]) min_point = positions.min(axis=0) max_point = positions.max(axis=0) ramp_range = max_point - min_point if not np.any((ramp_range == 0.0)): norm_positions = (positions - min_point) / ramp_range geo_points = [] geo_points.append( hou.Vector3(norm_positions[0][0], norm_positions[0][1], 0.0)) left = 0.0 for pt in norm_positions[1:-1]: if pt[0] >= left: left = pt[0] geo_points.append(hou.Vector3(pt[0], pt[1], 0.0)) geo_points.append( hou.Vector3(norm_positions[-1][0], norm_positions[-1][1], 0.0)) ramp_geo = hou.Geometry() # type: hou.Geometry ramp_points = ramp_geo.createPoints(geo_points) ramp_geo.createPolygons((ramp_points, ), False) resample_verb = hou.sopNodeTypeCategory().nodeVerb( "resample") # type: hou.SopVerb resample_verb.setParms({"length": 0.04}) resample_verb.execute(ramp_geo, [ramp_geo]) facet_verb = hou.sopNodeTypeCategory().nodeVerb( "facet") # type: hou.SopVerb facet_verb.setParms({"inline": 1, "inlinedist": 0.003}) facet_verb.execute(ramp_geo, [ramp_geo]) ramp_poly = ramp_geo.prim(0) ramp_points = ramp_poly.points() ramp_basis = hou.rampBasis.BSpline if self.disable_gamma_correction else hou.rampBasis.Linear basis = [] keys = [] values = [] for point in ramp_points: # type: hou.Point basis.append(ramp_basis) pos = point.position() keys.append(pos.x()) values.append(pos.y()) ramp = hou.Ramp(basis, keys, values) self.parm.set(ramp) self.parm.pressButton()
def build_bgeo(obj, bgeo, element_name): """Convert a obj file to a bgeo obj (str): File path to obj (input) bgeo (str): File path to bgeo (output) element_name (str): Name of the element (for material assignments) """ logging.info('Converting %s to %s', obj, bgeo) bgeo_dir = os.path.dirname(bgeo) if not os.path.isdir(bgeo_dir): os.makedirs(bgeo_dir) hier = os.path.splitext(obj)[0] + '.hier' with open(hier, 'rb') as hier_h: hier_data = json.load(hier_h) geo = hou.Geometry() prim_counter = collections.Counter() with make_tempfile() as tmp_obj_h: with ObjReader(obj) as f: for line in f: tmp_obj_h.write(line) tmp_obj_h.close() geo.loadFromFile(tmp_obj_h.name) # If duplication is detected (and verified that there # is an even number of them) delete the back half. num_prims = len(geo.prims()) if f.doubled_geo() and num_prims % 2 == 0: logging.warning('Duplicate geo detected, cleaning!') duped_prims = geo.prims()[num_prims / 2:] geo.deletePrims(duped_prims) # Optional, remove N (normals) as we'll be subdividing #N_atr = geo.findPointAttrib('N') #if N_atr: # N_atr.destroy() name_atr = geo.addAttrib(hou.attribType.Prim, 'name', '', create_local_variable=False) #hier_atr = geo.addAttrib(hou.attribType.Prim, 'hier', '', # create_local_variable=False) facenum_atr = geo.addAttrib(hou.attribType.Prim, 'facenum', 0, create_local_variable=False) for prim in geo.prims(): prim_name = f.prim_names[prim.number()] prim_hier = hier_data.get(prim_name, '') prim.setAttribValue(name_atr, prim_name) material = prim.attribValue('shop_materialpath') material_name = os.path.basename(material) element_material = '/mat/%s.%s' % (element_name, material_name) prim.setAttribValue('shop_materialpath', element_material) #prim.setAttribValue(hier_atr, prim_hier) prim.setAttribValue(facenum_atr, prim_counter[prim_name]) prim_counter[prim_name] += 1 logging.info('Saving out %s', bgeo) geo.saveToFile(bgeo) geo.clear() return prim_counter
def build_geo(self): return hou.Geometry()
def write_color_ramp(self): if len(self.colors) < 2: return color_points = [] vlast_color = hou.Vector3(hou.qt.fromQColor(self.colors[0])[0].rgb()) last_color_index = 0 color_points.append((vlast_color, 0)) # remove same keys in a row for index, color in enumerate(self.colors[1:]): color_index = index + 1 vcolor = hou.Vector3(hou.qt.fromQColor(color)[0].rgb()) dist = vcolor.distanceTo(vlast_color) if dist > TOLERANCE: # if color_index - last_color_index > 1 and dist > SHARP_PRECISION: # color_points.append((hou.Vector3(vlast_color), color_index - 1)) color_points.append((hou.Vector3(vcolor), color_index)) vlast_color = vcolor last_color_index = color_index if color_points[-1][1] < (len(self.colors) - 1): color_points.append( (hou.Vector3(hou.qt.fromQColor(self.colors[-1])[0].rgb()), len(self.colors) - 1)) # Create a polyline representing ramp and remove inline points with Facet SOP points = [color_point[0] for color_point in color_points] pos = [color_point[1] for color_point in color_points] ramp_geo = hou.Geometry() pos_attrib = ramp_geo.addAttrib(hou.attribType.Point, "ramp_pos", 0.0, create_local_variable=False) ramp_points = ramp_geo.createPoints(points) fnum_points = float(len(self.colors) - 1) for ptnum, point in enumerate(ramp_points): # type: (int, hou.Point) point.setAttribValue(pos_attrib, float(pos[ptnum]) / fnum_points) ramp_poly = ramp_geo.createPolygons((ramp_points, ), False)[0] # type: hou.Face facet_verb = hou.sopNodeTypeCategory().nodeVerb( "facet") # type: hou.SopVerb facet_verb.setParms({"inline": 1, "inlinedist": 0.02}) facet_verb.execute(ramp_geo, [ramp_geo]) ramp_poly = ramp_geo.prim(0) ramp_points = ramp_poly.points() linear = hou.rampBasis.Linear basis = [] keys = [] values = [] pos_attrib = ramp_geo.findPointAttrib("ramp_pos") for point in ramp_points: # type: hou.Point basis.append(linear) keys.append(point.attribValue(pos_attrib)) values.append(tuple(point.position())) if not self.disable_gamma_correction: values = [np.power(v, 2.2) for v in values] ramp = hou.Ramp(basis, keys, values) self.parm.set(ramp) self.parm.pressButton()
def trianglemesh_params(mesh_gdp, computeN=True): """Generates a ParamSet for a trianglemesh The following attributes are checked for - P (point), built-in attribute N (vertex/point), float[3] uv (vertex/point), float[3] S (vertex/point), float[3] faceIndices (prim), integer, used for ptex Args: mesh_gdp (hou.Geometry): Input geo computeN (bool): Whether to auto-compute normals if they don't exist Defaults to True Returns: ParamSet of the attributes on the geometry """ mesh_paramset = ParamSet() unique_points = False # Required P_attrib = mesh_gdp.findPointAttrib("P") # Optional N_attrib = mesh_gdp.findVertexAttrib("N") if N_attrib is None: N_attrib = mesh_gdp.findPointAttrib("N") # If there are no vertex or point normals and we need to compute # them with a SopVerb if N_attrib is None and computeN: normal_verb = hou.sopNodeTypeCategory().nodeVerb("normal") normal_verb.setParms({"type": 0}) normals_gdp = hou.Geometry() normal_verb.execute(normals_gdp, [mesh_gdp]) mesh_gdp.clear() del mesh_gdp mesh_gdp = normals_gdp N_attrib = mesh_gdp.findPointAttrib("N") uv_attrib = mesh_gdp.findVertexAttrib("uv") if uv_attrib is None: uv_attrib = mesh_gdp.findPointAttrib("uv") S_attrib = mesh_gdp.findVertexAttrib("S") if S_attrib is None: S_attrib = mesh_gdp.findPointAttrib("S") faceIndices_attrib = mesh_gdp.findPrimAttrib("faceIndices") # TODO: If uv's don't exist, check for 'st', we'll assume uvs are a float[3] # in Houdini and st are a float[2], or we could just auto-convert as # needed. # We need to unique the points if any of the handles # to vtx attributes exists. for attrib in (N_attrib, uv_attrib, S_attrib): if attrib is None: continue if attrib.type() == hou.attribType.Vertex: unique_points = True break S = None uv = None N = None faceIndices = None if faceIndices_attrib is not None: faceIndices = array.array("i") faceIndices.fromstring( mesh_gdp.primIntAttribValuesAsString("faceIndices")) # We will unique points (verts in PBRT) if any of the attributes are # per vertex instead of per point. if unique_points: P = vtx_attrib_gen(mesh_gdp, P_attrib) indices = linear_vtx_gen(mesh_gdp) if N_attrib is not None: N = vtx_attrib_gen(mesh_gdp, N_attrib) if uv_attrib is not None: uv = vtx_attrib_gen(mesh_gdp, uv_attrib) if S_attrib is not None: S = vtx_attrib_gen(mesh_gdp, S_attrib) else: # NOTE: We are using arrays here for very fast access since we can # fetch all the values at once compactly, while faster, this # will take more RAM than a generator approach. If this becomes # and issue we can change it. P = array.array("f") P.fromstring(mesh_gdp.pointFloatAttribValuesAsString("P")) indices = vtx_attrib_gen(mesh_gdp, None) if N_attrib is not None: N = array.array("f") N.fromstring(mesh_gdp.pointFloatAttribValuesAsString("N")) if S_attrib is not None: S = array.array("f") S.fromstring(mesh_gdp.pointFloatAttribValuesAsString("S")) if uv_attrib is not None: uv = pt_attrib_gen(mesh_gdp, uv_attrib) mesh_paramset.add(PBRTParam("integer", "indices", indices)) mesh_paramset.add(PBRTParam("point", "P", P)) if N is not None: mesh_paramset.add(PBRTParam("normal", "N", N)) if S is not None: mesh_paramset.add(PBRTParam("vector", "S", S)) if faceIndices is not None: mesh_paramset.add(PBRTParam("integer", "faceIndices", faceIndices)) if uv is not None: # Houdini's uvs are stored as 3 floats, but pbrt only needs two # We'll use a generator comprehension to strip off the extra # float. uv2 = (x[0:2] for x in uv) mesh_paramset.add(PBRTParam("float", "uv", uv2)) return mesh_paramset