Highlight for this release is Performance, and is part 2/4 of the new Markers.
- ADDED Performance Less work, greater parallelism and more GPU
- ADDED Overlap Groups Fine control over what overlaps with what
- ADDED Asleep Start simulating on first contact
- ADDED Ignore Gravity Because sometimes, you don't want to play by the rules
- ENHANCED Quality of Life Automated clean-up, support for Z-up and more!
You know the drill, we'll start with some eye candy. 🍬
Now more like actual candy. Nom nom nom!
Quick! Get inside!
Do the Robot
Model and Rig courtesy of Amedeo Beratta
Made by @tris
Guide Space Mania
Oh the trickery you can get up to. 🥳
That's right! Ragdoll turned 1 this week! 🥳
In my original business plan, I had written..
"Revenue, year 1: £20,000"
..which was blissfully optimistic. However! I'm happy to say that Ragdoll blew past this in the first 6 days into launch, on the 28th of July this year. Very few startups achieve this amount of revenue in year 1; the vast majority achieve £0 for the first number of years (I watch a lot of Dragon's Den 😅), the expectation being that they will regain their investment once enough value has been created. But given we're past this point already, this to me is validation that you want this.
So, let's keep it going, shall we? :)
Throughout these notes, I'll be using this guy here. Feel free to download and play around with it.
This release was all about performance, so how did we do?
In short, very well! We're now a lot closer to the capabilities of your hardware with a lot less waste. Because you see, software development is a lot like Jenga. You start off with a tower full of bricks, but every brick adds to the overall weight of the tower. And not every brick is necessary to keep it standing. The Eiffel Tower is an example of what a structure can look like with the absolute minimal amount of material. It is an optimal shape; anything added is wasted weight, anything removed would sacrifice stability. That is the structure we've been working towards with this release.
In terms of time spent, Ragdoll has three stages.
||This is primarily your character rig - the transform hierarchy, constraints, any deformers, and so forth. It is how data is passed from Maya into Ragdoll.|
||Once data has been aquired, Ragdoll considers all of it and applies forces, solves constraints, contacts, that kind of thing.|
||Finally, we need pixels. In the case of Ragdoll, this means generating and uploading geometry to the GPU; including capsules but also your meshes which are converted into "convex hulls".|
Simulation has always been fast and in the previous release, we focused entirely on workflow which had an indirect impact on
Rendering. One got faster, but the other got slower.
Changes in Part ¼
Let's recap what happened in the previous release.
We tackled Evaluation which boosted performance by 2-10x by unlocking parallelism. Before, the better your character rig benefited from multithreading the worse it would perform with Ragdoll. Ragdoll would force any control you simulated into serial evaluation - to compute one after another - because the solver was fundamentally single-threaded.
With Markers, Ragdoll separated from the overall rig evaluation, which meant (1) your rig can continue running in parallel and (2) Ragdoll could also run in parallel.
Consider this example.
This is how Maya scheduled evaluation for this scene with
Marker. To the left, everything runs one after the other. It's terrible. To the right, every box is evaluated in parallel. Which means the more boxes and cores you have, the better utilisation you get.
The scene itself is very simple, it's this one here.
So evaluation got faster, but rendering got slower. All-in-all we gained about 100% performance.
With this release, we'll tackle that rendering block. Let's have a look at what's changed, in order of most-to-least significance.
|Less CPU to GPU communication||1550x||More buffers, less uniforms|
|Connection Monitoring||40x||Less dependence on time, more on physical connections being made and unmade|
|Change Monitoring||40x||Ignore anything that hasn't actually changed|
|Less Dirty Propagation||3x||Less of a shotgun blast, more like a sniper|
CPU to GPU Communication
The previous release, and each one before it, had 1 shader per rigid. In the case of 600 rigid bodies, that meant 600 shaders. 600 shaders means 600 parameter updates of primarily color and 600 unique draw calls.
On top of this, all geometry was regenerated and re-uploaded to the GPU on every frame. Robust, but not very fast.
This release consolidates all shaders into one, colors are uploaded only once alongside their geometry and rendered using a custom GLSL shader (i.e. OpenGL 3.3).
What about DirectX?
If you are on Windows and can't use OpenGL for whichever reason, there is backwards compatibility built-in.
from ragdoll import options options.write("useShaders", False)
Or via the Ragdoll Preferences.
Bearing in mind this will cost you 50% of the rendering performance and won't benefit from future shading related features and improvements. The option will remain until it's clear whether and how much it is actually used. (Let us know in the chat!)
Let's have a look at how this change affects your overall experience.
After (130 fps)
A closer look reveals exactly where this improvement comes from.
This block is what we control, it's the Ragdoll rendering pipeline taking a whopping 93 ms per refresh.
With this release, this number dropped to 0.06ms (58 microseconds) that's an improvement of 1550x (!).
What about the other blocks?
The bottleneck has now moved to that green one and all of those blue, and those are Maya's internal rendering pipeline.
There isn't much we can do to directly impact it; it's mostly out of our hands. However, by massaging our data more and making life easier for Maya it should be possible to reduce these as well.
Finally, as a result of having complete control over the shader running on the GPU, we're now able to more intimately design it to look the way we want. Expect more refinements here over time.
Connection & Change Monitoring
In the previous release, and all versions of Ragdoll so far, we've tasked Maya with evaluating every plug on every frame, including the heavy-duty plugs between
Rigid Body ->
Here's what this felt like in a scenario of 600 unique objects.
Before (5 fps)
Painful! The reason is because even though we're only moving a single box, Ragdoll checks-in with all other boxes too.
After (90 fps)
Blissful. In this case, only one of the boxes is actually updated, as one would expect.
Let's have a closer look at where performance is going here.
Oh that's ghastly. Not only does it spend time evaluating all of those boxes, but it's making the solver take much longer consolidating the results taking a whopping 56 ms.
Whereas now, as one would expect, we're only evaluating this one box in a total of 0.7ms, resulting in a performance improvement 80x.
That looks like 3?
And that's true, it still makes three separate calls to this one box. Which means there's more room to optimise here, and we'll get there.
Needless to say, this happened before as well but was obscured by how many calls there actually are. Luckily, at least two of these calls happen in parallel.
The current framerate on 600 unique objects, something for future Ragdoll to try and compete with. For reference, an average ragdoll consists of about 20-30 objects.
There is at least 4-16x performance left on the table for specialised cases.
|Optimised Render Items||4x||Native Maya still renders 4x faster than us, which means there's more things we can do.|
|Instancing for Rendering||2-4x||Every render item is currently unique which means neither Maya nor your GPU is able to reuse geometry. Instancing is how games is able to render millions of objects on-screen at 60 fps, and best we can hope for is thousands.|
|Instancing for Simulation||2-4x||Likewise, every physics object is unique and, again, instancing in simulation is how games is able to run destruction and have thousands of objects interact in real-time.|
The challenge in both of these is deduplication; of identifying which of the many shapes you use can reuse their geometry.
Specify which markers may overlap rather than collide. This can be useful to enable dense areas of a character, like the clavicles, where there is natural overlap amongst large shapes like with the neck and spine.
||No overlap allowed|
||Default, respects self-collision on the group (if any)|
||Overlap everything with the same number|
rdMarker part of a
rdGroup can get an overlap group assigned procedurally, based on other members of that group. For example, in a complete ragdoll, all markers are part of the same group. So a
Self Collide = On means these will all be given the same overlap group.
If it isn't in a group, then
0 is the same as
-1, in that it will collide with everything.
Let's have a look at a few scenarios.
Collide with Everything
In this example, every marker is part of the same group. The group has
Self Collide = Off, which is fine for just about every marker except the fingers. In that case, we do want self-collision, so they are given the group
Respect Self Collision
In this case, we're happy with a default group of
0 since we don't need anything to self collide. Especially these clavicles that overlap significantly!
Finally, for the very specific cases of wanting two or more markers to overlap. Notice how we give both the ground and 3 of the boxes an
Overlap Group = 5.
Sometimes, you want things to stay put until something comes into contact with it. That's when you can tell a marker to start asleep, and "wake up" when necessary.
It surrounds us. It penetrates us. It binds the galaxy together. But sometimes, you just don't care.
Quality of Life
A few things to make your day that much more bright. 🌞
Guide Space 2.0
In the previous release, we introduced
Guide Space. Which was a quick way of controlling whether a simulation should follow your animation in..
- Local Space
- World Space
But it was challenging to control, not very obvious. Especially with how it was also taking into account its "group" guide space. This release addresses this by enabling you to specify a guide space for all markers and selectively override only the ones you're interested in. Just like how the
Input Space works.
Group Guide Space
Override all guide spaces, by editing the group.
Marker Guide Space
Or gain surgical control over guide space per-marker.
Delete All Physics menu command does what it says on the tin; it deletes all Ragdoll nodes from your Maya scene. But deleting a node, such as the new
rSolver left behind anything associated with it, like
rGroup and any
This releases addresses this by automatically removing anything that depends on the node you delete. For example..
- Deleting a
rMarkernode also deletes any associated lollipop controls
- Deleting a
rGroupalso deletes the associated
- Deleting the
Therefore, deleting a solver is now equivalent to
Delete All Physics, making it much more intuitive to delete things on a whim.
Minor cosmetic improvement, the
Reset to Default button now has an icon so you can actually tell it's a reset button (and not a bug, as many have pointed out 😅).
The default plane and solver offset was a off in the previous release, this fixes that. You can also manually re-adjust the plane and remove and orientation from the solver node to fix it locally, the solver itself is A-OK.
Rather than having to specify which frame to start simulating at, Ragdoll can now keep track of your animation start frame. Either the start of the range, or the full timeline. Or, you can still set a
Custom start time for when you do care about specifics.
Monitoring for and responding to changes is a hard problem.
Odds are some things aren't updating the way you expect, which could affect viewport rendering, or worse, the actual simulation. If you encounter any such issues, please let us know in the chat or ping me directly at firstname.lastname@example.org
Here are the currently known issues that we'll be fixing once a solution presents itself.
As an unintended consequence of the optimisation and shader work, we're currently compliant with Maya's requirement for motion blur. Since all of our simulation is transform-based, it means all of what you simulate can be motion blurred, as opposed to deformer and particle-based motion.
It won't work with any animated attributes, which makes it rather limited in what you can use it for. 🤔
Maintain Offset IK/FK
If you retarget a marker, the difference between the original and target is stored.
When you record, you have the option to
Maintain Offset. That's important if the assigned control has a different position and/or orientation than the destination control. For example, you can assign to a joint, but record onto a NURBS control.
For example, IK joints are assigned markers but are retargeted onto FK controls, it's important that you retarget when they are both in a similar pose. Otherwise, the difference between them will remain after recording.
To combat this, you have two options.
- Do not maintain offset
- Make sure IK and FK match when you
(1) may not always be an option. If the position and/or orientation of an assigned control is simply different, then there isn't much you can do. :(
(2) is your best option. If you make a mistake, you can always re-retarget to the same control again, and the offset will be updated.
Recording Kinematic Markers
When a marker treats the input as
Kinematic, it means it won't simulate it. It'll be 100% locked to animation. If that's the case, then there's really no point in recording those keys, right? Because they'd be 100% identical to the animation?
Except! If there's a parent, then we'll still need those keys to compensate for the parent not being kinematic.
Let's record without kinematic keys. Notice how the hand isn't given any keys, even though it needed them?
Record all keys, and the hand - even though kinematic - will still get recorded.
Record to Custom Attributes
Sometimes, rotation isn't coming from
Rotate X but rather a custom
Ball Roll attribute on a different IK control.
As Ragdoll only understands
Rotate, how would you go about recording onto this attribute!? Here's what you can do.
- Create a new Locator
- Retarget the foot to this Locator
Locator.rotateX -> R_foot_CTL.ballRoll
Now Ragdoll will record onto a familiar channel, and Maya will handle the conversion back onto the rig.
Like in earlier versions, drawing constraints are the slowest part. If you don't need them, disable them. You can do that either on the
rSolver node, or individually per
Some well-hidden but essential resources for any of the above. If you are into anything related to Maya plug-in development and performance, you'll treasure these as I have.
- Parallel Evaluation
- VP2 API Porting Guide for Locators
- VP2 API Porting Guide Part 1
- VP2 API Porting Guide Part 2