Houdini Resources

Updated on June 28  2025


Karma Texture Overrides

Deborah R. Fowler



Karma Texture Overrides with a peek at USDs and husk

Posted Aug 13  2024
Updated Feb 15  2026

As we adapt to Karma, it can be handy to compare to techniques that were well established in previous renders. For example, Texture Overrides were easy to do in Mantra and Redshift (see Texture Overrides).

Let's look at Karma. Karma cpu respects most principled shader properties, however xpu does not.
(from https://www.sidefx.com/docs/houdini/solaris/karma.html#overview under the topic xpu
"Because it must run in the more limited environment on the GPU, XPU drops support for even more legacy features than Karma CPU. Karma XPU will never support VEX-based shaders at all."

In addition, in my experience the Vulkan preview does not perform well with the principled shader (OpenGL works fine). More on that below.

Here I'll be looking at Karma cpu, xpu and MaterialX.


 
also on youtube https://www.youtube.com/watch?v=TM4d87-aJN8&t=14s

Sample files contained in this zip created in 20.5.278 and 21.0.440:


testKarmaWithPS.hiplc - using an example of a single grid copied to points of a grid, vary the scale, color and then render with Karma in a lopnetwork (with the Principled Shader assigned at the obj level). The visual result is the same in Karma cpu, xpu and Mantra.

The setups in the network include obj with gridExample, lopnet1, cam1 and in the lopnet1 a sceneimportall is used.
This is one of the easiest ways to use Karma. We will later do it slightly differently.

    
Next we add textures using the texture override (as in Redshift or Mantra).
In order to make this work in Karma, the override value was added as an attribute before the material node and then referenced in the node itself.

NOTE: if you are using more textures and need frame padding replace the expression for itoa(num) with sprintf("%02d", num) to get the proper string (get rid of the 0 in the previous string).
s@file = "$HIP/tex/Dog_" + sprintf("%02d",num) + ".PNG";

We can see we are getting a random selection in the render for mantra, Karma cpu (same setup as previous file), however Karma xpu only renders one image on all grids, as does the Houdini VK preview.



Interesting note, if the attribute is not created and the expression is used in the material only mantra works as expected, but Karma cpu ignores the override value. Only when it is made an attribute does Karma cpu work correctly.

Thus we can override textures using the Principled shader and Karma cpu - but what about xpu? We need to move to MaterialX.

with MaterialX

Changing the setup, now use sopimport nodes in the lopnetwork to import only the geometry and use MaterialX (mtlx) instead of the Principled Shader.
The geometry setup is the same, but now in lops we use a sopimport node to bring the geometry in, add a camera, and a material library

You might be tempted to follow the same method.



To do a material override we need the attribute defined so we can do that in a wrangle in sops.
In order to use the mtlxgeopropvalueuniform (the mtlxgeopropvalue node does not allow strings) to recognize the attribute defined on the instance.



This method does not require an assign material. The material can be assigned in the material library.
It also works with native or point instancer set. HOWEVER, it will not work using this on the renderfarm (the hard-coded paths are stored as primvars)



However, there is a way around this too. If we want to force the usd file to have relative paths we can use the following instead in the wrangle node:



The only catch is now the husk render works exactly as it should with no absolute paths in the primvars and pathing solved at render.
If you should run into problems in the gui - be sure you have selected a renderer and the texture path is being searched.

(Should not be needed)


Now mplay, gui, husk all work the same and are using relative paths! Hooray!


The method as seen in the file testKarmaWithXtex.hiplc is using an assignmaterial node with a cvex binding which is not necessary with the above approach.


To create a mtlx shader by diving inside the material library node and creating a mtlx builder. Inside we use a mtrlximage node to supply the image - I have also exposed the file parameter.

On the material library node click Auto-fill Materials - you can assign materials here, however I use a assignmaterial node as I want to create the material override.

In the assignmaterial node I have used the primitives (/sopimport1/obj_*) to assign the materials (materials/mtlxmaterial) with an override in vex similar to what we did in the wrangle, however @ptnum is replaced with @elemnum.
The CVEX Bindings is set to on with the attribute name file and vex parameter file


Now Karma XPU and Karma CPU as well as the Houdini Vulkan preview all produce the same texture pattern (differs from the previous - you can always manipulate the random seed to change).


A look at the USD file

Karma was created so that Houdini could be USD compatible. I've added a sopimport Layer Save Path so that the geometry is written as a usda that we can examine. (Default is binary and in 20.5 will issue a warning but by default will write it out into the sop path name relative to $HIP, in this case /obj/grid1/copytopoints1.usd). By adding the Layer Save Path I have written it in /geo/grid1.usda.
If you look at the file included in the zip you will see that it contains the grids listed as instances (what copy to points would be in usd).



The material overrides can then be seen in the main usda file called karma.usd.rop1.usda (in this case) that is written (I redirected it to write on the top level). It lists the sublayer @./geo/grid1.usda@ as well as the camera, and then mtrlxmaterial has the overridden texture listed as @./tex/Dog_05.PNG@ for example.

You can take a look at the usda file labeled karma.usd_rop1.usda. Note this is the ROP_USD result not the ROP_RenderUSD. This file along with the sublayer file is all that would be needed to render the image via husk.

If you open your command line tools, cd to the directory where this is located and run husk.

Final note - you will write usd (binary) rather than usda - ascii format was only for teaching purposes.
(as of this post I am still tracking down why there is an absolute path in token productName.timeSamples. In order to avoid this issues I have switched to using the general "render properties" rather than the "karma render properties" node which does not have this issue.)