2021.03.01
It's been an epic month of problem-solving, but it finally happened. :D Highlight for this release is.. drumroll.. Automatic Initial State!
- ADDED Auto Initial State Start simulating in whatever pose your character is in
- ADDED Hierarchy Preservation Moving parents around now correctly moves children
- ADDED Worldspace Constraints Animate in both local- and world-space
- FIXED DG Viewport Bug Fix for rare cases of viewport going out of sync
- FIXED Unload plug-in The Ragdoll plug-in can now be loaded and unloaded using the native Maya plug-in manager
- ADDED New Commands Developer candy, return a JSON of physics for export and import into another application, like Unreal, Motion Builder or Blender!
Tiger Rig courtesy of www.cgspectrum.com
Auto Initial State
Have you ever used the Set Initial State
button? It's useful, isn't it? It's what enables you to turn something dynamic but then change your mind about where it should start simulating.
With this release, that process is automatic! It's more or less what you expected would happen anyway. I mean, obviously the box should drop from where you left it, rather than where it was originally turned dynamic?
Disable Feature
If you would rather have none of it, or if it gives you trouble, you can switch it off like this.
NOTE: Changes take effect on next scene open and newly created rigids.
Parallel Only
That's right, automatic initial state will only work in Maya's Parallel Evaluation mode.
It may end up getting support for DG later on, the trouble lies in the callback we use to read an edited initial state is not reliable in DG. It's possible we'll find another means of achieving the same goal in the future, although DG really is part of the past. Ragdoll works best under Parallel for other reasons too; primarily performance but also stability and robustness.
Constraints Stay Behind
Constraints currently show you the true position of rigid bodies.
They stay behind because hierarchy preservation is "artificial". It's just for you and Maya. In a later release, I'll make rigids also stay behind, and only have your controls move with hierarchy, so that you get to visualise where rigid bodies really are (even when your controls have locked channels, like translate) whilst at the same time letting you move and see your controls and how they reflect that true position.
Caveat
There's one known "gotcha" with the automated initial state.
Namely, the initial state is "recorded" whenever you transition from the start time to the next frame. Evaluation on the next frame will automatically read whatever was evaluated previously, and store that as the initial state.
However! It is possible to trigger evaluation without actually changing time. Maya loves doing that. You can do it by either scrubbing the timeline, or holding K
and dragging (effectively scrubbing) the viewport. As you scrub, even if time isn't actually changing, Maya will go ahead and re-evaluated the time.
When that happens, it won't actually record a new initial state, but instead restore the original value. Something to be aware of.
Journey
For the technically inclined, here you can witness last month's struggle first hand and all the kinks uncovered in Maya's API and evaluation graph.
Hierarchy Preservation
Like in the real world, physics happens in worldspace. There are no "children" and no "parents". As a result, as soon as you turn any of your controls dynamic, they start acting that way. But we don't want that.
With this release, you'll now get realism along with that familiar feeling of having children and being a parent!
Before
After
Caveat
There is one known case to be aware of when it comes to children.
Passive Rigids
Hierarchy is currently preserved only if a rigid is active. The reason being.. well, I'll just show you.
In this case, the passive rigid bodies are driven by an external transform, those blue "controls". Hierarchy is coming from the blue rigids, so we wouldn't want the passive rigids to mess with that.
But now when we move the rigids themselves (gray, in this example) we aren't getting our hierarchy preservation.. :(
At the other extreme, if we do account for hierarchy then the problem pops up at the other end instead.
I trust experience and feedback will light the way here for a more intuitive experience working with external controls.
Worldspace Constraints
If you thought automatic initial state was enough, think again! If your controls have animation already applied, Ragdoll will now translate it into physics in world- and local-space.
Default Behavior
Local animation, like a rotated arm, are imbued with a "local constraint" to preserve the relative angle between it and its parent. World animation, like in this case where there is no parent, get imbued with a "world constraint".
World Only
Here's what you get when constraining the child to its worldspace pose. Notice how it assumes the angle you give it regardless of whatever the parent is doing.
Local Only
Conversely, with just the local constraint, it'll assume the relative angle and respects its parent.
World + Local
Things get interesting when you combine the two!
World + World + Local
..or combine the three! Here's the lower arm trying to adhere to both its worldspace and local orientation. Notice the constraint coming out of alignment at the root; the constraints are of equal strength per default so it'll end up averaging the desired poses.
There's one more thing happening here that I'll touch on in an upcoming release, which is the concept of world space forces. Notice how the joint chain follows animation
DG Viewport Bug
If you've ever had the viewport "remember" old frames as you scrub the timeline, this fix is for you.
Unload Plug-in
In the previous release, licencing was implemented as a Python binding. The trouble with compiled Python bindings in Maya is that they cannot be unloaded. As a result, Ragdoll could not be unloaded.
Licencing is now implemented as a native Maya command, accessible as ragdollLicence
from MEL and cmds.ragdollLicence()
from Python.
New Commands
Three new commands was added in this release, they are primarily intended for TDs and technically minded folk.
cmds.ragdollLicence()
cmds.ragdollPeek()
cmds.ragdollDump()
cmds.ragdollLicence
Synopsis: ragdollLicence [flags]
Flags:
-q -query
-a -activate String
-d -deactivate
-h -help
-i -init
-ia -isActivated
-ig -isGenuine
-it -isTrial
-iv -isVerified
-md -magicDays
-r -reverify
-s -serial
-td -trialDays
You still typically interact with ragdoll.licence
, as documented here. But under the hood, this is now the native Maya command being called.
from maya import cmds
cmds.ragdollLicence(serial=True, query=True)
# Your-Serial-Number-Here
cmds.ragdollPeek
Synopsis: ragdollPeek [flags]
Flags:
-e -entity UnsignedInt
-h -help
-ps -physicsStatistics
-ss -sceneStatistics
Gain insight into what Maya sees in Ragdoll.
cmds.ragdollPeek(sceneStatistics=True)
# Ragdoll Peek Scene
____________ ___________________________ _______________
| Id | Scene | Name |
|------------|---------------------------|---------------|
| 71 | rSceneShape | rSceneShape |
| 70 | rSceneShape | rRigid18 |
| 69 | rSceneShape | rRigid17 |
| 67 | rSceneShape | rRigid |
| 65 | rSceneShape | rRigid7 |
| 63 | rSceneShape | rRigid8 |
| 61 | rSceneShape | rRigid14 |
| 59 | rSceneShape | rRigid15 |
| 57 | rSceneShape | rRigid16 |
| 55 | rSceneShape | rRigid11 |
| 53 | rSceneShape | rRigid12 |
| 51 | rSceneShape | rRigid13 |
| 49 | rSceneShape | rRigid9 |
| 46 | rSceneShape | rRigid10 |
| 44 | rSceneShape | rRigid4 |
| 42 | rSceneShape | rRigid5 |
| 40 | rSceneShape | rRigid6 |
| 38 | rSceneShape | rRigid1 |
| 36 | rSceneShape | rRigid2 |
| 34 | rSceneShape | rRigid3 |
| 15 | rSceneShape | rRigid27 |
| 14 | rSceneShape | rRigid28 |
| 13 | rSceneShape | rRigid29 |
| 12 | rSceneShape | rRigid30 |
| 11 | rSceneShape | rRigid31 |
| 10 | rSceneShape | rRigid32 |
| 9 | rSceneShape | rRigid33 |
| 8 | rSceneShape | rRigid34 |
| 7 | rSceneShape | rRigid19 |
| 6 | rSceneShape | rRigid20 |
| 5 | rSceneShape | rRigid21 |
| 4 | rSceneShape | rRigid22 |
| 3 | rSceneShape | rRigid23 |
| 1048576 | rSceneShape | rRigid24 |
| 1048578 | rSceneShape | rRigid25 |
| 1048577 | rSceneShape | rRigid26 |
|____________|___________________________|_______________|
cmds.ragdollPeek(physicsStatistics=True)
# Ragdoll Peek Solver
- Number of scenes: 1
- Number of shapes: 36
- Number of materials: 36
- Number of convex meshes: 0
- scene[71]
- Number of dynamic actors: 35
- Number of static actors: 1
- Number of constraints: 18 #
cmds.ragdollDump
Synopsis: ragdollDump
-h -help
This is more of a teaser of what's to come, but let me tell you about it for completeness of these release notes.
ragdollDumps
is the start of an integration effort of Ragdoll into any and all external software, like Unreal and Blender. Anything able to parse JSON. Including web-applications.
What if you could rig and/or animate in Maya, but then export the physics setup into e.g. Unreal? I'm not talking about baking your animation and playing it back somewhere else. But of exporting the internal physics objects from Ragdoll, translating them to whatever the third-party software uses for physics, and re-using it there!
With that, you could bypass all of the horrible authoring tools of those applications and transfer a physics scene or setup across applications.
Later, you'll be able to load these into a standalone Ragdoll desktop and web-based application. Useful for sharing your creations and animations with others, and for debugging too!
import json
from maya import cmds
cmds.ragdollDump()
# {
# "scenes": {
# "0": {
# "id": 0,
# "name": "rSceneShape",
# "entities": {
# "0": {
# "id": 0,
# "components": {
# "NameComponent": {
# "type": "NameComponent",
# "members": {
# "value": "rSceneShape"
# }
# }
# }
# },
# "1": {
# "id": 1,
# "components": {
# "NameComponent": {
# "type": "NameComponent",
# "members": {
# "value": "rRigid"
# }
# }
# }
# },
# "2": {
# "id": 2,
# "components": {
# "NameComponent": {
# "type": "NameComponent",
# "members": {
# "value": "rGuideConstraint"
# }
# }
# }
# }
# }
# }
# }
# }
Turn this string into json, with the native Python json
module.
import json
from maya import cmds
dump = cmds.ragdollDump()
dump = json.loads(dump) # From string to dictionary
# The format is internal and yet to be documented, stay tuned
scene = dump["scenes"]["0"]
rigid = scene["entities"]["1"]
name = rigid["components"]["NameComponent"]["members"]["value"]
print(name)
# rRigid
Expect the output to grow throughout later releases as more internals get serialised to JSON.