Character animation tools for Autodesk Maya 2018-2022 that enable automatic overlapping animation through high-performance rigid-body simulation techniques.
Usage
This repository contains the Python package associated with the commercial compiled plug-in for Maya.
All Maya integration and user-facing tooling is stored in this repository. It's here to better help you integrate and extend the project to fit your specific pipeline, and similar to my other open-source projects facilitate PRs and the opportunity to take matters into your own hands. You've also got access to the commercial website and learning material to facilitate contributions and fixes.
Alongside the Python package, this repository also contains the documentation for Ragdoll, which you can build and preview locally prior to making a contribution.
Documentation should now be accessible at http://localhost:8000. Whenever you edit any Markdown document under ragdoll/docs/pages, the website will automatically be rebuilt and your browser refreshed. It might take a few seconds.
Seems to be a bug whereby if there exists a scene with a namespace, no more physics can be created.
Ragdoll 2021.06.10
# Traceback (most recent call last):# File "<maya console>", line 2, in <module># File "C:\gitlab\ragdollai\ragdoll-dynamics\python\ragdoll\internal.py", line 422, in _undo_chunk# return func(*args, **kwargs)# File "C:\gitlab\ragdollai\ragdoll-dynamics\python\ragdoll\interactive.py", line 1150, in create_active_rigid# scene = _find_current_scene()# File "C:\gitlab\ragdollai\ragdoll-dynamics\python\ragdoll\interactive.py", line 859, in _find_current_scene# current = __.solvers.index(scene.shortestPath())# ValueError: u'_:rSceneShape' is not in list #
The group argument in ragdoll.commands.assign_marker() is unused.
from ragdoll import commands as ragCmds
cube = ragCmds.cmdx.encode(cmds.polyCube(ch=False)[0])
solver = ragCmds.create_solver("test")
group = ragCmds.create_group(solver, "group")
marker = ragCmds.assign_marker(cube, solver, group=group)
# marker is not connected to group
for con in group.connections(source=True, destination=False):
print(con)
Recording is currently a two-step process, each running through the full timeline, e.g. frame 1-100.
For each frame:
Evaluate rig, step simulation and record worldspace position of each marker
Evaluate rig, convert world space positions to local space and write into Translate/Rotate channels
Step 1 is fast as the simulation is fast, and as far as Maya is concerned can run in parallel. No Maya data is modified during this step, so the Maya Evaluation Manager won't have to recreate its internal graph.
Step 2 is slow because we must once again evaluate the rig a second time, but this time cannot do it in parallel as we modify the rig each frame. As a result, evaluation happens in a single thread, and the evaluation graph is recreated each frame. It can be infinitely slower, depending on the complexity of such a rebuild. From taking 2x longer than simulating, to 100x longer. From taking 5 seconds, to taking far too long for comfort.
So, is there a way to avoid step 2?
For an entirely kinematic hierarchy, we can internally compute local positions given a worldspace position, by assuming that the dynamic and kinematic parents are the same. If so, we can invert the dynamic parent and multiply it with our world matrix to arrive at a local matrix. An example of entirely kinematic is a mocap joint hierarchy. But anyting beyond that, especially involving IK and constraints and offset groups, break this requirement.
For a character rig whose offsets between markers never change, we can once again use the parent marker alongside a pre-computed offset matrix to arrive at a local matrix. However this is very hard to prove up-front, as even things like rotatePivot can be animated and change over time. Resulting in an unreliable recording unless the animator explicitly guarantees that this relationship holds true.
...?
I find this problem difficult to solve, but also difficult to explain. It's complicated. But important. It's the difference between taking 500 ms and 50,000 ms to record a simulation. Given that we can evaluate the entire rig, read-only, over the full timeline, in parallel there must be a way in which we can then turn around and use what we evaluated to generate appropriate local Translate/Rotate channels without re-evaluating the rig.
So I'm leaving this here as a record of where I'm at right now and hope to solve this in the future as my understanding of the problem grows. If this sounds familiar to you reading this, or if you have any further ideas, feel free to comment on this issue.
Example
Here's an example of an IK hierarchy, representing our markers, being animated and recorded in worldspace. And then re-applied to another hierarchy, that assumes a linear, FK relationship between each recorded marker.
I feel like calling replace_mesh() should automatically set the shapeType attribute to Mesh.
This is not a problem with markers that get created on geometry as they get their shape type set to Mesh by default as far as I can tell but replacing the mesh on markers that were created for joints seemingly does nothing.
After running the code in the bottom, visually nothing will happen in scene. The marker will still display as sphere. Only after setting shapeType to Mesh we will see the effect.