Skip to content

Commit

Permalink
Version 0.6 conform
Browse files Browse the repository at this point in the history
  • Loading branch information
kimonmatara committed Jul 8, 2022
1 parent 6c50139 commit 70ec9fe
Show file tree
Hide file tree
Showing 112 changed files with 1,385 additions and 645 deletions.
9 changes: 6 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ Customisation is easy, and goes far beyond PyMEL's
`virtual classes <https://github.com/LumaPictures/pymel/blob/master/examples/customClasses.py>`_ system to add support
for attribute (including subtype), component and data types with true inheritance for the first time.

.. admonition:: New in version 0.5
.. admonition:: New in version 0.6

* Over **60 new methods** to create rig controls and :doc:`organise user attributes
<user_attrs>`
* Maya's ``copyDeformerWeights()``, ``copySkinWeights()`` and ``deformerWeights()`` commands have been
unified into simple-to-use methods for dumping, loading and copying deformer weights
* Smart new construction and copy methods for skinClusters
* ``Vector.blend()`` now supports angle-based blending (for both attributes and values, naturally)
* Easily create and drive twist chains
* And more !


Expand Down
Binary file modified __pycache__/plugtree.cpython-37.pyc
Binary file not shown.
Binary file modified __pycache__/pools.cpython-37.pyc
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/.buildinfo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 15802b7f68736c8aaec10c3872f934d2
config: f8f38c8e76b32901f4a0f51bb1be3705
tags: 645f666f9bcd5a90fca523b33c5a78b7
Binary file removed docs/_images/leg_after.png
Binary file not shown.
Binary file removed docs/_images/leg_before.png
Binary file not shown.
Binary file added docs/_images/leg_skel_edit.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
119 changes: 119 additions & 0 deletions docs/_sources/deformers.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
*********
Deformers
*********

=======
General
=======

Constructors
------------

Maya doesn't provide a consistent API to create deformers. Some, like ``skinCluster``, have their own commands; others,
like the non-linear variants, use :func:`~pymel.core.animation.deformer`; still others, like ``proximityWrap``, use
special classes.

To get around this, **version 0.6** of Paya kicks off a project to implement a :meth:`create` method on every deformer
class, starting with skinClusters. Stay tuned for more deformer constructors in upcoming versions.

Retrieving Deformers
--------------------

Use :meth:`~paya.runtime.nodes.GeometryFilter.getFromGeo` to find all deformers of a particular type on a shape. This
is more reliable than :func:`~pymel.core.general.listHistory` (or the :meth:`history` method) as it excludes deformers
in the dependency graph that don't directly affect the shape:

.. code-block:: python
skins = r.nodes.SkinCluster.getFromGeo('bodyShape1')
print(skins)
# [nt.SkinCluster('skinCluster1')]
.. _deformer weight management:

Loading / Dumping Weights
-------------------------

The standard way in Maya to dump and load per-component deformer weights is the
:func:`~pymel.internal.pmcmds.deformerWeights` command. Although this is fast, its flag interface is quirky and often
leads to unwanted deformers and shapes being processed.

To get around this, Paya's :mod:`paya.lib.xmlweights` module offers two functional wrappers,
:func:`~paya.lib.xmlweights.load` and :func:`~paya.lib.xmlweights.dump`. These take simpler path arguments, and ensure
that only requested deformers and shapes are processed.

Paya deformer instances carry matched :meth:`~paya.runtime.nodes.GeometryFilter.loadWeights` and
:meth:`~paya.runtime.nodes.GeometryFilter.dumpWeights` methods with additional perks, such as reliable inclusion
of DQ blend weights.

Here's an example:

.. code-block:: python
filePath = 'C:/Users/user/Desktop/skin.xml'
skin1 = r.nodes.SkinCluster.getFromGeo('body1')[0]
skin1.dumpWeights(filePath)
skin2 = r.nodes.SkinCluster.getFromGeo('body2')[0]
skin2.loadWeights(filePath)
.. note::

Paya's methods only support XML files. This is because calling :func:`~pymel.internal.pmcmds.deformerWeights` in
JSON mode sometimes leads to crashes.

Copying Weights
---------------

Paya's :meth:`~paya.runtime.nodes.GeoemtryFilter.copyWeightsFrom` method unifies various options from
Maya's :func:`~pymel.internal.pmcmds.deformerWeights`, :func:`~pymel.internal.pmcmds.copyDeformerWeights` and
:func:`~pymel.internal.pmcmds.copySkinWeights` commands into a single interface, automatically using the correct
implementation:

.. code-block:: python
skin2.copyWeightsFrom(skin1, method='index') # uses XML, includes DQ blend weights
skin2.copyWeightsFrom(skin1, method='closestPoint') # uses copySkinWeights()
blendShape2.copyWeightsFrom(blendShape1, method='uv') # uses copyDeformerWeights()
============
SkinClusters
============

.. _skinCluster constructor:

Constructor
-----------

The skinCluster constructor confers several advantages over :func:`~pymel.core.animation.skinCluster`:

- Influences and geometry can be passed via positional arguments, in any order and level of listing; alternatively
they can be passed via the ``influence`` and ``geometry`` keyword arguments
- A ``multi`` option to generate skinClusters across several passed geometries with the same arguments
- More useful defaults (for example, ``toSelectedBones=True``)
- Managed naming, including a ``nameFromGeo`` option

Here's an example:

.. code-block:: python
influences = r.ls(type='joint')
meshes = r.ls(type='mesh)
skins = r.nodes.SkinCluster.create(
influences, meshes, maximumInfluences=2, multi=True)
Copying
-------
Use :meth:`~paya.runtime.nodes.SkinCluster.copyTo` to copy skinClusters between geometries. This replicates all relevant
node configuration, including inputs for ``dqsScale``, and gives you the same options for weight copying as
:meth:`~paya.runtime.nodes.GeometryFilter.copyWeightsFrom`:
.. code-block:: python
skin1 = r.nodes.SkinCluster.getFromGeo('body')[0]
skin2 = skin1.copyTo('jacket', destUVSet='rigUVs') # uv mode with an explicit destination map
skin3 = skin1.copyTo('body_thin', method='index')
skin4 = skin1.copyTo('hair', weights=False) # omit weights, but copy configuration
18 changes: 12 additions & 6 deletions docs/_sources/index.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ Customisation is easy, and goes far beyond PyMEL's
`virtual classes <https://github.com/LumaPictures/pymel/blob/master/examples/customClasses.py>`_ system to add support
for attribute (including subtype), component and data types with true inheritance for the first time.

.. admonition:: New in version 0.5

* Over **60 new methods** to :doc:`create rig controls <controls>` and :doc:`organise user attributes
<user_attrs>`
.. admonition:: New in version 0.6

* Maya's :func:`copyDeformerWeights`, :func:`copySkinWeights` and :func:`deformerWeights` commands have been
unified into :ref:`simple-to-use methods for dumping, loading and copying deformer weights
<deformer weight management>`
* Smart new :ref:`construction and copy methods for skinClusters <skinCluster constructor>`
* :meth:`Vector.blend() <paya.runtime.plugs.Vector.blend>` now supports angle-based blending (for both attributes
and values, naturally)
* Easily :ref:`create and drive twist chains <twist chains>`
* And :doc:`more <whats_new>`!


Expand Down Expand Up @@ -154,10 +159,11 @@ Example: Rigging a Radial Repulsor
:hidden:

Maths <maths_rigging>
Controls <controls>
User Attributes <user_attrs>
Joint Chains <joint_chains>
IK Handles <ik>
deformers
Controls <controls>
User Attributes <user_attrs>
Node Names <naming_nodes>

.. toctree::
Expand Down
53 changes: 34 additions & 19 deletions docs/_sources/joint_chains.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ axis or vector arguments; joint positions and orientations are taken from the ma
discarded.

=======
Editing
Loading
=======

If you're not working on an instance of :class:`~paya.lib.skel.Chain` returned by one of the constructors described
Expand All @@ -80,8 +80,15 @@ Standard Python slice notation can be used to get sub-ranges:
lowerBone = chain[1:]
For a full reference of available editing methods, see the documentation for :class:`~paya.lib.skel.Chain`. In the
following example, a leg chain and a foot chain are spliced together, reoriented, subdivided and renamed:
=======
Editing
=======

.. _twist chains:

The :class:`~paya.lib.skel.Chain` class offers too many editing methods to enumerate here. See the class documentation
for a full reference. In the following example, a leg chain and a foot chain are spliced together, reoriented and
subdivided to create a twist chain which is then driven with full support for stretch and translation:

.. tabs::

Expand All @@ -91,31 +98,39 @@ following example, a leg chain and a foot chain are spliced together, reoriented
legChain = r.PyNode('joint1').chainFromHere()
footChain = r.PyNode('joint4').chainFromHere()
legChain.appendChain(footChain)
legChain.orient('y', 'x', [1, 0, 0])
# Order of operations is important to keep track of
# memberships
with r.Name(padding=3):
legChain.rename('driver')
twistChain = legChain.duplicate(n='twist')
thighChain = legChain[:2]
shinChain = legChain[1:3]
triad = twistChain[:3]
triad.subdivide(2)
thighChain.insertJoints(3)
shinChain.insertJoints(3)
# The initial twistChain now has outdated membership;
# reload it
twistChain = twistChain[0].chainFromHere()
# Recreate the instance with updated membership
legChain = thighChain[:-1] + shinChain[:-1] + footChain
# Set the start 'up' matrix to an identity matrix to 'anchor'
# the hip-level up vector
with r.Name(padding=3):
legChain.rename('L_leg')
legChain.driveTwistChain(
twistChain, 'x', 1.0, startUpMatrix=r.data.Matrix()
)
.. tab:: Before
# Display tweaks
.. figure:: leg_before.png
:align: center
for joint in legChain:
joint.attr('radius').set(1.5)
joint.attr('displayLocalAxis').set(False)
for joint in twistChain:
joint.attr('radius').set(0.5)
joint.attr('displayLocalAxis').set(True)
.. tab:: After
.. tab:: Viewport

.. figure:: leg_after.png
.. figure:: leg_skel_edit.gif
:align: center
5 changes: 5 additions & 0 deletions docs/_sources/matrices.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@ matrix:
.. figure:: shear_matrix.gif
:align: center

.. tip::

To quickly create scale-only matrices with simpler arguments, use the convenience function
:func:`~paya.lib.mathops.createScaleMatrix`, also available on :mod:`paya.runtime`.

=============
Quick Testing
=============
Expand Down
34 changes: 31 additions & 3 deletions docs/_sources/paya/plugtree.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ paya.plugtree

.. py:module:: paya.plugtree
Manages the inheritance tree used to construct abstract Paya attribute
subtypes. This module is not intended for direct use.
For internal use. Manages the inheritance tree used to construct abstract
Paya attribute subtypes.

.. py:function:: printTree()
Pretty-prints the Paya attribute inheritance tree.

.. py:function:: getPath(typeName)
Expand All @@ -15,4 +19,28 @@ subtypes. This module is not intended for direct use.
:param str typeName: The plug type to query
:return: A list of abstract type names, ordered
similarly to ``nodeType(inherited=True)``.
:rtype: :class:`list`
:rtype: :class:`list`

.. py:function:: getTerminatingKeys()
:return: All class names in the tree that have no descendants.
:rtype: [str]

.. py:function:: insert(typeName, parent=None)
Inserts an abstract type into the tree.

:param str typeName: the name of the type to insert
:param parent: an optional (existing) parent for the new type
:type parent: None, str

.. py:function:: createPath(path)
Ensures that the specified path exists in the tree.

:param path: the path to enforce
:type path: [str]

.. py:function:: expandTree()
Call on import to expand the explicit ``tree`` dictionary procedurally.
Loading

0 comments on commit 70ec9fe

Please sign in to comment.