Houdini Materials Override

Overriding materials in Houdini  not a simple task that you might think. There are many ways to do so such as Takes or shop_surfacepath method mention here (http://forums.odforce.net/topic/13385-global-material-override/)

Python Filtering technic described in the same post by King Tapir work pretty well and do not required that all of your material assigned on the object level. However, it might be difficult to figure out how to use it for the first time.

Made a .py file. In my case it called filter.py and contain following code.

import mantra

def filterInstance() : 
    mantra.setproperty('object:surface', 'op:/shop/AO'.split())
    mantra.setproperty('object:overridedetail', 1)

print "Python Filter Finished"
filterInstance() Called just prior to the ray_end statement which locks off the settings for an instance object. The function can query object: settings and possibly alter them.
object:surface = ('') The surface shader attached to the object.
vm_overridedetail / object:overridedetail = ('false') When geometry has shaders defined on a per-primitive basis, this parameter will override these shaders and use only the object’s shader. This is useful when performing matte shading on objects.
Not supported for per-primitive material assignment (material SOP).
'op:/shop/AO' Shop material that we going to override

Tell mantra to use this file as a Python Filter


Also, don’t forget to force writing of all shaders into .idf by setting Declare All SHOPs.


Create a simple SHOP material in this case I’m doing very simple Ambient Occlusion shader.


If everything set correctly you should see the print output “Python Filter Finished” in your console.

Screen Shot 2015-03-20 at 12.15.22 PM

This is my result


Useful links to explore:



Nuke Custom LUTs


Our post-production facility recessives DPX plates with .3dl LUT file from DaVinci Resolve. The LUTs were for two different cameras one of which is ARRI Alexa and another is RED. The task is to apply this LUTs to every dailies rendered by all artists.


First, we need to create a gizmo for each LUT which contain Vector Field Nuke node with the following expression in the “fectorfield file” field.

[getenv NUKE_LUT]/A_CAM_ArriLogC.3dl

where “getenv NUKE_LUT” will grab session environmental variable with name “NUKE_LUT” which contain path to the LUTs folder.




Now create a “init.py” file inside you .nuke directory.

 C:\Users\User name\.nuke

The “init.py” file should look something like this

import nuke
import os

# Path to executed file
cwd = os.path.dirname(os.path.realpath(__file__))

# Provide env variable for use in vectorfield node as a relative path
os.environ['NUKE_LUT'] = os.path.join(cwd, 'BB_LUT')

# Paths to viewer gizmos
RED_Viewer_LUT = os.path.join(cwd, 'BB_LUT', 'BB_RED_Viewer_LUT.gizmo').replace("\\", "/")
ARRI_Viewer_LUT = os.path.join(cwd, 'BB_LUT', 'BB_ARRI_Viewer_LUT.gizmo').replace("\\", "/")

# Paths to node gizmos
RED_LUT = os.path.join(cwd, 'BB_LUT', 'BB_RED_LUT.gizmo').replace("\\", "/")
ARRI_LUT = os.path.join(cwd, 'BB_LUT', 'BB_ARRI_LUT.gizmo').replace("\\", "/")

# Register custom LUTs
nuke.ViewerProcess.register("BB_ARRI_LUT", nuke.Node, (ARRI_Viewer_LUT, ""))
nuke.ViewerProcess.register("BB_RED_LUT", nuke.Node, (RED_Viewer_LUT, ""))

# Regester costome meny for creatin LUT gizmos
nuke.menu('Nodes').addCommand( 'BB_Tools/ARRI_LUT', lambda: nuke.createNode(ARRI_LUT))
nuke.menu('Nodes').addCommand( 'BB_Tools/RED_LUT', lambda: nuke.createNode(RED_LUT))


Beside registering gizmo for Nuke Tab menu I also register them as a custom  Nuke display LUTs.



Note how the “init.py” script setting a ‘NUKE_LUT’ environmental variable which is hold the path pointing to the current directory plus LUT sub-directory.

After that we should be able to access that variable through the following TCL expression inside of Nuke.

getenv NUKE_LUT

Now we can copy the folder with our LUTs and gizmos within “init.py” to any Windows or IOS machine without worrying about hard-coded path to our LUTs.