Houdini - LOPS & USD
Solaris is the umbrella name for Houdini’s scene building, layout, lighting, and rendering tools based on the Universal Scene Description (USD) framework. LOP (lighting operator) nodes generate USD describing characters, props, lighting, and rendering.
Tips
Lighting
- Automatic headlight Creation
- The default behaviour when there are no lights present in the scene is to create a default headlight. To disable the default light uncheck the following checkbox
Karma render settings (node) > Rendering > Geometry and Shading > Shading > Automatic Headlight Creation : Disable
- The default behaviour when there are no lights present in the scene is to create a default headlight. To disable the default light uncheck the following checkbox
Python
Scene Graph Tree
Lets select some prims in the Scene Graph Tree using Python. Note that the selection is stored on the LOP Network. In this example below the lop network is inside the “geo1” sop network. If it we are using the lop “Stage” context the path would be “/stage”
# get the selection of a lopnetwork inside a geo sop network
hou.node('/obj/geo1/lopnet1').selection()
# get the selection of the "root" stage context
hou.node('/stage').selection()
# set selection
paths = ['/scene/geo/sub/sphere', '/scene/geo/sub/box']
hou.node('/stage').setSelection(paths)
Get prim
We are in the Stage context in houdini.
- In the LOP network we have 3 nodes.
- First we have a null named “null_0”
- Then we have a Material Library named “materiallibrary” connected
- An inside this material library we have a material called “green”
- Lastly we have a null named “null_1” connected at the end
- Lets try to get the material prim
- If we try to get it through the first null we are out of luck since the prim does not yet exists in “usd” file.
- But we can get it if we access it through the material library or the last null node
# Try accessing through null_0
lop_node = hou.node('/stage').node('null_0')
# <hou.LopNode of type null at /stage/null_0>
stage = lop_node.stage()
# Usd.Stage.Open(rootLayer=... ...LOP:rootlayer-session.usda'))
stage.GetPrimAtPath('/materials/green')
# invalid null prim
# Try accessing through null_1
lop_node = hou.node('/stage').node('null_1')
# <hou.LopNode of type null at /stage/null_1>
stage = lop_node.stage()
# Usd.Stage.Open(rootLayer=... ...LOP:rootlayer-session.usda'))
stage.GetPrimAtPath('/materials/green')
# Usd.Prim(</materials/green>)
Camera
# camera in the lop context named camera1
# translation: (1, 2, 3)
# rotation: (-270, 0, 0)
lop_cam = hou.node('/obj/lopnet1/camera1')
stage = lop_cam.stage()
primpath = lop_cam.evalParm("primpath")
cam = stage.GetPrimAtPath(primpath)
property_names = cam.GetPropertyNames()
# print(property_names)
# ['clippingPlanes', 'clippingRange', 'exposure', 'focalLength', ...
focus_dist_attr = cam.GetAttribute('focusDistance')
focus_dist = focus_dist_attr.Get()
#print(focus_dist)
# 9.644547462463379
#print(type(focus_dist))
# <class 'float'>
transform_attr = cam.GetAttribute('xformOp:transform')
transform = transform_attr.Get()
#print(transform)
# ( (1, 0, 0, 0), (0, 0, 1, 0), (0, -1, 0, 0), (1, 2, 3, 1) )
#print(type(transform))
# <class 'pxr.Gf.Matrix4d'>
#print('\n'.join(dir(transform)))
pos = transform.GetRow3(3)
#print(pos)
# (1, 2, 3)
#print(type(pos))
# <class 'pxr.Gf.Vec3d'>
pos_tuple = (pos[0], pos[1], pos[2])
z_axis = transform.GetRow3(2)
#print(z_axis)
# (0, -1, 0)
z_axis_tuple = (z_axis[0], z_axis[1], z_axis[2])
print(pos_tuple)
print(z_axis_tuple)
Docs
Vex
Materials
I am using an Assign material node with the primpattern parm set to All Mesh Primitives (%type:Mesh) and using vex to specify the material (see snippet below).
I am checking if a shop_materialpath attr exists, if it does use that to construct the material name, if it does not exist set the “material name” to “no_shopmatpath”. Then I am checking to see if the constructed path to the material exists if it does, assign the material (by returning it) if it does not return the path to a material that will be used when materials are missing in the lop material library. This is probably not the best way to do this, but it is a way.
string shop = usd_attrib(0, @primpath, 'shop_materialpath');
if(shop==''){
shop = 'no_shopmatpath';
}
string mat_name = '/materials/' + shop;
int mat_exists = usd_isprim(0, mat_name);
if (mat_exists){
return mat_name;
}
else {
return '/materials/missing_in_lop';
}

Assign material with vex (with fallback for missing material) using sop attrib
misc
// material binding
string mat = usd_boundmaterialpath(0, @primpath);
// set attrib
usd_setattrib(0, @primpath, 'yolo', 42);
Nodes
Rendering
Camera
Latlong cubemap in Karma
I needed to render out a cube map using Karma so this led me to dig deeper into lens shaders.
Paul Ambrosiussen and
Matt Estela has some good information on the subject.
There seems to be a bug when Karma is rendering with Hython so the lensshader using cvex errors out (will maybe be fixed in Houdini 19.5). A workaround is to use the vrlens shader that you can create in a shopnet context.
Settings
Applies renderer-specific geometry settings to geometry in the scene graph.

Using a mtlxuniform_edf and a render geometry settings node to render an unshaded color material
Materials
Read more about material assignment in lops cgwiki. Below is a hip file where I try out varius ways of editing material attributes in lops.