Let's have a look at an example:
Sorcery?
You must be mistaken.
One of the cool things about Python in Houdini is its ability to create and delete nodes at runtime. Another cool thing is how it can read points and their attributes off geometry.
Put those two together and you can translate information in your scene to your node tree.
The idea is I first start off with a simple attribute wrangle that uses toNDC and fromNDC to flatten the points to face the camera so that it's a 2D set of points with screen space coordinates. The vex is fairly simple (adapted from f1480187's answer):
@id = @ptnum;
@P = toNDC(chs("camera"), @P);
@screenX = @P.x;
@screenY = @P.y;
@P.z = -ch("depth");
@P = fromNDC(chs("camera"), @P);
Here comes the magic.
I can quite easily create tons of nodes in python.
One of the things I have to ensure is that I clear all my nodes everytime I run the script. I did that by ensuring all my nodes start with an '_' in the name. This allowed me to iterate through every node and check thisNode.name().startsWith("_"), if proven true then simply delete that node. By appending the nodes with that name to an array, I can use hou.node('../').deleteItems(nodeArray) to easily remove all of them.
node = hou.pwd()
geo = node.geometry()
frame = hou.frame()
# Clear all _ nodes
def delSearch(pref):
results = []
for thisNode in hou.node('../').children():
if thisNode.name().startswith(pref):
results.append(n)
if len(results) > 0:
hou.node('../').deleteItems(results)
delSearch('_')
Now that we start with a blank slate, we want to create our nodes.
We can create nodes with:
newNode = hou.node(nodePath).createNode('null', nodeName).
We can also set the new nodes position with:
newNode.setPosition((0, 0))
and set its colour with:
newNode.setColor(hou.Color((1, 0, 0)))
Now, the fun stuff.
We can iterate over all of our points in the geometry with:
for point in geo.points():
Furthermore, we can take attributes from those points like so:
point.attribValue("Cd").
Put them together, and you can create nodes for each point in the geometry and colour them based on the point colour. In my previous nodes, I am storing the position in a screenX and screenY attribute. Since screenX is mapped to the width of the screen, if the value goes over 1 it means it's off the screen and should appear in the node view.
# Create all the nodes
def createNode(nodeName, nodePath, nodePos, nodeCol):
nodeFullPath = nodePath + "/" + nodeName
if hou.node(nodeFullPath) == None: # Ensures node doesn't already exist
newNode = hou.node(nodePath).createNode('null', nodeName)
newNode.setPosition(nodePos)
newNode.setColor(nodeCol)
points = geo.points()
for point in points:
pointX = point.attribValue("screenX")
pointY = point.attribValue("screenY")
pointCol = point.attribValue("Cd")
if pointX > 1:
nodePath = "../"
nodeName = "_" + str(point.attribValue("id"))
nodePos = ((pointX * 25*2, pointY * 15*2))
nodeCol = hou.Color(pointCol)
createNode(nodeName, nodePath, nodePos, nodeCol)
The cool thing with this is you can apply it to any object.
Yup, that's our favourite pig head.
You can take this further and remove points that are facing away from the camera so you don't see the other side.
Hook it up to your simulation and you've got yourself a winner.
Comments