Tuesday, 27 October 2026

Solaris instance lights and attribute variation

In Solaris we can instance lights onto points.
Make sure your points have  N & Up attributes, like you would with any instanced geo.

The more interesting stuff will be the intensity, exposure, "color" etc.

I know there's a post about this on Matt Estela's CGwiki, but I *think* it applies to an older version of Houdini/Solaris & the instancing method they use there is different - "reference" instead of point instancing. Never sure which is actually better or more efficient!

But how do we access them?? Here's a list of the stuff we can access (taken from the SideFX website)

Primvars

In Solaris/USD, you have access to several light-specific primvars. You can use attributes on the scatter points to drive these primvars. Here’s a list of the available primvars:

  • intensity (intensity)

  • exposure (exposure)

  • width (width)

  • height (height)

  • color (color)

  • radius (radius)

  • color temperature (colorTemperature)

  • diffuse multiplier (diffuse)

  • specular multiplier (specular)

Note that width, height and radius are only available with area lights, while the remaining primvars are available for any kind of light source.


SideFX recommends using Attribute Adjust sops to access these attribs. They're a bit neater and user friendly than wrangles I suppose!

Below is how you use it... plug your points into the Attrib Adjust and type this into the name:

`encode("light:color")`

Don't forget the back ticks - ` `


The same applies to Attribute adjust float, for something like Intensity.. `encode("light:intensity")`


Also.. if you want to do stuff to these attributes in a wrangle (after they've been created), they get given a funky name, but these can be accessed normally

For instance (lol), here i'm multiplying the intensity of the lights with the speed at which they move at in a wrangle.

I'm not sure if the assigned name is the same each time so do check... 

Tuesday, 20 October 2026

plate camera projection in Karma or Solaris

How to do camera projections in Karma/Solaris.
 
Coordsys is the magic node. Below are the settings.. I want to project a plate image onto /grid using /camera1... so put their names in the boxes shown.
"tex" is an arbitrary name, we'll use it to access the camera space coordinates later, in the material. This is all that NDC stuff.
Just in case the images vanish from this site... Primitive Path should be your grid/projection geo, same again for the Primitives. Coordsys name should be something like "tex" and Target should be your camera path. Everything else can be left as default.


Material X Position is the node that gets you access to the NDC stuff..
We call on "tex" and the ":ndc" gets us to that space. Following that we get a vector, where we only need the X and Y...........which we separate out and combine to make a UV coordinate for the image sequence.


Assign your material to the projection object/grid and then switch to a Karma render view to see the result (VK does NOT display this correctly)!
If it doesn't work...check all your name paths!

Thursday, 8 October 2026

render var for aov, karma, solaris

 
This seems to be the least painful way to make an AOV - using a "render var" node just before the Render Settings.

I've named the node itself "pref", so a $OS can pick up the naming.
Under the Standard tab, set the data type and source attribute name. My attrib is called "rest" and it's a vector 3 float. The source is Primvar, which means it comes from the mesh.


Next, on the Husk tab (this might be located under standard, depending on your Houdini version), the name box is what you'll want to call your AOV (here we use $OS to take the node label, pref in my case) and then the format that we are writing out - color3f (rgb).


screen space depth, ndc, camera space, flattening stuff

 

Pinched this from Tomas on the houdini forums.

This is useful for moving stuff in and out of camera space, but maintaining the "2d" flat appearance of an object.

Plug this into a point wrangle- 


string cam = "/obj/cam1";
@P = toNDC(cam, @P); // to ndc space
@P.z *= 0;  // flatten
@P.z -= chf("depth"); // set depth
@P = fromNDC(cam, @P); // if you need bring back in front of cam


i've changed the set depth to a float slider to be a bit more interactive, you could just put a hard value in.

the fromNDC(cam,@P) part is the line that brings your object back in front of your camera...otherwise toNDC just exists somewhere near the origin. 

the @P.z*=0; to flatten is entirely optional... you can use this script to move things around in "camera z" 

rendering with karma/solaris in a more "normal way"

 Just a way to work as if you have a render view, instead of in the viewport.

 In Stage, make a Clone Control Panel tab (where your parameters are)


click the Clones with a arrow button, make a new Local one, select Karma CPU or GPU..
Drag your karma render settings node onto the "Node".
Now you can toggle a render on and off in a Render Gallery window & it will save a snapshot each time (might be good or bad....).

Tuesday, 9 June 2026

refracting aovs in karma

 make a custom attribute, i've called it poso2, i'm hijacking the Position value for this & fitting it between 0 and 1.


in karma, use the geompropvalue to load it in to the shader. here i use a mtlxdot because apparently it doesn't change the value of the attribute (?).  i plug it into a karma aov thing and name it "poso", using the $OS. Here i'm using the float value to drive a colour ramp.


In the render settings, aov section, scroll down to "extra render vars" and add one. put in your name - "poso" in our case. set format to color3h and data type to color3f.
The source name is :
C<TG>.*L
and Source Type is LPE.
I actually used the settings created when you select Glossy Transmission for this, then changed the name to Poso. Seems to work though!

Tuesday, 12 May 2026

usd look publishing reminder

 when publishing usd look (with AYON, at least), double check the "materials" folder path. It needs to be sat under the main asset. Eg. if the main asset is /f1, the materials need to be located in /f1/materials.

equally, the geo should be under /f1/geo/

Thursday, 7 May 2026

rename, string substitution, replace in every occurence.


This is for replacing *EVERY* occurence of a string. Eg. SOMEONE has manually selected objects to assign materials to and you don't want to change every single instance of the object path!! This will go through your entire houdini script and change it

use this to string subsitute/replace. make a tool - right click on the shelf and select new tool.
Paste this code into the "code" tab and click create.



 import hou


contexts = ["/obj","/mat","/stage"]


def changeParms(node, search, replace):

    string_parms = [p for p in node.parms() if p.parmTemplate().type() == hou.parmTemplateType.String]

    for parm in string_parms:

        if (search in parm.eval()):

            newValue = parm.rawValue().replace(search, replace)

            parm.set(newValue)


input = hou.ui.readMultiInput("Tell me what to look for: ", ("search","replace"), buttons=('OK',"Cancel"), default_choice=0, close_choice=1, title="Replace Files")

if (input[0] == 0):

    search = input[1][0]

    replace = input[1][1]

    for rootNode in contexts:

        for node in hou.node(rootNode).allSubChildren():

            changeParms(node, search, replace)

Tuesday, 14 April 2026

geometry and material variants, instancing in solaris

Variant workflow. Use the Component builder + Geo Variants to build some variants. You'll use the Component Material node to create the mat variants, then packaged them out with the component output. Bake this as a USD.

 


Load your cached out USD. Attach an "explore variants" node and set the mode to explore. Set spacing to zero so they're all at the origin.

Then plug it into an Instancer. Specify the primitives you want to prototype (use in instancer). Make sure you UNTICK "Only Copy Specified Prototype Primitives". The rest is as normal (eg make some points inside the instancer and give it an index attribute).

Now all of your variants are in play.


This seems a bit longwinded, but I guess it does work and fits within a pipeline a bit nicer? It also works nicely with the variant systems that exist in Houdini/Solaris.

BONUS - if instead of using the Instancer in "Point Instancer" mode, you use "Instanceable Reference", you gain access to each and every instance. If you do this, you can actually use the Set Variant nodes to change particular instances, eg. you switch one of them to be a pig and make it red instead of green. Performance does take quite a big hit if you do this though. 

Friday, 10 April 2026

how to match geo based on path attribute and delete non matching (or keep) primitives

This is quite a specific script.. I got chatgpt to make them for me!

TWO SCRIPTS - they compare input 0 and 1's path attritbutes. Firstly, they strip away (deleting) the primitives that don't match. 
Use case-  you have two mostly identical alembic files of a house. One has UVs you want to transfer to another, but maybe one has some excess geo that you haven't processed yet, or forgot to delete. This will get the two alembics having the same geo (based on path attributes!), so you could do a clean transfer.

 // Get this primitive's path

string my_path = prim(0, "path", @primnum);


// Flag to track match

int match_found = 0;


// Loop over all primitives in input 1

int nprims1 = nprimitives(1);

for (int i = 0; i < nprims1; i++)

{

    string other_path = prim(1, "path", i);

    

    if (my_path == other_path)

    {

        match_found = 1;

        break;

    }

}


// Remove primitive if no match

if (!match_found)

{

    removeprim(0, @primnum, 1); // 1 = delete associated points if unused

}



AND THE REVERSE - KEEPING ONLY THE NON MATCHING STUFF, so you can merge that back into the matching stuff after transferring UVs or whatever.



// Get this primitive's path

string my_path = prim(0, "path", @primnum);


// Flag to track match

int match_found = 0;


// Loop over all primitives in input 1

int nprims1 = nprimitives(1);

for (int i = 0; i < nprims1; i++)

{

    string other_path = prim(1, "path", i);

    

    if (my_path == other_path)

    {

        match_found = 1;

        break;

    }

}


// Remove primitive if a match IS found (reverse logic)

if (match_found)

{

    removeprim(0, @primnum, 1);

}

replacing strings

can't remember if i've written about the "Replace" function. Replacing a given string with nothing, eg "" is a *another* way to remove parts of an existing string!


string tempo=s@path;

tempo=replace(tempo, "/ppHeroBuilding_forTexture/","");

@path=tempo;

Wednesday, 1 April 2026

stop shadow catcher from receiving shadows

Use the Light Linker, but switch the Link Type to Shadow Mask.
Now select your light sources and remove the shadow catcher from the Shadow Casters list.
This will prevent complex objects with detail from casting unwanted shadows on themselves (even though you've unticked self-casting on their object!)

like this-