Friday, May 31, 2013

Python Scripting

Data Expansion in Houdini  using Python & Renderman Interface Filters

   This page demonstrates the use of a procedural primitive, or helper app as they are often called, to generate an arbitrary number of points in order to enhance the appearance of a particle simulation.

   For this project i want to create a procedural Tornado/Dust Devil in Houdini and do data expansion in render-time  I am going to concentrate only on the tornado/dust devil network for now. 

Reference Footage


My Render


video

Houdini playblast of the initial Tornado Network

Following is the procedural network i created in Houdini which can be used to create a basic tornado/dust devil simulation.

video

My next step was to figure out a way to use Data Expansion in houdini since i want to avoid big simulation time. 

Script implementation for the Tornado network :

video
Original Houdini Particles Count : 5600         After applying the script : 1680000

Python Script

 Following is the code. It basically goes through all the points in the scene and creates a rib file for each point. The built-in procedural RiProcRunProgram will run an external “helper program,” capturing its output and interpreting it as RIB input. This helper program will add the extra particles during the render time.

The following code entered in "Python Source Editor".

import math,os,re,sys,prman,random
def main():
ri = prman.Ri()
ri.Option("rib", {"string asciistyle": "indented"})
ap_script = '/usr/bin/python/home/sragha20/mount/stuhome/vsfx705/python/addPoints.py'
ap_num = str(hou.node("/obj/proxy").parm("num").eval())
ap_dist = str(hou.node("/obj/proxy").parm("dist").eval())
ap_dia = str(hou.node("/obj/proxy").parm("dia").eval())
ap_freq = str(hou.node("/obj/proxy").parm("freq").eval())
inputs = ap_num + ' ' + ap_dia + ' ' + ap_freq + ' ' + ap_dist + ' ' + '3'
items = [ap_num, ap_dia, ap_freq, ap_dist]
pointnode = hou.node('/obj/pop/point1')
pointgeo = pointnode.geometry()
pos = pointgeo.iterPoints()
hou.setFrame(hou.frame())
path = '/home/sragha20/mount/project4/ribs/particle_%04d.rib' % int(hou.frame())
ri.Begin(path)  # set rendertarget to ri.RENDER to render pixels
for i in range(len(pos)):
tmp = pointgeo.iterPoints()[i]
tmp1 = tmp.floatListAttribValue("P")
ri.TransformBegin()  
ri.Translate(tmp1[0], tmp1[1], tmp1[2])
angle = random.uniform(-180.0, 180.0)
ri.Rotate(angle, random.uniform(-1.0, 1.0), random.uniform(-1.0, 1.0), random.uniform(-1.0, 1.0))
ri.Procedural( (ap_script, inputs), (-1,1, -1,1, -1,1), "ProcRunProgram")
ri.TransformEnd()
ri.End()
if __name__ == "__main__":
main()

Noise Function (Addpoints.py)

import sys, random, math
from pnoise import pnoise
inputs = sys.stdin.readline()
 while inputs:
items = inputs.split()
pixels = float(items[0])
num = int(items[1])
dia = float(items[2])
freq = float(items[3])
size = float(items[4])
sed = int(items[5])
random.seed(sed)
print 'Points "P" ['
for n in range(num):
x = random.random() * freq * random.uniform(0.8, 1.3)
y = random.random() * freq * random.uniform(0.8, 1.3)
z = random.random() * freq * random.uniform(0.8, 1.3)
  x = pnoise(x,y,z) * size
y = pnoise(y,x,z) * size 
z = pnoise(z,x,y) * size  
print '%1.3f %1.3f %1.3f' % (x,y,z)
print '] "constantwidth" [%1.3f]' % dia
sys.stdout.write('\377')
sys.stdout.flush()
inputs = sys.stdin.readline()

       Once the script was entered in source editor, I made a Renderman Rop and referenced the function in "Pre-Frame Script" field. 

                           hou.session.main()

       "hou" is a built-in python procedure which gives you interactive access to all the contexts in houdini. "main" is the function. 



No comments:

Post a Comment