I have found a solutuion to using skinned clothing layers in Houdini's crowd system.
This method involes saving clothing geometry in T-pose, or whatever rest pose your rig uses.
In my case, I am generating characters using Reallusion's Character Creator, which alows a character, with clothing to be posed in any position. The rig I am using comes from MocapOnline which has a T-pose rest position.
It is possible to use any pose, if the rig is key-framed before frame 1 and animated to rest position at the start of the clip. There is a step-by-step demonstration of this process by Kevin Ma, which clearly explains what to do.
What I want is to have an agent with multiple shirts, trousers and shoes. A few of each will give a reasonable variety. I plan to vary the shader on each piece of clothing too, but that will come later.
I need to generate a few versions of my character and save out the geometry. Character Creator can output obj and FBX formats.
Here are the variations of my character that I generated:
I will be using shirts from all five but just three trousers and shoes.
I have named these geometry meshes as MALE_01_VAR_01.obj, MALE_01_VAR_02.obj, etc.
Here is what the geometry and rig look like once they have been imported into Houdini.
The third picture shows the geometry and materials that comes with the MocapOnline rig. We will not need these so they can be deleted. We will replace the geometry with our own.
Rename the FBX import node as RIG
Now we will create an un-clothed agent:
Inside RIG, Create a geometry node, name it MALE_01
Jump inside MALE_01 and create a file node.
The file node should point to one of the obj files exported from Character Creator, let's say MALE_01_VAR_01.obj
That file will have clothes but we are going to remove those clothes.
Geometry exported from Character Creator has primitive groups, which is very useful in this next step.
We want to blast away all the primitive groups belonging to the clothes.
Follow that blast node with a null.
This is now ready for skinning to the rig.
Jump up one level so you can see the rig and the geometry object.
Select the geometry object and on the Rigging shelf, press the Capture Geometry button.
The viewport will prompt you to select the root node of the rig. Do that and press enter in the viewport.
After a short calculation, the goemetry will be skinned to the rig. Sort of.
If you see this kind of result, it's because the bind is calculated at frame 0, not frame 1. SideFX in their infinite wisdom have made that the default. It's easily fixed, though.
Jump into the geometry node again. You will see some new nodes.
The node called Bone Capture Lines has an option to specify which frame to use for binding the geometry to the rig. Set that parameter to 1. Then, on the Capture Cache node, press the Stash button. You should now have a properly skinned character.
Jump up to the /obj level and make a new Geomotry node.
Jump inside and drop down an Agent node.
The agent should have the Input set to Character Rig and then specify the RIG node with the rig and geometry inside.
You can import clips in the usual way, and then cache out the agent using the AgentDefinitionCache node.
The details of this process are covered in another post, so I will not spend too much time discussing these steps.
Now for the clothing layers.
Jump inside the RIG node again. We are going to create skinned geometry in the same way that we did for the unclothed body.
Greate a new Geometry node. Rename it MALE_01_SHIRT_01
Inside that node, drop down a File node and import MALE_01_VAR_01.obj
We want to delete everything except the shirt geometry, so use a Blast node and in the Group drop-down, choose the primitive group that refers to the shirt and then check the box 'Delete Non Selected'.
Now you just have the shirt. This can be skinned to the rig, as before.
Jump up one level, select the geometry node with the shirt geometry and press the Capture Geometry button on the Rigging shelf.
Again, you will probably have to set the capture frame to 1 and then hit the Stash button, just like we did before.
So you should now have a shirt skinned to the same rig as the body geometry.
We can make an Agent Layer from this.
A couple of critical points to note here:
Do not use a Source Layer. We want the clothing on it's own, without any body geometry. We are adding the clothing to the default Agent layer, which is the body, so we do not want another copy of the body.
Bind the clothes shape to the Root node of the rig. Because the clothes shape is skinned, it will follow the Root node the same way as the body does.
Repeat this for all the clothes layers you need.
Save the Agent definition using the AgentDefinitionCache node.
Bringing the Agent into a new scene and using the shirt layers requires an Agent SOP with the Input set to Agent Definition Cache. The agent will have a default layer and all the new clothing layers ('shirt_01', 'shirt_02', etc).
To have some agents using the default and some using the shirt layers, I have used 2 Crowdsource nodes.
One node is used for the default layer and the other to chose a random shirt.
You can use the wildcard ('*') to allow Houdini to randomly select a shirt with equal distribution, or you can have a more guided selection, allowing you to choose the probability of which shirt is chosen
The clothes should follow the body with any animation clip that the agent is playing.
My skinning skills are limited, which is why there are some areas of inter-penetration, but with more careful skinning these can be fixed.
When planning a Stadium Crowd, there are a few things to consider:
Probably the most important question is "how close to the camera is the crowd?". In most cases, the the crowd will be far away, in the shade and motion blurred. That may not be the best conditions to showcase your work, but it does allow you to work with lower quality assets with faster render times.
Is the crowd system to be customisable for multiple scenarios? I was inspired by the work by Postoffice's Crowd and Stadium Tool to start creating a system that can be used for any team in any stadium.
What assets do you have? Do you have a variety of 3D characters that are rigged? Can you get access to high quality motion capture? Do you have a model of the stadium? Where are you going to get these assets? In my case, I was luck to to have a good model of a stadium (Machester City, Etihad stadium) but there are options out there for free stadium models. You may need to add seating to these models or modify them to suit your needs, but they are a good start.
Break it Down
To create an effect like a stadium crowd, the best strategy is to break the job down into smaller parts while still being concious of the whole pipeline.
First up are the assets. We will need the folowing:
Geometry for placing the characters
Environment and lighting
There are several sources for gathering character assets. Mixamo has a few that would be suitable for stadium crowd work (Brian, Adam, Liam, Shea, Malcolm, Kate, Suzie, Elizabeth). These are free, rigged and come with animation clips.
If you need higher quality, you may find free models online. Have a look on cgTrader, TurboSquid and Sketchfab.
Another way to get high quality models is to generate them yourself using software, such as Reallusion's Character Creator.
This software can generate character meshes in Obj and Fbx format, posed as you like.
Clothing can be varied using the built-in library but that library is quite limited. However the library can be extended using clothing geometry from other sources.
Here is an example of a character with clothes from the built-in library
Another example using a modified texture and custom decals on a built-in garment
An example of a mesh (hooded sweater) imported into Character Creator
It is also possible to import textures for skin and faces. Here's Pep:
These meshes can be exported from Character Creator as FBX, which will produce a single mesh with primitive groups which will become useful when breaking the mesh in Houdini. The export will also save out texture files for each of the seperate mesh groups. Textures include Diffuse, Normal map, specular, roughness and maybe one or two others, depending on the materials on the clothing. Some of these textures will be too much detail for a Crowd simulation, but they are there if required for close-up shots. I would consider Crowd FX unsuitable for close-up shots, so I only use the Diffuse and Normal maps in most cases.
I have found a way of assigning random colors for the crowd agents.
1. Create a shader for your agents, called variation.
2. Create an attribute either on the points from which your agents are generated or on the crowd_sim_import node, which is the node that reads back the simulated agents.
3. Create a stylesheet override, so that your agents pick up the variation shader.
4. In the variation shader, create an Inline Code node.
The inline code node creates the link between the packed primitive and the shader. The renderer looks-up the attribute and passes the attribute value into a new variable inside the shader. You can then use that variable to alter the look of the shader. In my case I just used a rand node to apply a random colour and piped that straight into the shader output without any lighting.
Here I present a method of adding vellum cloth to crowd agents.
This is based on the SideFX example scene 'Simple Crowd Cloth' which you can find in the Houdini Help page for Agent Vellum Unpack.
I have modified the setup to allow the cloth object to be attached to a prop which the crowd agent is holding.
First we need an agent. For this tutorial, I have chosed a mocap animation from Mixamo. They are good quality, adaptable and free.
Go to mixamo.com and choose a character you like. I chose 'Brian' because it is the kind of character you might find at a football match waving a flag.
I wanted to find a clip where the character was holding and waving a prop. The closest I found was the clip called 'Standing Torch Inspect Upward'
Download this clip, with skin, and save it in a new Houdini project.
In Houdini, create an agent: Create a new Geometry object, jump inside and create an Agent SOP.
In the Agent SOP, choose FBX as the Input and browse to find the FBX saved from Mixamo.
Be careful here: Scale is extremely important when it comes to dynamic simulations. Make sure you check the Convert Units box. You do not want a human agent that is 150 metres high!
Name the clip in the agent SOP and name your agent as well.
Next, make a flag and flagpole. The rig does not have a prop joint, so we will have to manually place the flag and pole manually in the right position.
The pole is just a simple Tube SOP and the flag is a simple Grid SOP transformed into place.
One detail - I made a group of the flag vertices closest to the pole. That group will be used later to attach the flag to the pole.
Now we have to define the flag geometry as a Vellum object. To do this, simply drop down a Vellum Configure Cloth node and plug the flag geometry into the first input. We need the pole geometry to act as a collision object so that the flag can attach to it. Plug the pole geometry into the third input of the Vellum node.
So, now the flag is a Vellum cloth object, we need to add it to the Agent definition.
First, it must be packed. Use the Vellum Pack node to do that.
Now we need to add the new geometry to the agent as agent layers: first the pole layer -
Then the flag layer.
Note that we add the Vellum cloth version of the flag to the Agent Layer.
Also note: the flag layer also contains the pole object.
This is needed to allow the flag to attach to the pole later on.
Now that the Agent Layers have been created, save out the with Agent Definition Cache node (or use an Agent ROP node)
We are now ready to test the agent.
Back up in the /obj world, create a new Geometry object. Jump inside and drop a new Agent SOP and this time read back the agent you cached out. Choose Disk as the input and make sure you choose the same Agent Name used in the agent setup.
When you first load the agent, the flag and pole will not be visible. That's because they are on layers.
In the Agent SOP, choose the flag layer as the Current Layer. The flag and pole should now be visible.
Now we need to unpack the Vellum flag. There is a node to do this: Agent Vellum Unpack.
Here we want to choose select by Agent Layer and pick the flag layer.
The Shapes to Simulate is just the flag. We do not want to simulate the pole, just have it present for the flag to attach to.
The Agent Vellum Unpack node retrieves the Vellum cloth from the Agent, plus any collision geometry, that includes any geometry connected to the Vellum cloth node when it was created and the Agent geometry as well.
Now we can attach the flag to the pole, since the pole was added as collision geometry earlier.
Drop down a Vellum Attach To Geometry node and connect all three inputs to the previous unpack node. If Show Guide Geometry is checked, you can see all the collision geometry (in blue). There is the pole, ready for the flag to attach to.
You can specify some vertices or edges for the flag to attach to, but usually just using the Constrain to Closest Point will be adequate.
Now the flag is ready to simulate. Drop down a Vellum solver and plug all three inputs. You should have the flag attached to the pole and the pole being waved around tby the agent.
Of course, you want more that one agent. So, make a crowd.
Drop down a Crowd Source SOP and connect it just after the Agent SOP.
Now you will see lots of flags and lots of blue agent collision object.
If want to see agent geometry, you need to merge the flags with a different Agent Layer.
The pole layer contains the agent and the pole geometry. So, drop down an Agent Edit node and use that to specify the pole layer. This can then be merged with the Vellum cloth flags.
There you have a crowd of flag waving agents - perfect for your next stadium crowd project!
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 Mixamo.com 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!