USD has a few ways of doing instancing, and again assume I've done my speil here about how it works in all the packages yeah yeah blah blah.
Here's a simple instancing setup that should make sense to most Houdini folk:
- Duplicate yet another pig head reference node, put it in some clear space in the node view
- Create a point instancer, display it, connect the reference to the second input
- On the instancer, scroll down to 'prototypes', set prototype source to 'second input'
There, we see a pig again, but not just any pig; this is an instanced pig. See for yourself; look in the scene graph tree, there's a 'addpointinstancer1' prim of type 'PointInstancer', and underneath it is a prototypes folder, with a root node below that.
'Prototype' is what USD calls 'the geo to copy', or if you're used to a copy-to-points in houdini, is what you'd connect to the first input. Here we set the parameter to find the geo to copy from the second input.
If you're used to Houdini, you'll be looking for where to connect the points. Look at the parameters again, near the top there's a 'Target Points' section, with 'Location Source' set to 'Internal SOP'. That implies we should dive inside and see what's going on...
- Dive into the addpointinstancer
- Aha, we're in a Geometry (ie, sops) context now, and there's a single add sop, that is what's generating the single point (and hence the single pig for the instancer)
- Create a grid, set the display flag, woo, lots of pigs!
- Note that the display mode is ghosting the lops view from above. If you don't want that, set the display mode to 'hide other objects' on the viewport.
- Append a 'scatter and align', set sliders to randomise scale, rotation etc
- Lops is taking care of the translation from Houdini to USD for you, so pscale, orient etc are being converted to native USD point instancer attributes.
- Jump back up, feel smug.
You might ask why is this setup this way, why not just work exactly like copy to points, geo on the left, points on the right?
Ok, if done that way, how would you wire this inline, like we've done so far with all the other nodes? Ok sure, maybe it could have 3 inputs, but I hate 3 inputs.
Generally the left input is for the stuff that you're passing through, what you're building on top of, and right input is for whatever you need it for.
But that's not set in stone. If you look in the tab menu there's a few instancer/copy to points looking options, that all have the same icon:
- Copy To Points
- Point Instancer
- Instance to Points
If you compare them, they're all the same node, just with different parameter settings. There's a reasonable amount of flexibility of which inputs do what, but I find the above method makes the most sense to me.
Instance multiple shapes randomly
The USD instancer also has a trick that the native Houdini Copytopoints only got relatively recently; you can have have a library of shapes, and instance them in various ways.
- Create a cube and a sphere lop, insert them between the reference and the point instancer
- On the point instancer, scroll down to the Prototypes section
- Disable 'Use Entire Stage as Prototype'
- Set 'Prototype Index' to 'Random'
- At this stage you'll probably see only spheres, or whatever is the final node before the instancer. This is because the 'Prototype Primitives' field has an expression that tries to find the name of the prim defined in the previous node. Lets fix that.
- Change the Prototype Primtives to * so it will be able to choose from all the inputs, ie the pig reference, the cube, the sphere
- Change the seed value to mix up the randomness.
The random behaviour above is set via a random 'index' attribute that is setup for you, but you can override that if you want explicit control.
- Change 'Prototype Index' to index
- Slide through the index slider, you'll see 0 is the first shape, 1 the second, 2 the third.
- Change the mode to index attribute, note that the next parameter changes, to tell you it will look for an attribute called index. Cool. Dive inside the instancer.
- Bypass the scatteralign sop, append a point wrangle
- Use this code to have the index's cycle over the points, and have pscale be 0.3:
i@index = @ptnum%3; @pscale = 0.3;
There you go, full control.
Fair warning, 18.5 on a macbook pro is pretty unhappy running a point instancer. Geo gets stuck in the viewport all the time with the opengl view, trying to reset the view by making a new scene view often crashes. My memory was that this is all more stable on windows and linux, but yeah, ugh.
Usually karma is a much better ground truth for how things shoudl look, if you go to the top of the viewport where it says 'Houdini GL', click to bring up the menu, change to 'Karma', things behave. Karma is the Lops native USD renderer, more on that when we get to the rendering chapters.
You'll see `lopinputprims('.', 0)` pre-filled in on a lot of nodes, whats that about?
It's the lops equivalent of `opinputparm('..',0)` people often use in Dops.
As mentioned before, this is a helper function to tell you what node was created or modified by the previous node (or more explicitly, `lopinputprims('.', 0)` for the first input, `lopinputprims('.', 1)` for the second).
This is there to hopefully reduce typing and clicking for you. I mentioned a few chapters back that USD prefers to have a big scene all assembled together early, then you do atomic edits on single things as required.
Now think about how sops behave. If you put down a transform sop and rotate stuff, by default it will just translate all the geo fed into it, you have to opt-in to use groups, or ad-hoc expressions to limit its affect.
If Lops nodes behaved that way, it would be a disaster. You'd put down a transform sop, and by default it would try and move your entire coco set. No bueno. But Houdini users are so used to things moving without selecting stuff, they'd get confused and cranky if Lops defaulted to having nothing selected for every node.
Hence, this expression. It tries to make a guess as to what was created/modified in the upstream node, and only works on that. You can override this by dragging prims from the scene graph tree, or using the select arrow button on the right of the parameter and selecting in the viewport, or cmd-clicking the arrow, which brings up a pop-up scene graph tree to let you select stuff.
This also explains why some nodes appear to do nothing; if you midde click the parameter with the expression, and it returns an empty string, it wasn't able to find a prim in the upstream node, so you'll need to fill it in yourself.