Houdini Python

From bernie's
Jump to: navigation, search

Selected node as python code

(linux)

import hou
import os
sel = hou.selectedNodes()
strCode = sel[0].asCode(1,1)
#print strCode
fp = "/tmp/houdini_node_output.txt"
with open(fp, "w") as text_file:
    text_file.write(strCode)

os.system('xdg-open \"%s\"' % fp) 

gives:

dcwjJXK.png

Paste clipboard nodes to object merges

# this snippet will paste nodes in clipboard to object merges
# use it with a shortcut (I overrode 'alt-v' in network pane context)

import hou

network = hou.ui.curDesktop().paneTabUnderCursor()
networkpath = network.pwd().path()
pos = network.cursorPosition()

clipboard = hou.ui.getTextFromClipboard()

n = 0

if clipboard:
    list = clipboard.split()
    for item in list:
        if hou.node(item) != None:
            merge = hou.node(networkpath).createNode('object_merge','merge_'+item.split('/')[-1])
            merge.parm('objpath1').set(str(item))
            merge.setPosition(pos)
            merge.move([n*2,0])
            if n == 0:
                merge.setSelected(True,True)
            else:
                merge.setSelected(True,False)
            n = n + 1

Toggle off/on separate AOVs Arnold ROPs

Just saving it in case I need it

for child in hou.node('/out').children():
    #print child.type().name()
    if 'ppArnold' in child.type().name():
        #if child.name() == 'osacks_electric_brain_january_visual_cortex':
        for p in child.parms():
            if 'ar_aov_separate' in str(p) and 'file' not in str(p):
                p.set(0)
                print(child.name()+"."+str(p)+"   "+str(p.eval()))

Set expresions linking light visible parameter to display flag

idk why the candidate light didn't work on my machine so i used this

for child in hou.node('/obj').children():
    if 'light' in child.type().name():
        child.parm('light_enable').setExpression('hou.pwd().isDisplayFlagSet()', language=hou.exprLanguage.Python)

Skip if frame is in list

gbBP0Yj.png

Works if there's a parm called skip on the same (switch) node

#true only on frames specified. Dirty but works
if str(int(hou.frame())) in hou.pwd().parm('skip').eval().split(' '):
    return 1
else:
    return 0

and on a button if you want to easily add current frame to the list, make sure it's set to python

hou.pwd().parm('skip').set(hou.pwd().parm('skip').eval()+' '+str(int(hou.frame())))

Import neuron swc data

wip

# reads SWC and creates geo from it
# http://www.neuronland.org/NLMorphologyConverter/MorphologyFormats/SWC/Spec.html
#
#       0           ¦             1             ¦    2   3   4  ¦    5   ¦            6
# sample number     ¦    structure identifier   ¦    x   y   z  ¦ radius ¦  parent sample (connectivity)


import os
from itertools import *

node = hou.pwd()
geo = node.geometry()


# procedures

def isBadLine(line):
    return line[0]=='#'
    
#def createPoint(geo,data):
   

curDir = hou.node('/obj/swc_to_poly/directory_to_read').parm('readin').eval()
print("processing: "+curDir)

#read swc files in dir
files = []
for name in os.listdir(curDir):
    if name.endswith('.swc'):
        files.append(os.path.join(curDir, name))
    files.sort()


files = files[-1:]
for file in files:
    print("  --- processing file: "+file)
    with open(file) as f:
        for line in dropwhile(isBadLine, f):                    # only read lines that don't have hashtag
            data = line.lstrip().rstrip().split(" ")
            data = map(float,data)
            point = geo.createPoint()                           # create one point per line and fill attributes
            point.setPosition(hou.Vector3(*data[2:5]))
            point.setAttribValue('id', int(data[0]))
            point.setAttribValue('structid', int(data[1]))
            point.setAttribValue('radius', data[5])
            point.setAttribValue('parent_id', int(data[6]))

    #print file

Create nodes according to primitive groups

dbRXRdK.png

node = hou.pwd()

#custom undo stack 
with hou.undos.group("Poly Reduce Groups"):
    #uses parent, otherwise recursion happens with python sop node
    node = node.inputs()[0]
    geo = node.geometry()
    groups = geo.primGroups()
    count = 0
    mainReduce = ''
    
    merge = node.parent().createNode('merge')
    
    for o in groups:
    
        #keep a single prim group
        blast = node.parent().createNode('blast')
        blast.setInput(0,node)
        blast.moveToGoodPosition()
        blast.parm('negate').set(True)
        blast.parm('group').set(o.name())
        
        #use polyreduce with keep points on with an expression
        reduce = node.parent().createNode('polyreduce')
        reduce.setInput(0,blast)
        reduce.moveToGoodPosition()
    
        reduce.parm('originalpoints').set(True)
        reduce.parm('referframe').set(True)
        reduce.parm('framereference').setExpression('round((\$F+'+str(count)+')/ch("step"))*ch("step")')
    
        #create the 'step by' channel on this node
        parmTemplateGrp = reduce.parmTemplateGroup()
        stepByParm = hou.FloatParmTemplate('step', 'StepBy', 1,default_value=([10]))
        parmTemplateGrp.append(stepByParm)
        reduce.setParmTemplateGroup(parmTemplateGrp)
    
        if count == 0:
            reduce.setColor(hou.Color([0.6,1,0.6]))
            mainReduce = reduce
            reduce.parm('percentage').set(10)
            
        else:
            params = ['percentage','optimizationbias','borderweight','attribweight','topologicalweight','step']
            for element in params:
                reduce.parm(element).set(mainReduce.parm(element))
    
        merge.setInput(count,reduce,0)
        count = count + 1
        
    merge.moveToGoodPosition()
    merge.setDisplayFlag(True)
    mainReduce.setSelected(True, clear_all_selected=True)

Load a folder of objs and merge them

import hou
import glob
obj = hou.node("/obj")
s = obj.createNode('geo', 'loader', run_init_scripts=False) 
m = s.createNode('merge')

path = '/users/mbernadat/Downloads/body/*.obj'
i = -1
for file in glob.glob(path):
    i += 1
    f = s.createNode('file')
    f.parm('file').set(file)
    f.moveToGoodPosition()
    m.setInput(i,f,0)
m.moveToGoodPosition()

Best fitting bbox from eigenvectors

thanks to petz @ http://forums.odforce.net/topic/14879-bounding-box/

# This code is called when instances of this SOP cook.
geo = hou.pwd().geometry()
prims = geo.prims()
points = geo.points()

# parms
output = 0
maxIter = 10
threshold = 0.001

centroid = sum([point.position() for point in points], hou.Vector3()) * (1.0 / len(points))

# build covariance matrix
val11 = 0;  val12 = 0;  val13 = 0
val21 = 0;  val22 = 0;  val23 = 0
val31 = 0;  val32 = 0;  val33 = 0

for point in points:
    pos = point.position()
    val11 += (pos[0] - centroid[0]) * (pos[0] - centroid[0])
    val12 += (pos[0] - centroid[0]) * (pos[1] - centroid[1])
    val13 += (pos[0] - centroid[0]) * (pos[2] - centroid[2])
    val21 += (pos[1] - centroid[1]) * (pos[0] - centroid[0])
    val22 += (pos[1] - centroid[1]) * (pos[1] - centroid[1])
    val23 += (pos[1] - centroid[1]) * (pos[2] - centroid[2])
    val31 += (pos[2] - centroid[2]) * (pos[0] - centroid[0])
    val32 += (pos[2] - centroid[2]) * (pos[1] - centroid[1])
    val33 += (pos[2] - centroid[2]) * (pos[2] - centroid[2])

mat = hou.Matrix3(((val11, val12, val13), (val21, val22, val23), (val31, val32, val33)))
mat = hou.Matrix4(mat.inverted())

# search for eigenvector with lowest eigenvalue
vec1 = hou.Vector3(1.0, 1.0, 1.0)
vecTemp = vec1 * mat
vec2 = vecTemp * (1.0 / vecTemp.length())
i = 0
while not vec1.isAlmostEqual(vec2) and i < 100:
    vec1 = vec2
    vecTemp = vec1 * mat
    vec2 = vecTemp * (1.0 / vecTemp.length())
    i += 1
minAxis = vec2.normalized()


# build matrix to transform geometry to initial position and orientation
up = hou.Vector3(0.0, 1.0, 0.0)
matUp = hou.hmath.buildTranslate(-centroid)
matUp *= minAxis.matrixToRotateTo(up)
geo.transform(matUp)

# initialize attributes
initRot = 9
angleSum = 0
ratio = 1
i = 0

# adaptively rotate geometry until best orientation for smallest bounding box is found
while i < maxIter and ratio > threshold:
    angle = 0
    angleHold = 0
    angleRotBest = 0
    bboxSize = geo.boundingBox().sizevec()
    vol = bboxSize[0] * bboxSize[1] * bboxSize[2]
    volMin = vol
    volMinHold = vol

    for n in range(10):
        angle += initRot
        matRot = hou.hmath.buildRotateAboutAxis(up, initRot)
        geo.transform(matRot)
        
        bboxSize = geo.boundingBox().sizevec()
        vol = bboxSize[0] * bboxSize[1] * bboxSize[2]
        if vol < volMin:
            volMin = vol
            angleRotBest = angle
    
    # check ratio of vol and vol of previous bounding box
    ratio = abs(volMinHold - volMin)
    volMinHold = volMin
    if ratio == 0.0 and i == 0:
        ratio = 1.0
    
    angleRot = angle - angleRotBest + initRot
    angleSum += angleRotBest - initRot
    matRot = hou.hmath.buildRotateAboutAxis(up, -angleRot)
    geo.transform(matRot) 
    initRot *= 0.2
    i += 1


# bounding box 
bbox = geo.boundingBox()
size = bbox.sizevec()
vol = size[0] * size[1] * size[2]

# build matrix to transform geometry back to oiginal position and orientation
mat = hou.hmath.buildRotateAboutAxis(up, -angleSum) * matUp.inverted()
matAttrib = geo.findGlobalAttrib("mat")
if not matAttrib:
    matAttrib = geo.addAttrib(hou.attribType.Global, "mat", (   0.0, 0.0, 0.0, 0.0,
                                                                0.0, 0.0, 0.0, 0.0,
                                                                0.0, 0.0, 0.0, 0.0,
                                                                0.0, 0.0, 0.0, 0.0))
geo.setGlobalAttribValue(matAttrib, mat.asTuple())


#create objects from voronoi
from math import cos, sin, pi

obj = hou.selectedNodes()[0]
node = obj.displayNode()
prims = node.geometry().prims()

lastprim = prims[ len(prims)-1 ]
lastprimName = lastprim.attribValue("name")
lastprimName = lastprimName.partition("piece")
lastprimName = int( lastprimName[ len(lastprimName)-1 ] )

print lastprimName

subnet = hou.node("obj").createNode("subnet")

for i in range(0,lastprimName+1):
    geo = subnet.createNode("geo")
    geo.setPosition([cos( (1.0*i/lastprimName+1 ) * 2.0 * pi )*4.0, sin( (1.0*i/lastprimName+1 ) * 2.0 * pi )*4.0 ]) # lol
    objectMerge = geo.createNode("object_merge")
    delete = objectMerge.createOutputNode("delete")
    objectMerge.parm("objpath1").set(node.path())
    delete.parm("negate").set(1)
    delete.parm("group").set("@name=piece"+str(i))
    delete.setDisplayFlag(1)

Get functions in an OTL

#in button callback
hou.pwd().hdaModule().hello()

#in script window
def hello:
    ....


Preroll output to stdout (good for HQUEUE), put in a python node that gets fetched each step (source?). Also add f1 f2 parms to the python node with $RFSTART and $RFEND

import sys

start = hou.node(".").parm("f1").eval()
end = hou.node(".").parm("f2").eval()
current = hou.frame()

progress = str(int(hou.hmath.fit(current, start, end, 0.0, 100.0))).zfill(3)

print("\rFrame {0} done".format(current))
print("\rALF_PROGRESS {0}%".format(progress))
sys.stdout.flush()