Wednesday, 10 June 2020

Houdini Crowds: Texture variations

Here is a method I have used to vary textures on crowd agents.
I use a Colour Mix node to add a new colour, chosen from a ramp using a per-agent variable.

I will use a Mixamo character as they are freely available.

Go to and download a charater of your choice.
I have chosen 'Elizabeth' because she has a textured shirt, which requires a slightly different method.

In Houdini, import the FBX

If you jump inside the FBX network, you can see the rig plus the geometry nodes and also a material network.

If you jump inside the materials network, you see the shader networks for the model geometry. It is here that we will make the modifications.

Here we can see one particular shader which references a texture. When a FBX file is imported into Houdini, any file textures are kept internally and may be referenced using the '.fbm' file path. It would be useful to have those textures extracted when the FBX is imported, but that is not the case with Houdini. If you require these textures as seperate files, you can import the FBX into another 3D application such as ZBrush, which will save the textures in a FBM folder.

Before we can get stuck in to the shader network, we need to create a crowd agent.

Create a new Geometry object and inside it drop down an Agent SOP

Choose Chracter Rig as the input and select the FBX network. Name your agent and the clip.

We want to see some variations in texturing so lets hae a few agents to look at. Drop down a Crowd Source node.

Now we can move on to creating variatons. We will need a new attribute to choose a random colour for each piece of geometry that we want to vary.

After the Crowd Source node, drop down an Attribute Randomize node.

Choose a descriptive name for the attribute. We want a scalar float in the range 0 to 1, so set Distribution = Uniform, Dimensions = 1, and Min and Max to 0 and 1

Looking at the Geometry Spreadsheet, you can see the new attribute has been created with values between 0 and 1. Perfect!

Now, we can use this attribute in the shader network. Jump back out of the crowd object and into the FBX network.

Have a look at the geometry we are altering. See which shader it is using. In this case, the Pants Geometry is using the 'ch26_body' shader.

We need to put a node between the texture file and the shader, but remember that the texture file is referenced internally. We can still access it by using that internal reference.

Jump into the material network and select the shader. In our case it is 'ch26_body'
On the Textures tab, you can see the referenced texture file. Copy the path, in our case '.fbm/Ch26_1001_Diffuse.png'. We are going to replace that internal texture reference, so un-tick the Use Texture checkbox.

Drop down a Texture node and paste the path in the Texture Map box. Connect the output of the Texture node into the Basecolor input of the shader.

So, now we have extracted the texture file from the shader. We can introduce something in between the texture and the shader.
Drop down a Color Mix node. Connect the output of the Color Mix to the Basecolor input of the shader athen connect the output of the Texture node to one input of the Color Mix.
Next, create a Ramp Parameter node and connect its output to the second input of the Color Mix node.

Impotrant: There is a little gotcha here: ALWAYS name your ramp. If you forget to do this and then go on to make more ramps, Houdini will not know which ramp you are referencing.

The shader will mix a value from the ramp with the colour from the texture map. But which colour will the shader choose from the ramp? We can now use the attribute created earlier to tell the shader where on the ramp to choose the colour.
Instructing Houdini to look up attributes at rendertime involves using the 'renderstate' VEX command. We can set this up in a shader network using the Inline Code node.

The Inline Code node runs a VEX snippet and outputs local variables.
In our case the VEX snippet is one command - renderstate.
The renderstate command can look up data on the currently rendered object. We want to look up the 'pants_colour' attribute. That attribute is packed away in the crowd agent, so we need to access that using the 'packed:' prefix. The renderstate command reads that attribute and stores it locally in a variable '$pants_colour'.
We can output the value of that local variable in the lower section of the Inline Code node.
Set type to Float. The first box is the name of the attribute which we are outputting from the Inline Code node and the second box is the label.
Connect this output to the input of the Ramp Parameter node.

If you render now, you will not see any textures or variations yet. That is beacause we have not setup the Material Style Sheets yet.

So, let's do that. Create a new Pane Tab in Houdini and make it a Data Tree type. In the Data Tree, select Material Style Sheets from the drop down list.

We want to add a style sheet to the object we are rendering. In our case it is the Agent_Setup object.
Browse to that object in the Stylesheet editor and right-click and choose Add Style Sheet Parameter.
Next, right-click the Style Sheet Parameter and choose Add Style
Next, right-click the Style and choose Add Target
Next, right-click the target and choose Add Sub-Target. Here you ca specify which agent will take the override. In this case we only have one agent, so we can leave the wildcard '*' as default.
Next, right-click the Sub-Target and choose Add Condition.
The condition we want is Agent Shape, so select that from the drop-down list. In the Value text box next to it, type *Pants. That is the name of the geometry object in the agent we are applying the override to.
Now we need to create the override.
Right-click the Style and select Add Override
The override type we want is Set Material, so choose that in the drop-down list.
In the Override Value column, you can pick the material to use. Select the 'ch26_body' shader.

You may now render.

Of course you will want to repeat these steps for all the geometry object that make up the agent (hair, skin, shoes, etc).

I will show one more tip for the textured shirt.
For the shirt, I wanted to blend how much of the Colour Mix was applied to the original texture. I created a second attribute 'shirt_blend' and sent that through a second ramp.

The second ramp is a Linear ramp, not RGB, and connected to the Bias input on the Color Mix node. This controls how much the colour from the Shirt_colour ramp over-writes the original texture.

For the body colour, I have found using a Color Correction node instead of a Colour Mix and a linear ramp, ranging from 0.25 to 3, plugged into the Value attribute works quite well.

Obviously, you will want to play around with the ramps and see what works best for your situation. Then you can expose the ramps to a controller object somewhere more accessible. I will write about that soon!

No comments:

Post a comment