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- 



Thursday, 20 November 2025

copying a weave onto uv

you need a weave pattern that is positioned between positive 0 and 1 , on the XY plane

you also need an object with good UVs.

The weave goes into input 0 and the target object is input 1.


Here's the wrangle.

 vector uvpos = set(@P.x, @P.z, 0);

vector pos = uvsample(1, "P", "uv", uvpos);

vector normal = uvsample(1, "N", "uv", uvpos);

@P = pos+(normal*@P.y*1);


Wednesday, 8 October 2025

sweep node, spiral / wrap a curve around a curve

 I always forget how to do this ,so here we are.
This creates a spiral loop around a provided curve (no need to add cross section)
Important bits - Round Tube surface shape, Columns surface type, control the twists in the rotation section.


random vellum rest length in houdini core

 To randomise the stretch rest length value on initialisation (not dynamic, it can't be animated like this). make a primitive wrangle between the vellum hair constraint and the solver.

I've used a connectivity node set to Primitives and changed the "class" attrib to "hairID". Here we affect the restlength value by multiplying it by some remapped randomness.

f@restlength*=fit01(chramp("remap",rand(@hairID)),chf("min"),chf("max"));