Cloth and flab

Making simulation meshes with Zbrush's ZRemesher: 

I'm a big fan of ZRemesher (exoside quad remesher in houdini/blender), spend some time cleaning the meshes, apply some useful polygroups and it'll usually give you something you can work with for sculpting at the very least. One thing it really excels at, however, is clothes, often giving you meshes better than you could probably make doing manual topology for them. And one of the other things ZBrush has going for it is an exceptional unwrap algorithm in UV master that gives you very low stretching. This got me wondering if I could use it to generate simulation meshes for cloth sim. 

Before we continue I should probably explain what makes a mesh desirable from a simulation standpoint. The best way to generate meshes for simulation is to use Marvelous Designer. Marvelous designer is a program where you draw flat clothing panels (much like cutting out real clothing patterns), it triangulates the panels randomly with points (vertices) at an equal distance, then uses cloth simulation to wrap it around your character. This is ideal for a number of reasons. 

Marvelous Designer, the layout on the right shows the flat cloth panels.

#1: Cloth simulations want equidistant points

Cloth simulations are at heart, a particle simulation, equal distance between all points is how you make the physical properties of the cloth identical everywhere on your garment. Denser or less dense sections will respond differently to physics. 

#2: Cloth simulations look more realistic when built the same way real clothes are, from flat panels

If you build your simulation mesh in a form fitting manner around your model then hit simulate, it's never going to pull/fold/fall or react like real clothes do because it's a theoretically impossible shape for fabric to be, fabric doesn't come out of the factory shaped like clothes are, it comes out of it as flat sheet that we cut and transform into the rough shape of a person, this creates all sorts of tension/compression and ripple conditions that won't be there if you have your magical space garment that is somehow the exact shape of your body.

Marvelous Designer is expensive as hell and slow to produce garments with, so let's see if we can skip all that jive and get a similar result faster with ZRemesher. 

Making the mesh in ZBrush:

Duplicate your body mesh and mask out the shape of the clothes you want, hit Ctrl+W to polygroup it, isolate and run delete hidden on the rest of the mesh. Under masking on the tool menu, mask the border, invert it, blur it a few times by ctrl clicking on the mask. Under the deformation menu, click the bubble off on the "Polish by features" slider and run it a few times.

Now for the fun stuff! 

Start polygrouping your cloth mesh into panels, if you're not sure how to split this up, go study real clothes (or google actual stitching patterns for them) and look at where the seams are. Here's an example of a t-shirt. If you're looking at clothing patterns and realising they're basically UV maps, you're not wrong! That will help us later.

T-shirt diagram from google

ZBrush polygroups equivalent (model has already been ZRemeshed for clarity)

Once you have your polygroups we can start to ZRemesh it, go to Tool -> Geometry -> ZRemesher, turn keep groups to on, set the Target Polygon Count to something reasonable for the size of your mesh (probably around 5 to 15), turn the "adapt" button off (and drag the AdaptiveSize slider down to zero just in case) and hit the ZRemesh button. With the AdaptiveSize all the way down to zero, ZBrush will try and make every quad the exact same size. This is getting us our equidistant points. Due to the nature of ZRemesher this is never perfect but it's close enough for this hacky workflow.  

From here I like to press the "half" button and just keep ZRemeshing it over and over again until it gets down to a polycount that I find reasonable, remember we can always subdivide it up again at simulation time. It may have shrunk a bit during this process, press W go to go to gizmo mode, then ctrl click on the inside yellow rectangle to "inflate" the mesh back out to clear the body again. 

If you're finding the edges of the polygroups are messing up or it's getting confused by them, you're either trying to go too low on the mesh resolution, or you can try ZRemeshing it without the polygroups and then applying the polygroups later (if it's made loops that are conducive to it). We need clean straight edges on our polygroups for the next step. 

Next we're going to go to the Zplugin menu and find UV master, set symmetry to "on" if your model is symmetrical, turn on the polygroups button and press unwrap. You can view the output by pressing the "flatten" button. This is getting us our flat panels. Later on in houdini we're going to extract the UV map as a seperate mesh and use it in our simulation. So you can unflatten the mesh to its original position around the body, export an .obj and call this step done.

UV master

Our eventual UV map, each polygroup forming an island.

Simulation in Houdini Vellum:

Once you have your files imported into Houdini and scaled to the appropriate size (houdini simulations require correct physical size). The first step is to extract the flat UV mapped version of topology. If you've ever heard people use the term UVW Map before it's because UVs are actually not two dimensional coordinates, it's a 3 part vector just like your Position attribute, however, the W (the vertical component) will always be zero in a traditional unwrap. You can think of a UV map as effectively a flattened blendshape of the mesh's normal form, which means we can swap the coordinates and replace our P attribute with the UVW coordinates. 

First drop down a split uv seams node to unweld the edges of the UV islands, then put in an attribute promote, by default the UV coordinates are going to come attached to vertices but for us we want them to be on points, so just move the value over to points on the attribute promote. Now we just have to drop down an attribute wrangle set to points and place in this VEX snippet to make our Position coordinates equal our uv coordinates. 

 @P = @uv;

One thing to note is that the scale of this will not match your wrapped version, UVs are generally normalised to between 0 and 1 so therefore the size of our flat versions will always fit within a 1 meter square. We are accounting for this by scaling it up again afterwards to roughly match (this will be explained more during the constraints sections). 

Triangles and quads are just collections of points, UVs are also just points, everything in 3d is just points, get used to it now!

Now we can start putting together the Vellum cloth constraints and get simulating. The meat of the setup here is that we're going to use two vellum cloth configures, one on the wrapped version and one on the flat version, then use the vellum rest blend node to transfer the restlength of the flattened version to the wrapped version, hopefully making it behave more like real clothing in the process. The restlength is the default calculated length from point to point, if the length is higher than the restlength, it's considered to be under tension, if it's less it's considered to be under compression. So effectively we're making the wrapped version think it used to be flat by transferring values from the flat version..

So drop down two vellum cloth configures (one on the wrapped version, one on the flat version), then on the wrapped version apply a vellum weld to stitch the edge of the islands together. Now it's as simple as putting in a vellum restblend node. You can check it's working by attaching a null to the middle post (the constraints data flow) and viewing the attributes in the geometry spreadsheet. From here you can chuck down a vellum solver node and view the results. Immediately you'll find that the second transform node we placed after the UV flattening to scale it up again is extremely relevant, you need to fiddle with that until the cloth rests naturally on your character without immediately contracting or flopping out larger. I ended out with a scale of around 2.15 on mine but yours will be wildly different depending on the size of your garment and character. We are effectively manually changing the restlengthscale attribute by scaling the mesh up and down like this. 

Even after all that I found the cloth didn't rest on some regions as nicely as others, you could go back into Zbrush and start messing with the original mesh or you could modify the restlength with an attribute paint in Houdini to start making some regions contract or expand. Place down an attribpaint on the middle post and name the attribute something you'll remember like "mask", paint in the region you want to be either tighter or looser, you can put an attribute blur after it to spread it out further if need be. Promote the attribute to be a primitive and not a point attribute then run this attribute wrangle.


float mod = @restlength * 0.6;

@restlength = lerp(@restlength, mod, @mask);

In this case, I want the white painted region there to contract as it was too loose, so I'm multiplying the restlength by 0.6, if you wanted it to be looser, you would set it to something like 1.2 or 1.4.  The second line is using the mask we painted to blend (lerp = linear interpolate = blend them basically) between our multiplied restlength and the original one, wherever the mask is white we have our modified value, wherever it's black we have the original. 

Add a vellum post process node to stitch our welded edges back together for render and smooth the sim out, then view your handiwork! 

Here's a screenshot of the entire node graph and a .HIP file so you can follow along better. 

Conclusion: 

So was it worth it to make the flat version of this simulation for increased realism? honestly, hard to say, the fact we have to scale the flattened version means a perfect 1 to 1 comparison between it and just running the wrapped version is impossible. But hopefully the process discussed here helps explain a little bit about how simulations like these work and how we can manipulate them to do our bidding.