├── .clang-format
├── .gitattributes
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── README.md
├── bin
└── runmayatests.py
├── build.bat
├── cmt.mod
├── docs
├── .nojekyll
├── Makefile
├── conf.py
├── customwidgets.rst
├── dge.rst
├── html
│ ├── .nojekyll
│ ├── _images
│ │ ├── accordionwidget.gif
│ │ ├── control.png
│ │ ├── swingtwist.png
│ │ └── swingtwist_plugin.png
│ ├── _modules
│ │ ├── cmt
│ │ │ └── rig
│ │ │ │ ├── control.html
│ │ │ │ ├── spaceswitch.html
│ │ │ │ └── swingtwist.html
│ │ └── index.html
│ ├── _sources
│ │ ├── customwidgets.rst.txt
│ │ ├── dge.rst.txt
│ │ ├── index.rst.txt
│ │ ├── installation.rst.txt
│ │ ├── rig
│ │ │ ├── control.rst.txt
│ │ │ ├── spaceswitch.rst.txt
│ │ │ └── swingtwist.rst.txt
│ │ ├── rigging.rst.txt
│ │ └── ui
│ │ │ └── widgets
│ │ │ └── accordionwidget.rst.txt
│ ├── _static
│ │ ├── basic.css
│ │ ├── bootstrap-2.3.2
│ │ │ ├── css
│ │ │ │ ├── bootstrap-responsive.css
│ │ │ │ ├── bootstrap-responsive.min.css
│ │ │ │ ├── bootstrap.css
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── img
│ │ │ │ ├── glyphicons-halflings-white.png
│ │ │ │ └── glyphicons-halflings.png
│ │ │ └── js
│ │ │ │ ├── bootstrap.js
│ │ │ │ └── bootstrap.min.js
│ │ ├── bootstrap-3.3.7
│ │ │ ├── css
│ │ │ │ ├── bootstrap-theme.css
│ │ │ │ ├── bootstrap-theme.css.map
│ │ │ │ ├── bootstrap-theme.min.css
│ │ │ │ ├── bootstrap-theme.min.css.map
│ │ │ │ ├── bootstrap.css
│ │ │ │ ├── bootstrap.css.map
│ │ │ │ ├── bootstrap.min.css
│ │ │ │ └── bootstrap.min.css.map
│ │ │ ├── fonts
│ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ └── js
│ │ │ │ ├── bootstrap.js
│ │ │ │ ├── bootstrap.min.js
│ │ │ │ └── npm.js
│ │ ├── bootstrap-sphinx.css
│ │ ├── bootstrap-sphinx.js
│ │ ├── bootswatch-2.3.2
│ │ │ ├── amelia
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── cerulean
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── cosmo
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── cyborg
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── flatly
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── img
│ │ │ │ ├── glyphicons-halflings-white.png
│ │ │ │ └── glyphicons-halflings.png
│ │ │ ├── journal
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── readable
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── simplex
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── slate
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── spacelab
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── spruce
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── superhero
│ │ │ │ └── bootstrap.min.css
│ │ │ └── united
│ │ │ │ └── bootstrap.min.css
│ │ ├── bootswatch-3.3.7
│ │ │ ├── cerulean
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── cosmo
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── cyborg
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── darkly
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── flatly
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── fonts
│ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ ├── journal
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── lumen
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── paper
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── readable
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── sandstone
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── simplex
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── slate
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── solar
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── spacelab
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── superhero
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── united
│ │ │ │ └── bootstrap.min.css
│ │ │ └── yeti
│ │ │ │ └── bootstrap.min.css
│ │ ├── doctools.js
│ │ ├── documentation_options.js
│ │ ├── file.png
│ │ ├── jquery-3.5.1.js
│ │ ├── jquery.js
│ │ ├── js
│ │ │ ├── jquery-1.11.0.min.js
│ │ │ └── jquery-fix.js
│ │ ├── language_data.js
│ │ ├── minus.png
│ │ ├── plus.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── underscore-1.3.1.js
│ │ └── underscore.js
│ ├── customwidgets.html
│ ├── dge.html
│ ├── genindex.html
│ ├── index.html
│ ├── installation.html
│ ├── objects.inv
│ ├── py-modindex.html
│ ├── rig
│ │ ├── control.html
│ │ ├── spaceswitch.html
│ │ └── swingtwist.html
│ ├── rigging.html
│ ├── search.html
│ ├── searchindex.js
│ └── ui
│ │ └── widgets
│ │ └── accordionwidget.html
├── index.html
├── index.rst
├── installation.rst
├── make.bat
├── rig
│ ├── control.png
│ ├── control.rst
│ ├── spaceswitch.rst
│ ├── swingtwist.png
│ ├── swingtwist.rst
│ └── swingtwist_plugin.png
├── rigging.rst
└── ui
│ └── widgets
│ ├── accordionwidget.gif
│ └── accordionwidget.rst
├── icons
├── cmt_run_all_tests.png
├── cmt_run_failed_tests.png
├── cmt_run_selected_tests.png
├── cmt_test_error.png
├── cmt_test_fail.png
├── cmt_test_skip.png
├── cmt_test_success.png
├── spine.png
├── spine.psd
├── swingTwist.png
├── swingTwist.psd
├── test_icons.psd
└── test_toolbar.psd
├── plug-ins
└── cmt_py.py
├── scripts
├── cmt
│ ├── __init__.py
│ ├── anim
│ │ ├── __init__.py
│ │ └── ikrig.py
│ ├── deform
│ │ ├── __init__.py
│ │ ├── blendshape.py
│ │ ├── np_mesh.py
│ │ ├── shapesui.py
│ │ └── skinio.py
│ ├── dge.py
│ ├── io
│ │ ├── __init__.py
│ │ ├── fbx.py
│ │ └── obj.py
│ ├── menu.py
│ ├── model
│ │ └── __init__.py
│ ├── pipeline
│ │ ├── __init__.py
│ │ └── runscript.py
│ ├── plugins
│ │ ├── __init__.py
│ │ └── swingtwist.py
│ ├── reloadmodules.py
│ ├── rig
│ │ ├── __init__.py
│ │ ├── arm.py
│ │ ├── common.py
│ │ ├── control.py
│ │ ├── control_ui.py
│ │ ├── controls
│ │ │ ├── arrow.json
│ │ │ ├── barbell.json
│ │ │ ├── circle.json
│ │ │ ├── circle_arrow.json
│ │ │ ├── cube.json
│ │ │ ├── four_arrow_circle.json
│ │ │ ├── four_arrow_curved.json
│ │ │ ├── four_arrow_flat.json
│ │ │ ├── four_circle.json
│ │ │ ├── gear.json
│ │ │ ├── locator.json
│ │ │ ├── lollipop.json
│ │ │ ├── one_arrow_circle.json
│ │ │ ├── pointed_circle.json
│ │ │ ├── pyramid.json
│ │ │ ├── sharp_4_point_star.json
│ │ │ ├── sphere.json
│ │ │ ├── sphere_quarter.json
│ │ │ ├── square.json
│ │ │ ├── squiggle_circle.json
│ │ │ ├── star.json
│ │ │ ├── star_8.json
│ │ │ ├── triangle.json
│ │ │ └── two_arrow_flat.json
│ │ ├── face
│ │ │ ├── __init__.py
│ │ │ └── cartoony.py
│ │ ├── leg.py
│ │ ├── meshretarget.py
│ │ ├── orientjoints.py
│ │ ├── rbf.py
│ │ ├── skeleton.py
│ │ ├── spaceswitch.py
│ │ ├── spine.py
│ │ ├── splineik.py
│ │ ├── swingtwist.py
│ │ ├── transformstack.py
│ │ └── twoboneik.py
│ ├── settings.py
│ ├── shortcuts.py
│ ├── test
│ │ ├── __init__.py
│ │ ├── mayaunittest.py
│ │ └── mayaunittestui.py
│ ├── ui
│ │ ├── __init__.py
│ │ ├── optionbox.py
│ │ ├── stringcache.py
│ │ └── widgets
│ │ │ ├── __init__.py
│ │ │ ├── accordionwidget.py
│ │ │ ├── filepathwidget.py
│ │ │ ├── mayanodewidget.py
│ │ │ └── outputconsole.py
│ └── utility
│ │ ├── __init__.py
│ │ └── timing.py
├── pyparsing
│ ├── LICENSE
│ ├── __init__.py
│ ├── actions.py
│ ├── common.py
│ ├── core.py
│ ├── exceptions.py
│ ├── helpers.py
│ ├── results.py
│ ├── testing.py
│ ├── unicode.py
│ └── util.py
└── userSetup.py
├── src
├── CMakeLists.txt
├── DemBones
│ ├── ConvexLS.h
│ ├── DemBones.h
│ ├── DemBonesExt.h
│ ├── Indexing.h
│ ├── LICENSE.md
│ └── MatBlocks.h
├── cmtConfig.h.in
├── common.cpp
├── common.h
├── demBonesCmd.cpp
├── demBonesCmd.h
├── ikRigNode.cpp
├── ikRigNode.h
├── linearRegressionSolver.cpp
├── linearRegressionSolver.h
├── pluginMain.cpp
├── rbfNode.cpp
├── rbfNode.h
├── swingTwistCmd.cpp
├── swingTwistCmd.h
├── swingTwistNode.cpp
└── swingTwistNode.h
├── tests
├── clean_maya_app_dir
│ └── 2016
│ │ ├── Maya.env
│ │ └── prefs
│ │ ├── MayaInterfaceScalingConfig
│ │ ├── filePathEditorRegistryPrefs.mel
│ │ ├── markingMenus
│ │ ├── menu_ChangePanelLayout.mel
│ │ ├── menu_ChangePanelType.mel
│ │ ├── menu_ChangeSelectionMask.mel
│ │ ├── menu_CommonModelingPanes.mel
│ │ └── menu_ControlPaneVisibility.mel
│ │ ├── menuSetPrefs.mel
│ │ ├── pluginPrefs.mel
│ │ ├── synColorFileRules.xml
│ │ ├── userNamedCommands.mel
│ │ ├── userPrefs.mel
│ │ ├── userRunTimeCommands.mel
│ │ └── windowPrefs.mel
├── test_cmt_blendshape.py
├── test_cmt_control.py
├── test_cmt_dge.py
├── test_cmt_rbf.py
├── test_cmt_skinio.py
├── test_cmt_spaceswitch.py
├── test_cmt_transformstack.py
├── test_cmt_twist_decomposition.py
├── test_rig_common.py
└── test_skeleton.py
└── third-party
└── Eigen
└── .gitignore
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | BasedOnStyle: Google
3 | ColumnLimit: '100'
4 | DerivePointerAlignment: false
5 | PointerAlignment: Left
6 |
7 | ...
8 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/.gitattributes
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .coverage
41 | .coverage.*
42 | .cache
43 | nosetests.xml
44 | coverage.xml
45 | *,cover
46 | .hypothesis/
47 |
48 | # Translations
49 | *.mo
50 | *.pot
51 |
52 | # Django stuff:
53 | *.log
54 |
55 | # Sphinx documentation
56 | doctrees/
57 | .buildinfo
58 |
59 | # PyBuilder
60 | target/
61 |
62 | #Ipython Notebook
63 | .ipynb_checkpoints
64 |
65 | # PyCharm
66 | .idea
67 | build.*/
68 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "cgcmake"]
2 | path = cgcmake
3 | url = git@github.com:chadmv/cgcmake.git
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.1...3.15)
2 |
3 | if(${CMAKE_VERSION} VERSION_LESS 3.12)
4 | cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
5 | endif()
6 |
7 | cmake_policy(SET CMP0048 NEW)
8 |
9 | project(cmt VERSION 1.0 DESCRIPTION "Chad's Maya Tools" LANGUAGES CXX)
10 |
11 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR})
12 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cgcmake/modules)
13 |
14 | set(ENV{EIGEN3_ROOT_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/third-party/Eigen")
15 |
16 | add_subdirectory(src)
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Chad Vernon
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://opensource.org/licenses/MIT)
2 | [](https://github.com/ambv/black)
3 |
4 | # cmt
5 | cmt is a collection of various Maya tools I have written for my personal projects. Feel free to use
6 | the tools in your own projects, browse the code for inspiration, or silently judge me. These tools
7 | were never meant to be a professional product. Many areas are undocumented, I'm always experimenting but
8 | feel free to take and use any of the code in this project.
9 |
10 | Full documentation can be found here: https://chadmv.github.io/cmt
11 |
12 | # Installing the Maya Module
13 |
14 | ## Download Pre-built Release
15 | Built plug-ins are provided via my [Releases](https://github.com/chadmv/cmt/releases)
16 |
17 | ## Compile Your Own
18 |
19 | ### Plug-in Compilation Dependencies
20 | * [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page)
21 |
22 | ### Plug-in Compilation Instructions
23 | Download [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page) and extract into `third-party/Eigen`.
24 |
25 | The project is setup to use CMake to generate build files.
26 |
27 | #### Windows
28 | The build.bat included will build for 2018, 2019 and 2020. Or:
29 |
30 | ```
31 | mkdir build.2020
32 | cd build.2020
33 | cmake -A x64 -T v141 -DMAYA_VERSION=2020 ../
34 | cmake --build . --target install --config Release
35 | ```
36 |
37 | # Installation Instructions
38 | cmt is a Maya module that can be installed like all other [Maya modules](http://help.autodesk.com/view/MAYAUL/2020/ENU//?guid=Maya_SDK_MERGED_Distributing_Maya_Plug_ins_Distributing_Multi_File_Modules_html). You can do one of the following:
39 |
40 | * Add the cmt root directory to the MAYA_MODULE_PATH environment variable.
41 | * Add the cmt root directory to the MAYA_MODULE_PATH in your Maya.env. e.g. MAYA_MODULE_PATH=/path/to/cmt
42 | * Edit the cmt.mod file, and replace the ./ with the full path to the cmt root directory, then copy the cmt.mod file to where your modules are loaded from.
43 |
--------------------------------------------------------------------------------
/bin/runmayatests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | Command-line unit test runner for mayapy.
4 |
5 | This can be used to run tests from a commandline environment like on a build server.
6 |
7 | Usage:
8 | python runmayatests.py -m 2016
9 | """
10 | import argparse
11 | import errno
12 | import os
13 | import platform
14 | import shutil
15 | import stat
16 | import subprocess
17 | import tempfile
18 | import uuid
19 |
20 | CMT_ROOT_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
21 |
22 |
23 | def get_maya_location(maya_version):
24 | """Get the location where Maya is installed.
25 |
26 | @param maya_version The maya version number.
27 | @return The path to where Maya is installed.
28 | """
29 | if 'MAYA_LOCATION' in os.environ.keys():
30 | return os.environ['MAYA_LOCATION']
31 | if platform.system() == 'Windows':
32 | return 'C:/Program Files/Autodesk/Maya{0}'.format(maya_version)
33 | elif platform.system() == 'Darwin':
34 | return '/Applications/Autodesk/maya{0}/Maya.app/Contents'.format(maya_version)
35 | else:
36 | location = '/usr/autodesk/maya{0}'.format(maya_version)
37 | if maya_version < 2016:
38 | # Starting Maya 2016, the default install directory name changed.
39 | location += '-x64'
40 | return location
41 |
42 |
43 | def mayapy(maya_version):
44 | """Get the mayapy executable path.
45 |
46 | @param maya_version The maya version number.
47 | @return: The mayapy executable path.
48 | """
49 | python_exe = '{0}/bin/mayapy'.format(get_maya_location(maya_version))
50 | if platform.system() == 'Windows':
51 | python_exe += '.exe'
52 | return python_exe
53 |
54 |
55 | def create_clean_maya_app_dir(directory=None):
56 | """Creates a copy of the clean Maya preferences so we can create predictable results.
57 |
58 | @return: The path to the clean MAYA_APP_DIR folder.
59 | """
60 | app_dir = os.path.join(CMT_ROOT_DIR, 'tests', 'clean_maya_app_dir')
61 | temp_dir = tempfile.gettempdir()
62 | if not os.path.exists(temp_dir):
63 | os.makedirs(temp_dir)
64 | dst = directory if directory else os.path.join(temp_dir, 'maya_app_dir{0}'.format(str(uuid.uuid4())))
65 | if os.path.exists(dst):
66 | shutil.rmtree(dst, ignore_errors=False, onerror=remove_read_only)
67 | shutil.copytree(app_dir, dst)
68 | return dst
69 |
70 |
71 | def remove_read_only(func, path, exc):
72 | """Called by shutil.rmtree when it encounters a readonly file.
73 |
74 | :param func:
75 | :param path:
76 | :param exc:
77 | """
78 | excvalue = exc[1]
79 | if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
80 | os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
81 | func(path)
82 | else:
83 | raise RuntimeError('Could not remove {0}'.format(path))
84 |
85 |
86 | def main():
87 | parser = argparse.ArgumentParser(description='Runs unit tests for a Maya module')
88 | parser.add_argument('-m', '--maya',
89 | help='Maya version',
90 | type=int,
91 | default=2016)
92 | parser.add_argument('-mad', '--maya-app-dir',
93 | help='Just create a clean MAYA_APP_DIR and exit')
94 | pargs = parser.parse_args()
95 | mayaunittest = os.path.join(CMT_ROOT_DIR, 'scripts', 'cmt', 'test', 'mayaunittest.py')
96 | cmd = [mayapy(pargs.maya), mayaunittest]
97 | if not os.path.exists(cmd[0]):
98 | raise RuntimeError('Maya {0} is not installed on this system.'.format(pargs.maya))
99 |
100 | app_directory = pargs.maya_app_dir
101 | maya_app_dir = create_clean_maya_app_dir(app_directory)
102 | if app_directory:
103 | return
104 | # Create clean prefs
105 | os.environ['MAYA_APP_DIR'] = maya_app_dir
106 | # Clear out any MAYA_SCRIPT_PATH value so we know we're in a clean env.
107 | os.environ['MAYA_SCRIPT_PATH'] = ''
108 | # Run the tests in this module.
109 | os.environ['MAYA_MODULE_PATH'] = CMT_ROOT_DIR
110 | try:
111 | subprocess.check_call(cmd)
112 | except subprocess.CalledProcessError:
113 | pass
114 | finally:
115 | shutil.rmtree(maya_app_dir)
116 |
117 | if __name__ == '__main__':
118 | main()
119 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | FOR %%G IN (2018, 2019, 2020) DO (call :subroutine "%%G")
3 | GOTO :eof
4 |
5 | :subroutine
6 | set builddir=build.%1
7 | if not exist %builddir% goto BUILDENV
8 | del %builddir% /S /Q
9 | :BUILDENV
10 | mkdir %builddir%
11 | cd %builddir%
12 | if %1 LSS "2020" (
13 | cmake -A x64 -T v140 -DMAYA_VERSION=%1 ../
14 | ) ELSE (
15 | cmake -A x64 -T v141 -DMAYA_VERSION=%1 ../
16 | )
17 | cmake --build . --target install --config Release
18 | cd ..
19 | goto :eof
20 |
--------------------------------------------------------------------------------
/cmt.mod:
--------------------------------------------------------------------------------
1 | + MAYAVERSION:2018 cmt 1.0.0 ./
2 | CMT_ROOT_PATH := .
3 | plug-ins: plug-ins/2018
4 |
5 | + MAYAVERSION:2019 cmt 1.0.0 ./
6 | CMT_ROOT_PATH := .
7 | plug-ins: plug-ins/2019
8 |
9 | + MAYAVERSION:2020 cmt 1.0.0 ./
10 | CMT_ROOT_PATH := .
11 | plug-ins: plug-ins/2020
12 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SOURCEDIR = .
8 | BUILDDIR = .
9 |
10 | # Put it first so that "make" without argument is like "make help".
11 | help:
12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
13 |
14 | .PHONY: help Makefile
15 |
16 | # Catch-all target: route all unknown targets to Sphinx using the new
17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
18 | %: Makefile
19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
20 |
--------------------------------------------------------------------------------
/docs/customwidgets.rst:
--------------------------------------------------------------------------------
1 | Custom Widgets
2 | ==============
3 |
4 | The cmt package contains the following custom PySide widgets.
5 |
6 | .. toctree::
7 | :maxdepth: 1
8 |
9 | ui/widgets/accordionwidget
10 |
11 |
--------------------------------------------------------------------------------
/docs/dge.rst:
--------------------------------------------------------------------------------
1 | Dependency Graph Expressions
2 | ============================
3 |
4 | .. automodule:: cmt.dge
5 | :members: dge
6 |
--------------------------------------------------------------------------------
/docs/html/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/.nojekyll
--------------------------------------------------------------------------------
/docs/html/_images/accordionwidget.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_images/accordionwidget.gif
--------------------------------------------------------------------------------
/docs/html/_images/control.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_images/control.png
--------------------------------------------------------------------------------
/docs/html/_images/swingtwist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_images/swingtwist.png
--------------------------------------------------------------------------------
/docs/html/_images/swingtwist_plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_images/swingtwist_plugin.png
--------------------------------------------------------------------------------
/docs/html/_modules/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Overview: module code — cmt documentation
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
41 |
42 |
43 |
44 |
45 |
46 | -
47 | Site
52 |
61 |
62 |
63 | -
64 | Page
69 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
All modules for which code is available
106 |
110 |
111 |
112 |
113 |
114 |
115 |
127 |
128 |
--------------------------------------------------------------------------------
/docs/html/_sources/customwidgets.rst.txt:
--------------------------------------------------------------------------------
1 | Custom Widgets
2 | ==============
3 |
4 | The cmt package contains the following custom PySide widgets.
5 |
6 | .. toctree::
7 | :maxdepth: 1
8 |
9 | ui/widgets/accordionwidget
10 |
11 |
--------------------------------------------------------------------------------
/docs/html/_sources/dge.rst.txt:
--------------------------------------------------------------------------------
1 | Dependency Graph Expressions
2 | ============================
3 |
4 | .. automodule:: cmt.dge
5 | :members: dge
6 |
--------------------------------------------------------------------------------
/docs/html/_sources/index.rst.txt:
--------------------------------------------------------------------------------
1 | .. cmt documentation master file, created by
2 | sphinx-quickstart on Sat Dec 1 13:46:34 2018.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to cmt's documentation!
7 | ===============================
8 |
9 | cmt is a collection of various Maya tools I have written for my personal projects.
10 |
11 | .. toctree::
12 | :maxdepth: 2
13 |
14 | installation
15 | rigging
16 | dge
17 | customwidgets
18 |
19 |
20 |
21 | Indices and tables
22 | ==================
23 |
24 | * :ref:`genindex`
25 | * :ref:`modindex`
26 | * :ref:`search`
27 |
--------------------------------------------------------------------------------
/docs/html/_sources/installation.rst.txt:
--------------------------------------------------------------------------------
1 | Installation Instructions
2 | =========================
3 | cmt is Maya module that can be installed like all other Maya modules. You can do one of the
4 | following:
5 |
6 | * Add the cmt root directory to the MAYA_MODULE_PATH environment variable.
7 | * Add the cmt root directory to the MAYA_MODULE_PATH in your Maya.env. e.g.
8 | MAYA_MODULE_PATH += /path/to/cmt
9 | * Edit the cmt.mod file, and replace the ./ with the full path to the cmt root directory,
10 | then copy the cmt.mod file to where your modules are loaded from.
11 |
12 |
--------------------------------------------------------------------------------
/docs/html/_sources/rig/control.rst.txt:
--------------------------------------------------------------------------------
1 | Curve Control Creator
2 | =====================
3 |
4 | .. automodule:: cmt.rig.control
5 | :members: export_curves, import_new_curves, import_curves_on_selected, load_curves, mirror_curve, CurveShape
6 |
7 |
--------------------------------------------------------------------------------
/docs/html/_sources/rig/spaceswitch.rst.txt:
--------------------------------------------------------------------------------
1 | Space Switching
2 | ===============
3 |
4 | .. automodule:: cmt.rig.spaceswitch
5 | :members: create_space_switch, switch_space
6 |
--------------------------------------------------------------------------------
/docs/html/_sources/rig/swingtwist.rst.txt:
--------------------------------------------------------------------------------
1 | Swing Twist Decomposition
2 | =========================
3 |
4 | .. automodule:: cmt.rig.swingtwist
5 | :members: create_swing_twist
6 |
7 | Network with the Plug-in
8 | ------------------------
9 | .. image:: swingtwist_plugin.png
10 |
11 | Network without the Plug-in
12 | ---------------------------
13 | .. image:: swingtwist.png
14 |
--------------------------------------------------------------------------------
/docs/html/_sources/rigging.rst.txt:
--------------------------------------------------------------------------------
1 | Rigging Tools
2 | =============
3 |
4 | The cmt package contains the following rigging tools.
5 |
6 | .. toctree::
7 | :maxdepth: 1
8 |
9 | rig/spaceswitch
10 | rig/swingtwist
11 | rig/control
12 |
13 |
--------------------------------------------------------------------------------
/docs/html/_sources/ui/widgets/accordionwidget.rst.txt:
--------------------------------------------------------------------------------
1 | Accordion Widget
2 | ================
3 |
4 | .. automodule:: cmt.ui.widgets.accordionwidget
5 |
6 | .. image:: accordionwidget.gif
--------------------------------------------------------------------------------
/docs/html/_static/bootstrap-2.3.2/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootstrap-2.3.2/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/docs/html/_static/bootstrap-2.3.2/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootstrap-2.3.2/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/docs/html/_static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/docs/html/_static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/docs/html/_static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/docs/html/_static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/docs/html/_static/bootstrap-3.3.7/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/docs/html/_static/bootstrap-sphinx.css:
--------------------------------------------------------------------------------
1 | /*
2 | * bootstrap-sphinx.css
3 | * ~~~~~~~~~~~~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- Bootstrap theme.
6 | */
7 |
8 | /*
9 | * Imports to aggregate everything together.
10 | */
11 |
12 | @import url("./basic.css");
13 |
14 |
15 |
16 |
17 |
18 |
19 | @import url("./bootstrap-3.3.7/css/bootstrap.min.css");
20 | @import url("./bootstrap-3.3.7/css/bootstrap-theme.min.css");
21 |
22 |
23 | /*
24 | * Styles
25 | */
26 |
27 | .navbar-inverse .brand {
28 | color: #FFF;
29 | }
30 |
31 | /*
32 | * Reset navbar styles from overrides in:
33 | * https://bitbucket.org/birkenfeld/sphinx/commits/78d8ebf76b630ab4073a7328af9d91e8123b8d96
34 | */
35 | .navbar .container {
36 | padding-top: 0;
37 | }
38 |
39 | /*
40 | * Reset the logo image dimensions. Sites like RTD can override with bad
41 | * results on mobile (mega-huge logo...)
42 | *
43 | * https://github.com/ryan-roemer/sphinx-bootstrap-theme/issues/142
44 | */
45 | .navbar-brand img {
46 | width: auto;
47 | height: 100%;
48 | }
49 |
50 | .page-top {
51 | top: 0px;
52 | }
53 |
54 |
55 |
56 |
57 |
58 | body {
59 |
60 | padding-top: 40px;
61 |
62 | }
63 | .page-top {
64 |
65 | top: 40px;
66 |
67 | }
68 |
69 |
70 |
71 | .navbar-inner {
72 | padding-left: 12px !important;
73 | padding-right: 12px !important;
74 | }
75 |
76 |
77 | table {
78 | border: 0;
79 | }
80 |
81 | .highlighttable .code pre {
82 | font-size: 12px;
83 | }
84 |
85 | .highlighttable .linenos pre {
86 | word-break: normal;
87 | font-size: 12px;
88 | }
89 |
90 | div.highlight {
91 | background: none;
92 | }
93 |
94 | a.headerlink {
95 | margin-left: 0.25em;
96 | }
97 |
98 | a.footnote-reference {
99 | vertical-align: super;
100 | font-size: 75%;
101 | }
102 |
103 | table.footnote td.label {
104 | color: inherit;
105 | font-size: 100%;
106 | display: block;
107 | line-height: normal;
108 | background: inherit;
109 | }
110 |
111 | table.footnote {
112 | width: auto;
113 | margin-bottom: 0px;
114 | }
115 |
116 | table.field-list {
117 | width: auto;
118 | }
119 |
120 | .footer {
121 | width: 100%;
122 | border-top: 1px solid #ccc;
123 | padding-top: 10px;
124 | }
125 |
126 | .bs-sidenav form, .bs-sidenav #sourcelink {
127 | padding: 5px 20px;
128 | }
129 |
130 |
131 |
132 | /* The code below is based on the bootstrap website sidebar */
133 |
134 | .bs-sidenav.affix {
135 | position: static;
136 | }
137 |
138 | /* First level of nav */
139 | .bs-sidenav {
140 | margin-top: 30px;
141 | margin-bottom: 30px;
142 | padding-top: 10px;
143 | padding-bottom: 10px;
144 | text-shadow: 0 1px 0 #fff;
145 | background-color: #f7f5fa;
146 | border-radius: 5px;
147 | }
148 |
149 | /* All levels of nav */
150 | .bs-sidenav .nav > li > a {
151 | display: block;
152 | color: #716b7a;
153 | padding: 5px 20px;
154 | }
155 | .bs-sidenav .nav > li > a:hover,
156 | .bs-sidenav .nav > li > a:focus {
157 | text-decoration: none;
158 | background-color: #e5e3e9;
159 | border-right: 1px solid #dbd8e0;
160 | }
161 | .bs-sidenav .nav > .active > a,
162 | .bs-sidenav .nav > .active:hover > a,
163 | .bs-sidenav .nav > .active:focus > a {
164 | font-weight: bold;
165 | color: #563d7c;
166 | background-color: transparent;
167 | border-right: 1px solid #563d7c;
168 | }
169 |
170 | .bs-sidenav .nav .nav > li > a {
171 | padding-top: 3px;
172 | padding-bottom: 3px;
173 | padding-left: 30px;
174 | font-size: 90%;
175 | }
176 |
177 | .bs-sidenav .nav .nav .nav > li > a {
178 | padding-top: 3px;
179 | padding-bottom: 3px;
180 | padding-left: 40px;
181 | font-size: 90%;
182 | }
183 |
184 | .bs-sidenav .nav .nav .nav .nav > li > a {
185 | padding-top: 3px;
186 | padding-bottom: 3px;
187 | padding-left: 50px;
188 | font-size: 90%;
189 | }
190 |
191 | /* Show and affix the side nav when space allows it */
192 | @media screen and (min-width: 992px) {
193 | .bs-sidenav .nav > .active > ul {
194 | display: block;
195 | }
196 | /* Widen the fixed sidenav */
197 | .bs-sidenav.affix,
198 | .bs-sidenav.affix-bottom {
199 | width: 213px;
200 | }
201 | .bs-sidenav.affix {
202 | position: fixed; /* Undo the static from mobile first approach */
203 | }
204 | .bs-sidenav.affix-bottom {
205 | position: absolute; /* Undo the static from mobile first approach */
206 | }
207 | .bs-sidenav.affix-bottom .bs-sidenav,
208 | .bs-sidenav.affix .bs-sidenav {
209 | margin-top: 0;
210 | margin-bottom: 0;
211 | }
212 | }
213 | @media screen and (min-width: 1200px) {
214 | /* Widen the fixed sidenav again */
215 | .bs-sidenav.affix-bottom,
216 | .bs-sidenav.affix {
217 | width: 263px;
218 | }
219 | }
220 |
221 |
222 |
--------------------------------------------------------------------------------
/docs/html/_static/bootswatch-2.3.2/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootswatch-2.3.2/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/docs/html/_static/bootswatch-2.3.2/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootswatch-2.3.2/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/docs/html/_static/bootswatch-3.3.7/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootswatch-3.3.7/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/docs/html/_static/bootswatch-3.3.7/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootswatch-3.3.7/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/docs/html/_static/bootswatch-3.3.7/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootswatch-3.3.7/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/docs/html/_static/bootswatch-3.3.7/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/bootswatch-3.3.7/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/docs/html/_static/documentation_options.js:
--------------------------------------------------------------------------------
1 | var DOCUMENTATION_OPTIONS = {
2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 | VERSION: '',
4 | LANGUAGE: 'None',
5 | COLLAPSE_INDEX: false,
6 | BUILDER: 'html',
7 | FILE_SUFFIX: '.html',
8 | LINK_SUFFIX: '.html',
9 | HAS_SOURCE: true,
10 | SOURCELINK_SUFFIX: '.txt',
11 | NAVIGATION_WITH_KEYS: false
12 | };
--------------------------------------------------------------------------------
/docs/html/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/file.png
--------------------------------------------------------------------------------
/docs/html/_static/js/jquery-fix.js:
--------------------------------------------------------------------------------
1 | // No Conflict in later (our) version of jQuery
2 | window.$jqTheme = jQuery.noConflict(true);
--------------------------------------------------------------------------------
/docs/html/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/minus.png
--------------------------------------------------------------------------------
/docs/html/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/_static/plus.png
--------------------------------------------------------------------------------
/docs/html/_static/pygments.css:
--------------------------------------------------------------------------------
1 | .highlight .hll { background-color: #ffffcc }
2 | .highlight { background: #f8f8f8; }
3 | .highlight .c { color: #8f5902; font-style: italic } /* Comment */
4 | .highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */
5 | .highlight .g { color: #000000 } /* Generic */
6 | .highlight .k { color: #204a87; font-weight: bold } /* Keyword */
7 | .highlight .l { color: #000000 } /* Literal */
8 | .highlight .n { color: #000000 } /* Name */
9 | .highlight .o { color: #ce5c00; font-weight: bold } /* Operator */
10 | .highlight .x { color: #000000 } /* Other */
11 | .highlight .p { color: #000000; font-weight: bold } /* Punctuation */
12 | .highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */
13 | .highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
14 | .highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
15 | .highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */
16 | .highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */
17 | .highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */
18 | .highlight .gd { color: #a40000 } /* Generic.Deleted */
19 | .highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
20 | .highlight .gr { color: #ef2929 } /* Generic.Error */
21 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
22 | .highlight .gi { color: #00A000 } /* Generic.Inserted */
23 | .highlight .go { color: #000000; font-style: italic } /* Generic.Output */
24 | .highlight .gp { color: #8f5902 } /* Generic.Prompt */
25 | .highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */
26 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
27 | .highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
28 | .highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
29 | .highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
30 | .highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
31 | .highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
32 | .highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
33 | .highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */
34 | .highlight .ld { color: #000000 } /* Literal.Date */
35 | .highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */
36 | .highlight .s { color: #4e9a06 } /* Literal.String */
37 | .highlight .na { color: #c4a000 } /* Name.Attribute */
38 | .highlight .nb { color: #204a87 } /* Name.Builtin */
39 | .highlight .nc { color: #000000 } /* Name.Class */
40 | .highlight .no { color: #000000 } /* Name.Constant */
41 | .highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
42 | .highlight .ni { color: #ce5c00 } /* Name.Entity */
43 | .highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */
44 | .highlight .nf { color: #000000 } /* Name.Function */
45 | .highlight .nl { color: #f57900 } /* Name.Label */
46 | .highlight .nn { color: #000000 } /* Name.Namespace */
47 | .highlight .nx { color: #000000 } /* Name.Other */
48 | .highlight .py { color: #000000 } /* Name.Property */
49 | .highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */
50 | .highlight .nv { color: #000000 } /* Name.Variable */
51 | .highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */
52 | .highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
53 | .highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */
54 | .highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
55 | .highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
56 | .highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
57 | .highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
58 | .highlight .sa { color: #4e9a06 } /* Literal.String.Affix */
59 | .highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */
60 | .highlight .sc { color: #4e9a06 } /* Literal.String.Char */
61 | .highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */
62 | .highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
63 | .highlight .s2 { color: #4e9a06 } /* Literal.String.Double */
64 | .highlight .se { color: #4e9a06 } /* Literal.String.Escape */
65 | .highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */
66 | .highlight .si { color: #4e9a06 } /* Literal.String.Interpol */
67 | .highlight .sx { color: #4e9a06 } /* Literal.String.Other */
68 | .highlight .sr { color: #4e9a06 } /* Literal.String.Regex */
69 | .highlight .s1 { color: #4e9a06 } /* Literal.String.Single */
70 | .highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */
71 | .highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */
72 | .highlight .fm { color: #000000 } /* Name.Function.Magic */
73 | .highlight .vc { color: #000000 } /* Name.Variable.Class */
74 | .highlight .vg { color: #000000 } /* Name.Variable.Global */
75 | .highlight .vi { color: #000000 } /* Name.Variable.Instance */
76 | .highlight .vm { color: #000000 } /* Name.Variable.Magic */
77 | .highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/docs/html/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/html/objects.inv
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. cmt documentation master file, created by
2 | sphinx-quickstart on Sat Dec 1 13:46:34 2018.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to cmt's documentation!
7 | ===============================
8 |
9 | cmt is a collection of various Maya tools I have written for my personal projects.
10 |
11 | .. toctree::
12 | :maxdepth: 2
13 |
14 | installation
15 | rigging
16 | dge
17 | customwidgets
18 |
19 |
20 |
21 | Indices and tables
22 | ==================
23 |
24 | * :ref:`genindex`
25 | * :ref:`modindex`
26 | * :ref:`search`
27 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | Installation Instructions
2 | =========================
3 | cmt is Maya module that can be installed like all other Maya modules. You can do one of the
4 | following:
5 |
6 | * Add the cmt root directory to the MAYA_MODULE_PATH environment variable.
7 | * Add the cmt root directory to the MAYA_MODULE_PATH in your Maya.env. e.g.
8 | MAYA_MODULE_PATH += /path/to/cmt
9 | * Edit the cmt.mod file, and replace the ./ with the full path to the cmt root directory,
10 | then copy the cmt.mod file to where your modules are loaded from.
11 |
12 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=.
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/rig/control.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/rig/control.png
--------------------------------------------------------------------------------
/docs/rig/control.rst:
--------------------------------------------------------------------------------
1 | Curve Control Creator
2 | =====================
3 |
4 | .. automodule:: cmt.rig.control
5 | :members: export_curves, import_new_curves, import_curves_on_selected, load_curves, mirror_curve, CurveShape
6 |
7 |
--------------------------------------------------------------------------------
/docs/rig/spaceswitch.rst:
--------------------------------------------------------------------------------
1 | Space Switching
2 | ===============
3 |
4 | .. automodule:: cmt.rig.spaceswitch
5 | :members: create_space_switch, switch_space
6 |
--------------------------------------------------------------------------------
/docs/rig/swingtwist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/rig/swingtwist.png
--------------------------------------------------------------------------------
/docs/rig/swingtwist.rst:
--------------------------------------------------------------------------------
1 | Swing Twist Decomposition
2 | =========================
3 |
4 | .. automodule:: cmt.rig.swingtwist
5 | :members: create_swing_twist
6 |
7 | Network with the Plug-in
8 | ------------------------
9 | .. image:: swingtwist_plugin.png
10 |
11 | Network without the Plug-in
12 | ---------------------------
13 | .. image:: swingtwist.png
14 |
--------------------------------------------------------------------------------
/docs/rig/swingtwist_plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/rig/swingtwist_plugin.png
--------------------------------------------------------------------------------
/docs/rigging.rst:
--------------------------------------------------------------------------------
1 | Rigging Tools
2 | =============
3 |
4 | The cmt package contains the following rigging tools.
5 |
6 | .. toctree::
7 | :maxdepth: 1
8 |
9 | rig/spaceswitch
10 | rig/swingtwist
11 | rig/control
12 |
13 |
--------------------------------------------------------------------------------
/docs/ui/widgets/accordionwidget.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/docs/ui/widgets/accordionwidget.gif
--------------------------------------------------------------------------------
/docs/ui/widgets/accordionwidget.rst:
--------------------------------------------------------------------------------
1 | Accordion Widget
2 | ================
3 |
4 | .. automodule:: cmt.ui.widgets.accordionwidget
5 |
6 | .. image:: accordionwidget.gif
--------------------------------------------------------------------------------
/icons/cmt_run_all_tests.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/cmt_run_all_tests.png
--------------------------------------------------------------------------------
/icons/cmt_run_failed_tests.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/cmt_run_failed_tests.png
--------------------------------------------------------------------------------
/icons/cmt_run_selected_tests.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/cmt_run_selected_tests.png
--------------------------------------------------------------------------------
/icons/cmt_test_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/cmt_test_error.png
--------------------------------------------------------------------------------
/icons/cmt_test_fail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/cmt_test_fail.png
--------------------------------------------------------------------------------
/icons/cmt_test_skip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/cmt_test_skip.png
--------------------------------------------------------------------------------
/icons/cmt_test_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/cmt_test_success.png
--------------------------------------------------------------------------------
/icons/spine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/spine.png
--------------------------------------------------------------------------------
/icons/spine.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/spine.psd
--------------------------------------------------------------------------------
/icons/swingTwist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/swingTwist.png
--------------------------------------------------------------------------------
/icons/swingTwist.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/swingTwist.psd
--------------------------------------------------------------------------------
/icons/test_icons.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/test_icons.psd
--------------------------------------------------------------------------------
/icons/test_toolbar.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/icons/test_toolbar.psd
--------------------------------------------------------------------------------
/plug-ins/cmt_py.py:
--------------------------------------------------------------------------------
1 | import maya.OpenMayaMPx as OpenMayaMPx
2 | import cmt.plugins.swingtwist as swingtwist
3 |
4 |
5 | def initializePlugin(obj):
6 | plugin = OpenMayaMPx.MFnPlugin(obj, 'Chad Vernon', '1.0', 'Any')
7 |
8 | # plugin.registerNode(swingtwist.SwingTwistNode.name, swingtwist.SwingTwistNode.id,
9 | # swingtwist.SwingTwistNode.creator, swingtwist.SwingTwistNode.initialize)
10 | #
11 | # plugin.registerCommand(swingtwist.SwingTwistCommand.name, swingtwist.SwingTwistCommand.creator,
12 | # swingtwist.SwingTwistCommand.command_syntax)
13 | #
14 |
15 | def uninitializePlugin(obj):
16 | plugin = OpenMayaMPx.MFnPlugin(obj)
17 |
18 | # plugin.deregisterCommand(swingtwist.SwingTwistCommand.name)
19 | # plugin.deregisterNode(swingtwist.SwingTwistNode.id)
20 |
--------------------------------------------------------------------------------
/scripts/cmt/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | CMT (Chad's Maya Tools) is a collection of the Maya tools and plug-ins I (Chad Vernon)
3 | have developed for use in my projects. You are free to use them in your projects too!
4 |
5 | CMT is licensed under:
6 |
7 | The MIT License (MIT)
8 |
9 | Copyright (c) 2018 Chad Vernon
10 |
11 | Permission is hereby granted, free of charge, to any person obtaining a copy
12 | of this software and associated documentation files (the "Software"), to deal
13 | in the Software without restriction, including without limitation the rights
14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | copies of the Software, and to permit persons to whom the Software is
16 | furnished to do so, subject to the following conditions:
17 |
18 | The above copyright notice and this permission notice shall be included in all
19 | copies or substantial portions of the Software.
20 |
21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | SOFTWARE.
28 | """
29 | import logging
30 |
31 | log = logging.getLogger(__name__)
32 |
33 |
34 | def initialize():
35 | """
36 | Runs any initialization for CMT such as creating the menu.
37 | """
38 | import cmt.menu
39 | import cmt.reloadmodules
40 |
41 | cmt.menu.create_menu()
42 |
--------------------------------------------------------------------------------
/scripts/cmt/anim/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/anim/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/deform/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/deform/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/deform/np_mesh.py:
--------------------------------------------------------------------------------
1 | """Efficient mesh processing using numpy"""
2 |
3 | import numpy as np
4 | import os
5 | import json
6 | import maya.api.OpenMaya as OpenMaya
7 | import cmt.shortcuts as shortcuts
8 |
9 |
10 | class Mesh(object):
11 | @classmethod
12 | def from_obj(cls, file_path):
13 | with open(file_path, "r") as fh:
14 | lines = fh.readlines()
15 |
16 | points = []
17 | read_vertices = False
18 | for line in lines:
19 | if line.startswith("v "):
20 | read_vertices = True
21 | v = line.split()[1:]
22 | points.append([float(v[0]), float(v[1]), float(v[2])])
23 | elif read_vertices:
24 | break
25 | points = np.array(points)
26 | name = os.path.splitext(os.path.basename(file_path))[0]
27 | return Mesh(points, name)
28 |
29 | @classmethod
30 | def from_maya_mesh(cls, mesh):
31 |
32 | points = shortcuts.get_points(mesh)
33 | points = np.array([[p.x, p.y, p.z] for p in points])
34 | return Mesh(points)
35 |
36 | def __init__(self, points, name=None):
37 | self.points = points
38 | self.name = name
39 |
40 | def mask_points(self, base, mask):
41 | points = base.points + ((self.points - base.points).T * mask.values).T
42 | name = "{}_{}".format(self.name, mask.name)
43 | return Mesh(points, name)
44 |
45 | def separate_axis(
46 | self,
47 | base,
48 | x_axis=1.0,
49 | y_axis=1.0,
50 | z_axis=1.0,
51 | x_direction=0,
52 | y_direction=0,
53 | z_direction=0,
54 | ):
55 | axis_scale = np.array([x_axis, y_axis, z_axis])
56 | deltas = (self.points - base.points) * axis_scale
57 |
58 | isolate_vector_direction(deltas, x_direction, 0)
59 | isolate_vector_direction(deltas, y_direction, 1)
60 | isolate_vector_direction(deltas, z_direction, 2)
61 |
62 | points = base.points + deltas
63 | name = "{}_".format(self.name)
64 | if x_axis != 0.0:
65 | name += "X"
66 | if y_axis != 0.0:
67 | name += "Y"
68 | if z_axis != 0.0:
69 | name += "Z"
70 | return Mesh(points, name)
71 |
72 | def to_maya_mesh(self, mesh):
73 |
74 | points = OpenMaya.MPointArray()
75 | for p in self.points:
76 | points.append(OpenMaya.MPoint(p[0], p[1], p[2]))
77 | shortcuts.set_points(mesh, points)
78 |
79 | def __sub__(self, other):
80 | points = (self.points - other.points)
81 | return Mesh(points)
82 |
83 | def __add__(self, other):
84 | points = (self.points + other.points)
85 | return Mesh(points)
86 |
87 |
88 | def isolate_vector_direction(deltas, direction, axis):
89 | if direction < 0:
90 | deltas[:, :][deltas[:, axis] > 0] = 0
91 | elif direction > 0:
92 | deltas[:, :][deltas[:, axis] < 0] = 0
93 | return deltas
94 |
95 |
96 | class Mask(object):
97 | """1D array of float values."""
98 |
99 | @classmethod
100 | def from_file(cls, file_path):
101 | with open(file_path, "r") as fh:
102 | data = json.load(fh)
103 | values = np.array(data)
104 | name = os.path.splitext(os.path.basename(file_path))[0]
105 | return Mask(values, name)
106 |
107 | @classmethod
108 | def normalize(cls, masks):
109 | stacked = np.stack([m.values for m in masks])
110 | totals = np.sum(stacked, axis=0)
111 | totals[totals == 0.0] = 1.0
112 | normalized = stacked / totals
113 | normalized_masks = [Mask(*n) for n in zip(normalized, [m.name for m in masks])]
114 | return normalized_masks
115 |
116 | def __init__(self, values, name=None):
117 | self.values = values
118 | self.name = name
119 |
120 | def __mul__(self, other):
121 | if not isinstance(other, Mask):
122 | raise RuntimeError(
123 | "Unable to multiply Mask with type {}".format(type(other))
124 | )
125 | name = "{}_{}".format(self.name, other.name)
126 | return Mask(self.values * other.values, name)
127 |
--------------------------------------------------------------------------------
/scripts/cmt/io/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/io/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/io/obj.py:
--------------------------------------------------------------------------------
1 | import os
2 | import maya.cmds as cmds
3 | import logging
4 | logger = logging.getLogger(__name__)
5 |
6 |
7 | def import_obj(file_path):
8 |
9 | old_nodes = set(cmds.ls(assemblies=True))
10 |
11 | cmds.file(
12 | file_path,
13 | i=True,
14 | type="OBJ",
15 | ignoreVersion=True,
16 | mergeNamespacesOnClash=False,
17 | options="mo=0",
18 | )
19 |
20 | new_nodes = set(cmds.ls(assemblies=True))
21 | new_nodes = new_nodes.difference(old_nodes)
22 | new_mesh = list(new_nodes)[0]
23 | name = os.path.splitext(os.path.basename(file_path))[0]
24 | return cmds.rename(new_mesh, name)
25 |
26 |
27 | def export_obj(mesh, file_path):
28 | cmds.select(mesh)
29 | cmds.file(
30 | file_path,
31 | force=True,
32 | options="groups=0;ptgroups=0;materials=0;smoothing=0;normals=0",
33 | typ="OBJexport",
34 | es=True,
35 | )
36 | logger.info("Exported {}".format(file_path))
37 |
--------------------------------------------------------------------------------
/scripts/cmt/model/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/model/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/pipeline/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/pipeline/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/plugins/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/reloadmodules.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 |
4 | class RollbackImporter(object):
5 | """Used to remove imported modules from the module list.
6 |
7 | This allows tests to be rerun after code updates without doing any reloads.
8 | Original idea from: http://pyunit.sourceforge.net/notes/reloading.html
9 |
10 | Usage:
11 | def run_tests(self):
12 | if self.rollback_importer:
13 | self.rollback_importer.uninstall()
14 | self.rollback_importer = RollbackImporter()
15 | self.load_and_execute_tests()
16 | """
17 |
18 | def __init__(self):
19 | """Creates an instance and installs as the global importer."""
20 | self.previous_modules = set(sys.modules.keys())
21 |
22 | def uninstall(self):
23 | for modname in sys.modules.keys():
24 | if modname not in self.previous_modules:
25 | # Force reload when modname next imported
26 | del (sys.modules[modname])
27 |
28 |
29 | _rollbackimporter = RollbackImporter()
30 |
31 |
32 | def save_modules():
33 | global _rollbackimporter
34 | _rollbackimporter = RollbackImporter()
35 |
36 |
37 | def reload_modules():
38 | global _rollbackimporter
39 | _rollbackimporter.uninstall()
40 |
--------------------------------------------------------------------------------
/scripts/cmt/rig/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/rig/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/rig/arm.py:
--------------------------------------------------------------------------------
1 | import maya.cmds as cmds
2 | import maya.api.OpenMaya as OpenMaya
3 | import cmt.shortcuts as shortcuts
4 | import cmt.rig.common as common
5 | from cmt.dge import dge
6 | import cmt.rig.twoboneik as twoboneik
7 |
8 | reload(twoboneik)
9 |
10 |
11 | class ArmRig(object):
12 | def __init__(self, upper_arm_joint, hand_joint, name="arm"):
13 | self.two_bone_ik = twoboneik.TwoBoneIk(upper_arm_joint, hand_joint, name)
14 | self.name = name
15 | self.group = "{}_grp".format(self.name)
16 |
17 | def create(
18 | self,
19 | ik_control,
20 | pole_vector=None,
21 | global_scale_attr=None,
22 | scale_stretch=True,
23 | parent=None,
24 | ):
25 | if not cmds.objExists(self.group):
26 | self.group = cmds.createNode("transform", name=self.group)
27 |
28 | # self.__create_pivots(ik_control, pivots)
29 | self.two_bone_ik.create(
30 | ik_control,
31 | pole_vector,
32 | soft_ik_parent=ik_control,
33 | global_scale_attr=global_scale_attr,
34 | scale_stretch=scale_stretch,
35 | parent=parent,
36 | )
37 | self.config_control = self.two_bone_ik.config_control
38 | self.upper_fk_control = self.two_bone_ik.start_fk_control
39 | cmds.parent(self.two_bone_ik.start_loc, self.group)
40 | cmds.addAttr(
41 | ik_control,
42 | ln="localRotation",
43 | minValue=0,
44 | maxValue=1,
45 | keyable=True,
46 | )
47 | self.local_rotation = "{}.localRotation".format(ik_control)
48 |
49 | self.rotation_control = cmds.createNode(
50 | "transform", name="{}_rotate_ctrl".format(self.two_bone_ik.end_joint)
51 | )
52 |
53 | common.snap_to(self.rotation_control, self.two_bone_ik.end_joint)
54 | if parent:
55 | cmds.parent(self.rotation_control, parent)
56 | common.freeze_to_parent_offset(self.rotation_control)
57 | common.opm_parent_constraint(
58 | self.two_bone_ik.mid_joint, self.rotation_control, maintain_offset=True
59 | )
60 | common.lock_and_hide(self.rotation_control, "tsv")
61 |
62 | # Drive the wrist joint
63 | wrist_ori = cmds.createNode(
64 | "transform", name="{}_orient".format(self.two_bone_ik.end_joint)
65 | )
66 | cmds.parent(wrist_ori, ik_control)
67 | common.snap_to(wrist_ori, self.two_bone_ik.end_joint)
68 | ori = cmds.orientConstraint(
69 | wrist_ori, self.rotation_control, self.two_bone_ik.end_joint
70 | )[0]
71 | inv_ikfk = dge("1.0 - ikFk", ikFk="{}.ikFk".format(self.config_control))
72 | dge(
73 | "W1 = inv_ikfk * (1.0 - local)",
74 | W1="{}.{}W1".format(ori, wrist_ori),
75 | inv_ikfk=inv_ikfk,
76 | local=self.local_rotation,
77 | )
78 | dge(
79 | "W2 = inv_ikfk * local",
80 | W2="{}.{}W2".format(ori, self.rotation_control),
81 | inv_ikfk=inv_ikfk,
82 | local=self.local_rotation,
83 | )
84 |
85 | def __create_pivots(self, ik_control, pivots):
86 | """
87 | """
88 | hierarchy = {
89 | "ball_pivot": {
90 | "heel_pivot_ctrl": {
91 | "out_pivot": {
92 | "in_pivot": {
93 | "toe_pivot_ctrl": {"toe_ctrl": None, "heel_ctrl": None}
94 | }
95 | }
96 | }
97 | }
98 | }
99 | hierarchy = common.RigHierarchy(
100 | hierarchy,
101 | prefix="{}_".format(self.name),
102 | suffix="",
103 | lock_and_hide=["s", "v"],
104 | )
105 | hierarchy.create()
106 | cmds.parent(hierarchy.ball_pivot, ik_control)
107 | for driver, driven in [
108 | [self.ball_joint, hierarchy.ball_pivot],
109 | [self.two_bone_ik.end_joint, hierarchy.heel_pivot_ctrl],
110 | [self.ball_joint, hierarchy.out_pivot],
111 | [self.ball_joint, hierarchy.in_pivot],
112 | [self.toe_joint, hierarchy.toe_pivot_ctrl],
113 | [self.ball_joint, hierarchy.toe_ctrl],
114 | [self.ball_joint, hierarchy.heel_ctrl],
115 | ]:
116 | common.snap_to_position(driven, driver)
117 | for node, position in pivots.items():
118 | node = getattr(hierarchy, node, None)
119 | if not node:
120 | continue
121 | children = cmds.listRelatives(node, children=True, path=True)
122 | if children:
123 | cmds.parent(children, world=True)
124 | cmds.xform(node, ws=True, t=position)
125 | if children:
126 | cmds.parent(children, node)
127 |
128 | hierarchy.parent_to_heel_ctrl(self.ik_handle_ball)
129 | hierarchy.parent_to_toe_ctrl(self.ik_handle_toe)
130 | common.lock_and_hide(hierarchy.heel_ctrl, "t")
131 | common.lock_and_hide(hierarchy.toe_pivot_ctrl, "t")
132 | cmds.setAttr("{}.rotateOrder".format(hierarchy.heel_ctrl), 2) # zxy
133 |
134 | self.hierarchy = hierarchy
135 |
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/arrow.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7
12 | ],
13 | "degree": 1,
14 | "form": 0,
15 | "color": null,
16 | "cvs": [
17 | [
18 | -0.66,
19 | 0.0,
20 | -0.33
21 | ],
22 | [
23 | 0.0,
24 | 0.0,
25 | -0.33
26 | ],
27 | [
28 | 0.0,
29 | 0.0,
30 | -0.66
31 | ],
32 | [
33 | 0.99,
34 | 0.0,
35 | 0.0
36 | ],
37 | [
38 | 0.0,
39 | 0.0,
40 | 0.66
41 | ],
42 | [
43 | 0.0,
44 | 0.0,
45 | 0.33
46 | ],
47 | [
48 | -0.66,
49 | 0.0,
50 | 0.33
51 | ],
52 | [
53 | -0.66,
54 | 0.0,
55 | -0.33
56 | ]
57 | ],
58 | "transform": "arrow"
59 | }
60 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/barbell.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9,
14 | 10,
15 | 11,
16 | 12,
17 | 13,
18 | 14,
19 | 15,
20 | 16,
21 | 17,
22 | 18,
23 | 19,
24 | 20,
25 | 21,
26 | 22
27 | ],
28 | "degree": 1,
29 | "form": 0,
30 | "color": null,
31 | "cvs": [
32 | [
33 | -1.4695761589768238e-16,
34 | -1.2,
35 | 0.0
36 | ],
37 | [
38 | -0.23511400000000016,
39 | -1.276393,
40 | 0.0
41 | ],
42 | [
43 | -0.3804230000000002,
44 | -1.476393,
45 | 0.0
46 | ],
47 | [
48 | -0.38042300000000023,
49 | -1.723607,
50 | 0.0
51 | ],
52 | [
53 | -0.2351140000000002,
54 | -1.923607,
55 | 0.0
56 | ],
57 | [
58 | -2.4492935982947064e-16,
59 | -2.0,
60 | 0.0
61 | ],
62 | [
63 | 0.23511399999999977,
64 | -1.923607,
65 | 0.0
66 | ],
67 | [
68 | 0.3804229999999998,
69 | -1.723607,
70 | 0.0
71 | ],
72 | [
73 | 0.38042299999999984,
74 | -1.476393,
75 | 0.0
76 | ],
77 | [
78 | 0.23511399999999982,
79 | -1.276393,
80 | 0.0
81 | ],
82 | [
83 | -1.4695761589768238e-16,
84 | -1.2,
85 | 0.0
86 | ],
87 | [
88 | 0.0,
89 | 0.0,
90 | 0.0
91 | ],
92 | [
93 | 0.0,
94 | 1.2,
95 | 0.0
96 | ],
97 | [
98 | -0.235114,
99 | 1.276393,
100 | 0.0
101 | ],
102 | [
103 | -0.380423,
104 | 1.476393,
105 | 0.0
106 | ],
107 | [
108 | -0.380423,
109 | 1.723607,
110 | 0.0
111 | ],
112 | [
113 | -0.235114,
114 | 1.923607,
115 | 0.0
116 | ],
117 | [
118 | 0.0,
119 | 2.0,
120 | 0.0
121 | ],
122 | [
123 | 0.235114,
124 | 1.923607,
125 | 0.0
126 | ],
127 | [
128 | 0.380423,
129 | 1.723607,
130 | 0.0
131 | ],
132 | [
133 | 0.380423,
134 | 1.476393,
135 | 0.0
136 | ],
137 | [
138 | 0.235114,
139 | 1.276393,
140 | 0.0
141 | ],
142 | [
143 | 0.0,
144 | 1.2,
145 | 0.0
146 | ]
147 | ],
148 | "transform": "barbell"
149 | }
150 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/circle.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | -2,
5 | -1,
6 | 0,
7 | 1,
8 | 2,
9 | 3,
10 | 4,
11 | 5,
12 | 6,
13 | 7,
14 | 8,
15 | 9,
16 | 10
17 | ],
18 | "degree": 3,
19 | "form": 2,
20 | "color": null,
21 | "cvs": [
22 | [
23 | 1.2601436025374922e-16,
24 | 0.783611624891225,
25 | -0.7836116248912238
26 | ],
27 | [
28 | -6.785732323110916e-17,
29 | -1.2643170607829324e-16,
30 | -1.108194187554388
31 | ],
32 | [
33 | -2.2197910707351845e-16,
34 | -0.7836116248912243,
35 | -0.7836116248912243
36 | ],
37 | [
38 | -2.460685405557301e-16,
39 | -1.108194187554388,
40 | -3.21126950723723e-16
41 | ],
42 | [
43 | -1.2601436025374907e-16,
44 | -0.7836116248912245,
45 | 0.783611624891224
46 | ],
47 | [
48 | 6.785732323110907e-17,
49 | -3.3392053635905195e-16,
50 | 1.1081941875543881
51 | ],
52 | [
53 | 2.2197910707351835e-16,
54 | 0.7836116248912238,
55 | 0.7836116248912244
56 | ],
57 | [
58 | 2.4606854055573016e-16,
59 | 1.108194187554388,
60 | 5.952132599280585e-16
61 | ]
62 | ],
63 | "transform": "circle"
64 | }
65 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/circle_arrow.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9,
14 | 10,
15 | 11,
16 | 12,
17 | 13,
18 | 14,
19 | 15,
20 | 16,
21 | 17,
22 | 18,
23 | 19,
24 | 20,
25 | 21,
26 | 22,
27 | 23,
28 | 24,
29 | 25,
30 | 26,
31 | 27,
32 | 28,
33 | 29
34 | ],
35 | "degree": 1,
36 | "form": 0,
37 | "color": null,
38 | "cvs": [
39 | [
40 | -1.084005,
41 | 0.0,
42 | -0.092136
43 | ],
44 | [
45 | -0.791121,
46 | 0.0,
47 | -0.955956
48 | ],
49 | [
50 | -0.707107,
51 | 0.0,
52 | -0.707107
53 | ],
54 | [
55 | -0.570265,
56 | 0.0,
57 | -0.843948
58 | ],
59 | [
60 | -0.205819,
61 | 0.0,
62 | -1.040044
63 | ],
64 | [
65 | 0.405223,
66 | 0.0,
67 | -0.978634
68 | ],
69 | [
70 | 0.881027,
71 | 0.0,
72 | -0.588697
73 | ],
74 | [
75 | 1.059487,
76 | 0.0,
77 | 0.0
78 | ],
79 | [
80 | 0.881027,
81 | 0.0,
82 | 0.588697
83 | ],
84 | [
85 | 0.405223,
86 | 0.0,
87 | 0.978634
88 | ],
89 | [
90 | -0.205819,
91 | 0.0,
92 | 1.040044
93 | ],
94 | [
95 | -0.570265,
96 | 0.0,
97 | 0.843948
98 | ],
99 | [
100 | -0.707107,
101 | 0.0,
102 | 0.707107
103 | ],
104 | [
105 | -0.791121,
106 | 0.0,
107 | 0.955956
108 | ],
109 | [
110 | -1.084005,
111 | 0.0,
112 | 0.092136
113 | ],
114 | [
115 | -0.315189,
116 | 0.0,
117 | 0.413069
118 | ],
119 | [
120 | -0.540989,
121 | 0.0,
122 | 0.540989
123 | ],
124 | [
125 | -0.436294,
126 | 0.0,
127 | 0.645682
128 | ],
129 | [
130 | -0.157467,
131 | 0.0,
132 | 0.79571
133 | ],
134 | [
135 | 0.310025,
136 | 0.0,
137 | 0.748727
138 | ],
139 | [
140 | 0.67405,
141 | 0.0,
142 | 0.450396
143 | ],
144 | [
145 | 0.810585,
146 | 0.0,
147 | 0.0
148 | ],
149 | [
150 | 0.67405,
151 | 0.0,
152 | -0.450396
153 | ],
154 | [
155 | 0.310025,
156 | 0.0,
157 | -0.748727
158 | ],
159 | [
160 | -0.157467,
161 | 0.0,
162 | -0.79571
163 | ],
164 | [
165 | -0.436294,
166 | 0.0,
167 | -0.645682
168 | ],
169 | [
170 | -0.540989,
171 | 0.0,
172 | -0.540989
173 | ],
174 | [
175 | -0.315189,
176 | 0.0,
177 | -0.413069
178 | ],
179 | [
180 | -1.084005,
181 | 0.0,
182 | -0.092136
183 | ],
184 | [
185 | -0.791121,
186 | 0.0,
187 | -0.955956
188 | ]
189 | ],
190 | "transform": "circle_arrow"
191 | }
192 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/cube.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 0,
6 | 0,
7 | 0,
8 | 0,
9 | 0,
10 | 0,
11 | 0,
12 | 0,
13 | 0,
14 | 1,
15 | 1,
16 | 1,
17 | 1,
18 | 1,
19 | 1,
20 | 1,
21 | 1,
22 | 1
23 | ],
24 | "degree": 1,
25 | "form": 0,
26 | "color": null,
27 | "cvs": [
28 | [
29 | 0.5,
30 | 0.5,
31 | -0.5
32 | ],
33 | [
34 | 0.5,
35 | 0.5,
36 | 0.5
37 | ],
38 | [
39 | 0.5,
40 | -0.5,
41 | 0.5
42 | ],
43 | [
44 | 0.5,
45 | -0.5,
46 | -0.5
47 | ],
48 | [
49 | 0.5,
50 | 0.5,
51 | -0.5
52 | ],
53 | [
54 | -0.5,
55 | 0.5,
56 | -0.5
57 | ],
58 | [
59 | -0.5,
60 | -0.5,
61 | -0.5
62 | ],
63 | [
64 | -0.5,
65 | -0.5,
66 | 0.5
67 | ],
68 | [
69 | -0.5,
70 | 0.5,
71 | 0.5
72 | ],
73 | [
74 | 0.5,
75 | 0.5,
76 | 0.5
77 | ],
78 | [
79 | 0.5,
80 | -0.5,
81 | 0.5
82 | ],
83 | [
84 | -0.5,
85 | -0.5,
86 | 0.5
87 | ],
88 | [
89 | -0.5,
90 | -0.5,
91 | -0.5
92 | ],
93 | [
94 | 0.5,
95 | -0.5,
96 | -0.5
97 | ],
98 | [
99 | 0.5,
100 | 0.5,
101 | -0.5
102 | ],
103 | [
104 | -0.5,
105 | 0.5,
106 | -0.5
107 | ],
108 | [
109 | -0.5,
110 | 0.5,
111 | 0.5
112 | ],
113 | [
114 | 0.5,
115 | 0.5,
116 | 0.5
117 | ],
118 | [
119 | 0.5,
120 | 0.5,
121 | -0.5
122 | ]
123 | ],
124 | "transform": "cube"
125 | }
126 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/four_arrow_flat.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9,
14 | 10,
15 | 11,
16 | 12,
17 | 13,
18 | 14,
19 | 15,
20 | 16,
21 | 17,
22 | 18,
23 | 19,
24 | 20,
25 | 21,
26 | 22,
27 | 23,
28 | 24,
29 | 25
30 | ],
31 | "degree": 1,
32 | "form": 0,
33 | "color": null,
34 | "cvs": [
35 | [
36 | -0.20232736113964017,
37 | 0.0,
38 | -0.19597824869222055
39 | ],
40 | [
41 | -0.20232736113964017,
42 | 0.0,
43 | -0.6047152875596473
44 | ],
45 | [
46 | -0.20232736113964017,
47 | 0.0,
48 | -0.6047152875596473
49 | ],
50 | [
51 | -0.4007772028417856,
52 | 0.0,
53 | -0.6047152876853943
54 | ],
55 | [
56 | 0.0,
57 | 0.0,
58 | -1.0019430071044664
59 | ],
60 | [
61 | 0.4007772028417856,
62 | 0.0,
63 | -0.6011658042626783
64 | ],
65 | [
66 | 0.2003886014208928,
67 | 0.0,
68 | -0.6011658042626783
69 | ],
70 | [
71 | 0.2003886014208928,
72 | 0.0,
73 | -0.2003886014208928
74 | ],
75 | [
76 | 0.6011658042626783,
77 | 0.0,
78 | -0.2003886014208928
79 | ],
80 | [
81 | 0.6011658042626783,
82 | 0.0,
83 | -0.4007772028417856
84 | ],
85 | [
86 | 1.0019430071044664,
87 | 0.0,
88 | 0.0
89 | ],
90 | [
91 | 0.6011658042626783,
92 | 0.0,
93 | 0.4007772028417856
94 | ],
95 | [
96 | 0.6011658042626783,
97 | 0.0,
98 | 0.2003886014208928
99 | ],
100 | [
101 | 0.2003886014208928,
102 | 0.0,
103 | 0.2003886014208928
104 | ],
105 | [
106 | 0.2003886014208928,
107 | 0.0,
108 | 0.6011658042626783
109 | ],
110 | [
111 | 0.4007772028417856,
112 | 0.0,
113 | 0.6011658042626783
114 | ],
115 | [
116 | 0.0,
117 | 0.0,
118 | 1.0019430071044664
119 | ],
120 | [
121 | -0.4007772028417856,
122 | 0.0,
123 | 0.6011658042626783
124 | ],
125 | [
126 | -0.2003886014208928,
127 | 0.0,
128 | 0.6011658042626783
129 | ],
130 | [
131 | -0.2003886014208928,
132 | 0.0,
133 | 0.2003886014208928
134 | ],
135 | [
136 | -0.6011658042626783,
137 | 0.0,
138 | 0.2003886014208928
139 | ],
140 | [
141 | -0.6011658042626783,
142 | 0.0,
143 | 0.4007772028417856
144 | ],
145 | [
146 | -1.0019430071044664,
147 | 0.0,
148 | 0.0
149 | ],
150 | [
151 | -0.6011658042626783,
152 | 0.0,
153 | -0.4007772028417856
154 | ],
155 | [
156 | -0.6011658042626783,
157 | 0.0,
158 | -0.2003886014208928
159 | ],
160 | [
161 | -0.2003886014208928,
162 | 0.0,
163 | -0.2003886014208928
164 | ]
165 | ],
166 | "transform": "four_arrow_flat"
167 | }
168 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/locator.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7
12 | ],
13 | "degree": 1,
14 | "form": 0,
15 | "color": null,
16 | "cvs": [
17 | [
18 | 0.0,
19 | 0.0,
20 | 1.0
21 | ],
22 | [
23 | 0.0,
24 | 0.0,
25 | -1.0
26 | ],
27 | [
28 | 0.0,
29 | 0.0,
30 | 0.0
31 | ],
32 | [
33 | 1.0,
34 | 0.0,
35 | 0.0
36 | ],
37 | [
38 | -1.0,
39 | 0.0,
40 | 0.0
41 | ],
42 | [
43 | 0.0,
44 | 0.0,
45 | 0.0
46 | ],
47 | [
48 | 0.0,
49 | 1.0,
50 | 0.0
51 | ],
52 | [
53 | 0.0,
54 | -1.0,
55 | 0.0
56 | ]
57 | ],
58 | "transform": "locator"
59 | }
60 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/lollipop.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9,
14 | 10,
15 | 11
16 | ],
17 | "degree": 1,
18 | "form": 0,
19 | "color": null,
20 | "cvs": [
21 | [
22 | 0.0,
23 | 0.0,
24 | 0.0
25 | ],
26 | [
27 | 0.0,
28 | 1.2,
29 | 0.0
30 | ],
31 | [
32 | -0.235114,
33 | 1.276393,
34 | 0.0
35 | ],
36 | [
37 | -0.380423,
38 | 1.476393,
39 | 0.0
40 | ],
41 | [
42 | -0.380423,
43 | 1.723607,
44 | 0.0
45 | ],
46 | [
47 | -0.235114,
48 | 1.923607,
49 | 0.0
50 | ],
51 | [
52 | 0.0,
53 | 2.0,
54 | 0.0
55 | ],
56 | [
57 | 0.235114,
58 | 1.923607,
59 | 0.0
60 | ],
61 | [
62 | 0.380423,
63 | 1.723607,
64 | 0.0
65 | ],
66 | [
67 | 0.380423,
68 | 1.476393,
69 | 0.0
70 | ],
71 | [
72 | 0.235114,
73 | 1.276393,
74 | 0.0
75 | ],
76 | [
77 | 0.0,
78 | 1.2,
79 | 0.0
80 | ]
81 | ],
82 | "transform": "lollipop"
83 | }
84 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/pointed_circle.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 0,
6 | 0,
7 | 1,
8 | 2,
9 | 3,
10 | 4,
11 | 5,
12 | 6,
13 | 7,
14 | 8,
15 | 9,
16 | 10,
17 | 11,
18 | 12,
19 | 13,
20 | 13,
21 | 13
22 | ],
23 | "degree": 3,
24 | "form": 0,
25 | "color": null,
26 | "cvs": [
27 | [
28 | 0.0,
29 | 0.0,
30 | 1.4458237945008834
31 | ],
32 | [
33 | 0.3390851803340782,
34 | 0.0,
35 | 0.9577110694510105
36 | ],
37 | [
38 | 0.3390851803340782,
39 | 0.0,
40 | 0.9577110694510105
41 | ],
42 | [
43 | 0.3390851803340782,
44 | 0.0,
45 | 0.9577110694510105
46 | ],
47 | [
48 | 0.8764628251341291,
49 | 0.0,
50 | 0.6064978822415238
51 | ],
52 | [
53 | 1.0070584462523031,
54 | 0.0,
55 | 0.01580116213963464
56 | ],
57 | [
58 | 0.8866375910572012,
59 | 0.0,
60 | -0.5159192834604646
61 | ],
62 | [
63 | 0.3592715607483328,
64 | 0.0,
65 | -0.9858403104926516
66 | ],
67 | [
68 | -0.3592715607483328,
69 | 0.0,
70 | -0.9858403104926516
71 | ],
72 | [
73 | -0.8866375910572012,
74 | 0.0,
75 | -0.5159192834604646
76 | ],
77 | [
78 | -1.0070584462523031,
79 | 0.0,
80 | 0.01580116213963464
81 | ],
82 | [
83 | -0.8764628251341291,
84 | 0.0,
85 | 0.6064978822415238
86 | ],
87 | [
88 | -0.3390851803340782,
89 | 0.0,
90 | 0.9577110694510105
91 | ],
92 | [
93 | -0.3390851803340782,
94 | 0.0,
95 | 0.9577110694510105
96 | ],
97 | [
98 | -0.3390851803340782,
99 | 0.0,
100 | 0.9577110694510105
101 | ],
102 | [
103 | 0.0,
104 | 0.0,
105 | 1.4458237945008834
106 | ]
107 | ],
108 | "transform": "pointed_circle"
109 | }
110 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/pyramid.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9
14 | ],
15 | "degree": 1,
16 | "form": 0,
17 | "color": null,
18 | "cvs": [
19 | [
20 | 0.006234634768881182,
21 | 0.4959534703003189,
22 | 0.4959534703003189
23 | ],
24 | [
25 | 0.006234634768881182,
26 | 0.4959534703003189,
27 | -0.4959534703003189
28 | ],
29 | [
30 | 0.006234634768881182,
31 | -0.4959534703003189,
32 | -0.4959534703003189
33 | ],
34 | [
35 | 0.006234634768881182,
36 | -0.4959534703003189,
37 | 0.4959534703003189
38 | ],
39 | [
40 | 0.006234634768881182,
41 | 0.4959534703003189,
42 | 0.4959534703003189
43 | ],
44 | [
45 | 0.9981415753695205,
46 | 0.0,
47 | 0.0
48 | ],
49 | [
50 | 0.006234634768881182,
51 | -0.4959534703003189,
52 | 0.4959534703003189
53 | ],
54 | [
55 | 0.006234634768881182,
56 | -0.4959534703003189,
57 | -0.4959534703003189
58 | ],
59 | [
60 | 0.9981415753695205,
61 | 0.0,
62 | 0.0
63 | ],
64 | [
65 | 0.006234634768881182,
66 | 0.4959534703003189,
67 | -0.4959534703003189
68 | ]
69 | ],
70 | "transform": "pyramid"
71 | }
72 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/sharp_4_point_star.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | -2,
5 | -1,
6 | 0,
7 | 1,
8 | 2,
9 | 3,
10 | 4,
11 | 5,
12 | 6,
13 | 7,
14 | 8,
15 | 9,
16 | 10
17 | ],
18 | "degree": 3,
19 | "form": 2,
20 | "color": null,
21 | "cvs": [
22 | [
23 | 4.3028001425820526e-18,
24 | 0.07027005901747052,
25 | -0.07027005901747063
26 | ],
27 | [
28 | -7.74170920797604e-33,
29 | 1.108194187554388,
30 | 1.2643170607829326e-16
31 | ],
32 | [
33 | -4.3028001425820464e-18,
34 | 0.07027005901747063,
35 | 0.07027005901747063
36 | ],
37 | [
38 | -6.785732323110913e-17,
39 | 3.21126950723723e-16,
40 | 1.108194187554388
41 | ],
42 | [
43 | -4.3028001425820464e-18,
44 | -0.07027005901747052,
45 | 0.07027005901747063
46 | ],
47 | [
48 | -2.0446735801084019e-32,
49 | -1.1081941875543881,
50 | 3.3392053635905195e-16
51 | ],
52 | [
53 | 4.3028001425820464e-18,
54 | -0.07027005901747063,
55 | -0.07027005901747052
56 | ],
57 | [
58 | 6.785732323110913e-17,
59 | -5.952132599280585e-16,
60 | -1.108194187554388
61 | ]
62 | ],
63 | "transform": "sharp_4_point_star"
64 | }
65 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/sphere_quarter.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9,
14 | 10,
15 | 11,
16 | 12,
17 | 13,
18 | 14,
19 | 15,
20 | 16,
21 | 17,
22 | 18,
23 | 19,
24 | 20
25 | ],
26 | "degree": 1,
27 | "form": 0,
28 | "color": null,
29 | "cvs": [
30 | [
31 | 1.0,
32 | 0.0,
33 | 0.0
34 | ],
35 | [
36 | 0.9238799810409546,
37 | 0.0,
38 | 0.38268300890922546
39 | ],
40 | [
41 | 0.7071070075035095,
42 | 0.0,
43 | 0.7071070075035095
44 | ],
45 | [
46 | 0.38268300890922546,
47 | 0.0,
48 | 0.9238799810409546
49 | ],
50 | [
51 | 0.0,
52 | 0.0,
53 | 1.0
54 | ],
55 | [
56 | 0.0,
57 | 0.38268300890922546,
58 | 0.9238799810409546
59 | ],
60 | [
61 | 0.0,
62 | 0.7071070075035095,
63 | 0.7071070075035095
64 | ],
65 | [
66 | 0.0,
67 | 0.9238799810409546,
68 | 0.38268300890922546
69 | ],
70 | [
71 | 0.0,
72 | 1.0,
73 | 0.0
74 | ],
75 | [
76 | 0.38268300890922546,
77 | 0.9238799810409546,
78 | 0.0
79 | ],
80 | [
81 | 0.7071070075035095,
82 | 0.7071070075035095,
83 | 0.0
84 | ],
85 | [
86 | 0.9238799810409546,
87 | 0.38268300890922546,
88 | 0.0
89 | ],
90 | [
91 | 1.0,
92 | 0.0,
93 | 0.0
94 | ],
95 | [
96 | 0.9238799810409546,
97 | 0.0,
98 | -0.38268300890922546
99 | ],
100 | [
101 | 0.7071070075035095,
102 | 0.0,
103 | -0.7071070075035095
104 | ],
105 | [
106 | 0.38268300890922546,
107 | 0.0,
108 | -0.9238799810409546
109 | ],
110 | [
111 | 0.0,
112 | 0.0,
113 | -1.0
114 | ],
115 | [
116 | 0.0,
117 | 0.38268300890922546,
118 | -0.9238799810409546
119 | ],
120 | [
121 | 0.0,
122 | 0.7071070075035095,
123 | -0.7071070075035095
124 | ],
125 | [
126 | 0.0,
127 | 0.9238799810409546,
128 | -0.38268300890922546
129 | ],
130 | [
131 | 0.0,
132 | 1.0,
133 | 0.0
134 | ]
135 | ],
136 | "transform": "sphere_quarter"
137 | }
138 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/square.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4
9 | ],
10 | "degree": 1,
11 | "form": 0,
12 | "color": null,
13 | "cvs": [
14 | [
15 | 0.0,
16 | -0.5,
17 | 0.5
18 | ],
19 | [
20 | 0.0,
21 | 0.5,
22 | 0.5
23 | ],
24 | [
25 | 0.0,
26 | 0.5,
27 | -0.5
28 | ],
29 | [
30 | 0.0,
31 | -0.5,
32 | -0.5
33 | ],
34 | [
35 | 0.0,
36 | -0.5,
37 | 0.5
38 | ]
39 | ],
40 | "transform": "square"
41 | }
42 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/squiggle_circle.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | -2,
5 | -1,
6 | 0,
7 | 1,
8 | 2,
9 | 3,
10 | 4,
11 | 5,
12 | 6,
13 | 7,
14 | 8,
15 | 9,
16 | 10
17 | ],
18 | "degree": 3,
19 | "form": 2,
20 | "color": null,
21 | "cvs": [
22 | [
23 | -0.29999999999999993,
24 | 0.7836116248912238,
25 | -0.783611624891225
26 | ],
27 | [
28 | 0.3,
29 | 1.108194187554388,
30 | 1.2643170607829326e-16
31 | ],
32 | [
33 | -0.30000000000000004,
34 | 0.7836116248912243,
35 | 0.7836116248912243
36 | ],
37 | [
38 | 0.29999999999999993,
39 | 3.21126950723723e-16,
40 | 1.108194187554388
41 | ],
42 | [
43 | -0.30000000000000004,
44 | -0.783611624891224,
45 | 0.7836116248912245
46 | ],
47 | [
48 | 0.3,
49 | -1.1081941875543881,
50 | 3.3392053635905195e-16
51 | ],
52 | [
53 | -0.29999999999999993,
54 | -0.7836116248912244,
55 | -0.7836116248912238
56 | ],
57 | [
58 | 0.30000000000000004,
59 | -5.952132599280585e-16,
60 | -1.108194187554388
61 | ]
62 | ],
63 | "transform": "squiggle_circle"
64 | }
65 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/star.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9,
14 | 10
15 | ],
16 | "degree": 1,
17 | "form": 0,
18 | "color": null,
19 | "cvs": [
20 | [
21 | 0.0,
22 | -0.808685,
23 | 0.587544
24 | ],
25 | [
26 | 0.0,
27 | -0.117124,
28 | 0.362759
29 | ],
30 | [
31 | 0.0,
32 | 0.308727,
33 | 0.950163
34 | ],
35 | [
36 | 0.0,
37 | 0.308789,
38 | 0.224351
39 | ],
40 | [
41 | 0.0,
42 | 1.0,
43 | 0.0
44 | ],
45 | [
46 | 0.0,
47 | 0.308789,
48 | -0.2259
49 | ],
50 | [
51 | 0.0,
52 | 0.308789,
53 | -0.950355
54 | ],
55 | [
56 | 0.0,
57 | -0.117124,
58 | -0.366219
59 | ],
60 | [
61 | 0.0,
62 | -0.808685,
63 | -0.591155
64 | ],
65 | [
66 | 0.0,
67 | -0.381065,
68 | 0.0
69 | ],
70 | [
71 | 0.0,
72 | -0.808685,
73 | 0.587544
74 | ]
75 | ],
76 | "transform": "star"
77 | }
78 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/star_8.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9,
14 | 10,
15 | 11,
16 | 12,
17 | 13,
18 | 14,
19 | 15,
20 | 16
21 | ],
22 | "degree": 1,
23 | "form": 0,
24 | "color": null,
25 | "cvs": [
26 | [
27 | 0.0,
28 | 0.0,
29 | 0.99792
30 | ],
31 | [
32 | 0.0,
33 | 0.291405,
34 | 0.706516
35 | ],
36 | [
37 | 0.0,
38 | 0.706233,
39 | 0.706233
40 | ],
41 | [
42 | 0.0,
43 | 0.706233,
44 | 0.292213
45 | ],
46 | [
47 | 0.0,
48 | 0.99792,
49 | 0.0
50 | ],
51 | [
52 | 0.0,
53 | 0.706233,
54 | -0.291622
55 | ],
56 | [
57 | 0.0,
58 | 0.706233,
59 | -0.706233
60 | ],
61 | [
62 | 0.0,
63 | 0.291558,
64 | -0.706362
65 | ],
66 | [
67 | 0.0,
68 | 0.0,
69 | -0.99792
70 | ],
71 | [
72 | 0.0,
73 | -0.291292,
74 | -0.706362
75 | ],
76 | [
77 | 0.0,
78 | -0.706233,
79 | -0.706233
80 | ],
81 | [
82 | 0.0,
83 | -0.706233,
84 | -0.292591
85 | ],
86 | [
87 | 0.0,
88 | -0.99792,
89 | 0.0
90 | ],
91 | [
92 | 0.0,
93 | -0.706233,
94 | 0.291574
95 | ],
96 | [
97 | 0.0,
98 | -0.706233,
99 | 0.706233
100 | ],
101 | [
102 | 0.0,
103 | -0.291292,
104 | 0.706335
105 | ],
106 | [
107 | 0.0,
108 | 0.0,
109 | 0.99792
110 | ]
111 | ],
112 | "transform": "star_8"
113 | }
114 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/triangle.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3
8 | ],
9 | "degree": 1,
10 | "form": 0,
11 | "color": null,
12 | "cvs": [
13 | [
14 | 0.0,
15 | 0.0,
16 | 0.0
17 | ],
18 | [
19 | -1.0,
20 | 0.0,
21 | -2.0
22 | ],
23 | [
24 | 1.0,
25 | 0.0,
26 | -2.0
27 | ],
28 | [
29 | 0.0,
30 | 0.0,
31 | 0.0
32 | ]
33 | ],
34 | "transform": "triangle"
35 | }
36 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/controls/two_arrow_flat.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "knots": [
4 | 0,
5 | 1,
6 | 2,
7 | 3,
8 | 4,
9 | 5,
10 | 6,
11 | 7,
12 | 8,
13 | 9,
14 | 10
15 | ],
16 | "degree": 1,
17 | "form": 0,
18 | "color": null,
19 | "cvs": [
20 | [
21 | 0.5817809942183504,
22 | -7.301272741955022e-17,
23 | 0.19392699807289498
24 | ],
25 | [
26 | 0.5817809942183504,
27 | -7.301272741955022e-17,
28 | 0.38785399614551747
29 | ],
30 | [
31 | 0.9696349903639185,
32 | 5.8410181935640175e-16,
33 | -9.090084563734023e-14
34 | ],
35 | [
36 | 0.5817809942183504,
37 | -7.301272741955022e-17,
38 | -0.38785399614551747
39 | ],
40 | [
41 | 0.5817809942183504,
42 | -7.301272741955022e-17,
43 | -0.193926998072896
44 | ],
45 | [
46 | -0.5817809942183523,
47 | 7.301272741955022e-17,
48 | -0.193926998072896
49 | ],
50 | [
51 | -0.5817809942183523,
52 | 7.301272741955022e-17,
53 | -0.38785399614551747
54 | ],
55 | [
56 | -0.9696349903639185,
57 | 1.0221781838737028e-15,
58 | -9.090084563734023e-14
59 | ],
60 | [
61 | -0.5817809942183523,
62 | 7.301272741955022e-17,
63 | 0.38785399614551747
64 | ],
65 | [
66 | -0.5817809942183523,
67 | 7.301272741955022e-17,
68 | 0.19392699807289498
69 | ],
70 | [
71 | 0.5817809942183504,
72 | -7.301272741955022e-17,
73 | 0.19392699807289498
74 | ]
75 | ],
76 | "transform": "two_arrow_flat"
77 | }
78 | ]
--------------------------------------------------------------------------------
/scripts/cmt/rig/face/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/rig/face/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/rig/meshretarget.py:
--------------------------------------------------------------------------------
1 | """Retarget meshes fit on a source mesh to a modified version of the source mesh.
2 |
3 | Most of this was taken from http://mathlab.github.io/PyGeM/_modules/pygem/radial.html#RBF
4 |
5 | Example Usage
6 | =============
7 |
8 | retarget("source_body", "new_body", ["shirt", "pants"], rbf=RBF.linear)
9 |
10 | """
11 | import math
12 | import time
13 | import numpy as np
14 | from scipy.spatial.distance import cdist
15 |
16 | import maya.api.OpenMaya as OpenMaya
17 | import maya.cmds as cmds
18 | import cmt.shortcuts as shortcuts
19 |
20 |
21 | def retarget(source, target, shapes, rbf=None, radius=0.5, stride=1):
22 | """Run the mesh retarget.
23 |
24 | :param source: Source mesh
25 | :param target: Modified source mesh
26 | :param shapes: List of meshes to retarget
27 | :param rbf: One of the RBF functions. See class RBF
28 | :param radius: Smoothing parameter for the rbf
29 | :param stride: Vertex stride to sample on the source mesh. Increase to speed up
30 | the calculation but less accurate.
31 | """
32 | start_time = time.time()
33 | source_points = points_to_np_array(source, stride)
34 | target_points = points_to_np_array(target, stride)
35 |
36 | if rbf is None:
37 | rbf = RBF.linear
38 | weights = get_weight_matrix(source_points, target_points, rbf, radius)
39 |
40 | for shape in shapes:
41 | points = points_to_np_array(shape)
42 | n_points = points.shape[0]
43 | dist = get_distance_matrix(points, source_points, rbf, radius)
44 | identity = np.ones((n_points, 1))
45 | h = np.bmat([[dist, identity, points]])
46 | deformed = np.asarray(np.dot(h, weights))
47 | points = [OpenMaya.MPoint(*p) for p in deformed]
48 | dupe = cmds.duplicate(
49 | shape, name="{}_{}_{}".format(shape, radius, rbf.__name__)
50 | )[0]
51 | set_points(dupe, points)
52 |
53 | end_time = time.time()
54 | print("Transferred in {} seconds".format(end_time - start_time))
55 |
56 |
57 | def points_to_np_array(mesh, stride=1):
58 | points = get_points(mesh)
59 | sparse_points = [OpenMaya.MPoint(p) for p in points][::stride]
60 | np_points = np.array([[p.x, p.y, p.z] for p in sparse_points])
61 | return np_points
62 |
63 |
64 | def get_points(mesh):
65 | path = shortcuts.get_dag_path2(shortcuts.get_shape(mesh))
66 | mesh_fn = OpenMaya.MFnMesh(path)
67 | return mesh_fn.getPoints()
68 |
69 |
70 | def get_weight_matrix(sp, tp, rbf, radius):
71 | """Get the weight matrix x in Ax=B
72 |
73 | :param sp: Source control point array
74 | :param tp: Target control point aray
75 | :param rbf: Rbf function from class RBF
76 | :param radius: Smoothing parameter
77 |
78 | :return: Weight matrix
79 | """
80 | identity = np.ones((sp.shape[0], 1))
81 | dist = get_distance_matrix(sp, sp, rbf, radius)
82 | # Solve x for Ax=B
83 | dim = 3
84 | a = np.bmat(
85 | [
86 | [dist, identity, sp],
87 | [identity.T, np.zeros((1, 1)), np.zeros((1, dim))],
88 | [sp.T, np.zeros((dim, 1)), np.zeros((dim, dim))],
89 | ]
90 | )
91 | b = np.bmat([[tp], [np.zeros((1, dim))], [np.zeros((dim, dim))]])
92 | weights = np.linalg.solve(a, b)
93 | return weights
94 |
95 |
96 | def get_distance_matrix(v1, v2, rbf, radius):
97 | matrix = cdist(v1, v2, "euclidean")
98 | if rbf != RBF.linear:
99 | matrix = rbf(matrix, radius)
100 | return matrix
101 |
102 |
103 | def set_points(mesh, points):
104 | path = shortcuts.get_dag_path2(shortcuts.get_shape(mesh))
105 | mesh_fn = OpenMaya.MFnMesh(path)
106 | mesh_fn.setPoints(points)
107 |
108 |
109 | class RBF(object):
110 | """Various RBF kernels"""
111 |
112 | @classmethod
113 | def linear(cls, matrix, radius):
114 | return matrix
115 |
116 | @classmethod
117 | def gaussian(cls, matrix, radius):
118 | result = np.exp(-(matrix * matrix) / (radius * radius))
119 | return result
120 |
121 | @classmethod
122 | def thin_plate(cls, matrix, radius):
123 | result = matrix / radius
124 | result *= matrix
125 |
126 | np.warnings.filterwarnings("ignore")
127 | result = np.where(result > 0, np.log(result), result)
128 | np.warnings.filterwarnings("always")
129 |
130 | return result
131 |
132 | @classmethod
133 | def multi_quadratic_biharmonic(cls, matrix, radius):
134 | result = np.sqrt((matrix * matrix) + (radius * radius))
135 | return result
136 |
137 | @classmethod
138 | def inv_multi_quadratic_biharmonic(cls, matrix, radius):
139 | result = 1.0 / (np.sqrt((matrix * matrix) + (radius * radius)))
140 | return result
141 |
142 | @classmethod
143 | def beckert_wendland_c2_basis(cls, matrix, radius):
144 | arg = matrix / radius
145 | first = np.zeros(matrix.shape)
146 | first = np.where(1 - arg > 0, np.power(1 - arg, 4), first)
147 | second = (4 * arg) + 1
148 | result = first * second
149 | return result
150 |
--------------------------------------------------------------------------------
/scripts/cmt/rig/spaceswitch.py:
--------------------------------------------------------------------------------
1 | """Space switching without constraints or extra DAG nodes.
2 |
3 | Contains functions to create a space switching network as well as seamlessly switching
4 | between spaces.
5 |
6 | Example Usage
7 | =============
8 |
9 | ::
10 |
11 | import cmt.rig.spaceswitch as spaceswitch
12 |
13 | # Create the space switch
14 | spaceswitch.create_space_switch(
15 | pole_vector_control,
16 | [(ik_control, "foot"), (root_control, "root"), (world_control, "world")],
17 | switch_attribute="space",
18 | use_rotate=False,
19 | )
20 |
21 | # Seamless switch
22 | spaceswitch.switch_space(pole_vector_control, "space", 1, create_keys=False)
23 |
24 | """
25 | import maya.cmds as cmds
26 | import maya.api.OpenMaya as OpenMaya
27 | from cmt.dge import dge
28 | import cmt.rig.common as common
29 | import cmt.shortcuts as shortcuts
30 |
31 |
32 | def create_space_switch(
33 | node, drivers, switch_attribute=None, use_translate=True, use_rotate=True
34 | ):
35 | """Creates a space switch network.
36 |
37 | The network uses the offsetParentMatrix attribute and does not create any
38 | constraints or new dag nodes.
39 |
40 | :param node: Transform to drive
41 | :param drivers: List of tuples: [(driver1, "spaceName1"), (driver2, "spaceName2")]
42 | :param switch_attribute: Name of the switch attribute to create on the target node.
43 | """
44 | if switch_attribute is None:
45 | switch_attribute = "space"
46 |
47 | if cmds.objExists("{}.{}".format(node, switch_attribute)):
48 | cmds.deleteAttr(node, at=switch_attribute)
49 | names = [d[1] for d in drivers]
50 | cmds.addAttr(node, ln=switch_attribute, at="enum", en=":".join(names), keyable=True)
51 |
52 | # Create attribute to toggle translation in the matrices
53 | enable_translate_attr = _create_bool_attribute(
54 | node, "{}UseTranslate".format(switch_attribute), use_translate
55 | )
56 |
57 | # Create attribute to toggle rotation in the matrices
58 | enable_rotate_attr = _create_bool_attribute(
59 | node, "{}UseRotate".format(switch_attribute), use_rotate
60 | )
61 |
62 | blend = cmds.createNode("blendMatrix", name="{}_spaceswitch".format(node))
63 |
64 | # Get the current offset parent matrix. This is used as the starting blend point
65 | m = OpenMaya.MMatrix(cmds.getAttr("{}.offsetParentMatrix".format(node)))
66 | cmds.setAttr("{}.inputMatrix".format(blend), list(m), type="matrix")
67 |
68 | parent = cmds.listRelatives(node, parent=True, path=True)
69 | to_parent_local = "{}.worldInverseMatrix[0]".format(parent[0]) if parent else None
70 |
71 | for i, driver in enumerate(drivers):
72 | driver = driver[0]
73 |
74 | _connect_driver_matrix_network(blend, node, driver, i, to_parent_local)
75 |
76 | target_attr = "{}.target[{}]".format(blend, i)
77 |
78 | # Hook up the weight toggle when switching spaces
79 | dge(
80 | "x = switch == {} ? 1 : 0".format(i),
81 | x="{}.weight".format(target_attr),
82 | switch="{}.{}".format(node, switch_attribute),
83 | )
84 |
85 | # Connect the translation, rotation toggles
86 | cmds.connectAttr(enable_translate_attr, "{}.useTranslate".format(target_attr))
87 | cmds.connectAttr(enable_rotate_attr, "{}.useRotate".format(target_attr, i))
88 |
89 | cmds.connectAttr(
90 | "{}.outputMatrix".format(blend), "{}.offsetParentMatrix".format(node)
91 | )
92 |
93 |
94 | def _create_bool_attribute(node, attribute, default_value):
95 | cmds.addAttr(
96 | node, ln=attribute, at="bool", defaultValue=default_value, keyable=True
97 | )
98 | return "{}.{}".format(node, attribute)
99 |
100 |
101 | def _connect_driver_matrix_network(blend, node, driver, index, to_parent_local):
102 | # The multMatrix node will calculate the transformation to blend to when driven
103 | # by this driver transform
104 | mult = cmds.createNode(
105 | "multMatrix", name="spaceswitch_{}_to_{}".format(node, driver)
106 | )
107 |
108 | offset = (
109 | shortcuts.get_dag_path2(node).exclusiveMatrix()
110 | * OpenMaya.MMatrix(cmds.getAttr("{}.worldInverseMatrix[0]".format(driver)))
111 | )
112 | cmds.setAttr("{}.matrixIn[0]".format(mult), list(offset), type="matrix")
113 |
114 | cmds.connectAttr("{}.worldMatrix[0]".format(driver), "{}.matrixIn[1]".format(mult))
115 |
116 | if to_parent_local:
117 | cmds.connectAttr(to_parent_local, "{}.matrixIn[2]".format(mult))
118 |
119 | cmds.connectAttr(
120 | "{}.matrixSum".format(mult), "{}.target[{}].targetMatrix".format(blend, index)
121 | )
122 |
123 |
124 | def switch_space(node, attribute, space, create_keys=False):
125 | """Seamlessly switch between spaces
126 |
127 | :param node: Node to switch
128 | :param attribute: Space switching attribute on node
129 | :param space: Space index in the space attribute
130 | :param create_keys: True to create switching keys
131 | """
132 | m = cmds.xform(node, q=True, ws=True, m=True)
133 | cmds.setAttr("{}.{}".format(node, attribute), space)
134 | cmds.xform(node, ws=True, m=m)
135 |
--------------------------------------------------------------------------------
/scripts/cmt/rig/splineik.py:
--------------------------------------------------------------------------------
1 | import maya.cmds as cmds
2 | import cmt.shortcuts as shortcuts
3 |
4 |
5 | def create_spine(start_joint, end_joint, lower_control, upper_control, name="spine"):
6 | spline_chain, original_chain = shortcuts.duplicate_chain(
7 | start_joint, end_joint, prefix="ikSpine_"
8 | )
9 |
10 | # Create the spline ik
11 | ikh, effector, curve = cmds.ikHandle(
12 | name="{0}_ikh".format(name),
13 | solver="ikSplineSolver",
14 | startJoint=spline_chain[0],
15 | endEffector=spline_chain[-1],
16 | parentCurve=False,
17 | simplifyCurve=False,
18 | )
19 | effector = cmds.rename(effector, "{0}_eff".format(name))
20 | curve = cmds.rename(curve, "{0}_crv".format(name))
21 |
22 | # Create the joints to skin the curve
23 | curve_start_joint = cmds.duplicate(
24 | start_joint, parentOnly=True, name="{0}CurveStart_jnt".format(name)
25 | )
26 | cmds.parent(curve_start_joint, lower_control)
27 | curve_end_joint = cmds.duplicate(
28 | end_joint, parentOnly=True, name="{0}CurveEnd_jnt".format(name)
29 | )
30 | cmds.parent(curve_end_joint, upper_control)
31 |
32 | # Skin curve
33 | cmds.skinCluster(
34 | curve_start_joint, curve_end_joint, curve, name="{0}_scl".format(name), tsb=True
35 | )
36 |
37 | # Create stretch network
38 | curve_info = cmds.arclen(curve, constructionHistory=True)
39 | mdn = cmds.createNode("multiplyDivide", name="{0}Stretch_mdn".format(name))
40 | cmds.connectAttr("{0}.arcLength".format(curve_info), "{0}.input1X".format(mdn))
41 | cmds.setAttr(
42 | "{0}.input2X".format(mdn), cmds.getAttr("{0}.arcLength".format(curve_info))
43 | )
44 | cmds.setAttr("{0}.operation".format(mdn), 2) # Divide
45 |
46 | # Connect to joints
47 | for joint in spline_chain[1:]:
48 | tx = cmds.getAttr("{0}.translateX".format(joint))
49 | mdl = cmds.createNode("multDoubleLinear", name="{0}Stretch_mdl".format(joint))
50 | cmds.setAttr("{0}.input1".format(mdl), tx)
51 | cmds.connectAttr("{0}.outputX".format(mdn), "{0}.input2".format(mdl))
52 | cmds.connectAttr("{0}.output".format(mdl), "{0}.translateX".format(joint))
53 |
54 | # Setup advanced twist
55 | cmds.setAttr("{0}.dTwistControlEnable".format(ikh), True)
56 | cmds.setAttr("{0}.dWorldUpType".format(ikh), 4) # Object up
57 | cmds.setAttr("{0}.dWorldUpAxis".format(ikh), 0) # Positive Y Up
58 | cmds.setAttr("{0}.dWorldUpVectorX".format(ikh), 0)
59 | cmds.setAttr("{0}.dWorldUpVectorY".format(ikh), 1)
60 | cmds.setAttr("{0}.dWorldUpVectorZ".format(ikh), 0)
61 | cmds.setAttr("{0}.dWorldUpVectorEndX".format(ikh), 0)
62 | cmds.setAttr("{0}.dWorldUpVectorEndY".format(ikh), 1)
63 | cmds.setAttr("{0}.dWorldUpVectorEndZ".format(ikh), 0)
64 | cmds.connectAttr(
65 | "{0}.worldMatrix[0]".format(lower_control), "{0}.dWorldUpMatrix".format(ikh)
66 | )
67 | cmds.connectAttr(
68 | "{0}.worldMatrix[0]".format(upper_control), "{0}.dWorldUpMatrixEnd".format(ikh)
69 | )
70 |
71 | # Constrain original chain back to spline chain
72 | for ik_joint, joint in zip(spline_chain, original_chain):
73 | if joint == end_joint:
74 | cmds.pointConstraint(ik_joint, joint, mo=True)
75 | cmds.orientConstraint(upper_control, joint, mo=True)
76 | else:
77 | cmds.parentConstraint(ik_joint, joint)
78 |
--------------------------------------------------------------------------------
/scripts/cmt/rig/transformstack.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 | from __future__ import division
3 | from __future__ import print_function
4 |
5 | import logging
6 | import os
7 | import re
8 |
9 | import maya.cmds as cmds
10 |
11 | # The message attribute specifying which nodes are part of a transform stack.
12 | STACK_ATTRIBUTE = "cmt_transformStack"
13 |
14 | logger = logging.getLogger(__name__)
15 |
16 |
17 | def create_transform_stack(node, suffixes=None):
18 | """Creates a transform stack above the given node.
19 |
20 | Any previous transform stack will be deleted.
21 |
22 | :param node: Node to parent into a transform stack.
23 | :param suffixes: List of suffixes to add to the created transforms
24 | :return: A list of the transform nodes created starting from top to bottom.
25 | """
26 | previous_parent = get_stack_parent(node)
27 | delete_stack(node)
28 |
29 | stack_transforms = []
30 | for i, suffix in enumerate(suffixes):
31 | name = "{}{}".format(node, suffix)
32 | transform = cmds.createNode("transform", name=name)
33 | stack_transforms.append(transform)
34 | cmds.addAttr(transform, ln=STACK_ATTRIBUTE, at="message")
35 | cmds.connectAttr(
36 | "{}.message".format(node), "{}.{}".format(transform, STACK_ATTRIBUTE)
37 | )
38 | cmds.delete(cmds.parentConstraint(node, transform))
39 | if previous_parent:
40 | cmds.parent(transform, previous_parent)
41 | previous_parent = transform
42 | cmds.parent(node, previous_parent)
43 | stack_transforms.append(node)
44 | logger.info("Created transform stack {}".format("|".join(stack_transforms)))
45 | return stack_transforms
46 |
47 |
48 | def delete_stack(node):
49 | """Delete the transforms of the stack.
50 |
51 | :param node: Stack leaf.
52 | """
53 | stack = get_stack(node)
54 | if len(stack) <= 1:
55 | return
56 | parent = get_stack_parent(node)
57 | if parent:
58 | cmds.parent(node, parent)
59 | else:
60 | cmds.parent(node, world=True)
61 | cmds.delete(stack[:-1])
62 |
63 |
64 | def get_stack(node):
65 | """Get the transforms in the transform stack
66 |
67 | :param node: Stack leaf transform
68 | :return: List of transforms
69 | """
70 | stack = [node]
71 | parent = cmds.listRelatives(node, parent=True, path=True)
72 | if parent:
73 | parent = parent[0]
74 | while _is_transform_stack_node(parent):
75 | stack.insert(0, parent)
76 | parent = cmds.listRelatives(parent, parent=True, path=True)
77 | if parent:
78 | parent = parent[0]
79 | return stack
80 |
81 |
82 | def _is_transform_stack_node(node):
83 | """Tests if the given node is part of a transform stack.
84 |
85 | :param node: Node to test.
86 | :return: True or False
87 | """
88 | if not node:
89 | return False
90 | return cmds.objExists("{}.{}".format(node, STACK_ATTRIBUTE))
91 |
92 |
93 | def get_stack_count(node):
94 | """Get the number of transforms in the stack.
95 |
96 | :param node: Node to query.
97 | :return: The number of transforms in the stack.
98 | """
99 | return len(get_stack(node))
100 |
101 |
102 | def get_stack_parent(node):
103 | """Get the parent of the transform stack belonging to the given node.
104 |
105 | :param node: Node to query.
106 | :return: The parent node or None if there is no parent.
107 | """
108 | stack = get_stack(node)
109 | parent = cmds.listRelatives(stack[0], parent=True, path=True)
110 | return parent[0] if parent else None
111 |
--------------------------------------------------------------------------------
/scripts/cmt/settings.py:
--------------------------------------------------------------------------------
1 | DOCUMENTATION_ROOT = "https://chadmv.github.io/cmt/html"
2 |
3 | ENABLE_PLUGINS = True
4 |
--------------------------------------------------------------------------------
/scripts/cmt/test/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | CMT Unit Test framework.
3 | """
4 | from cmt.test.mayaunittest import TestCase
5 |
6 | __all__ = ["TestCase", "run_tests"]
7 |
--------------------------------------------------------------------------------
/scripts/cmt/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/ui/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/ui/optionbox.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 | from __future__ import division
3 | from __future__ import print_function
4 |
5 | import maya.cmds as cmds
6 | import maya.mel as mel
7 |
8 |
9 | class OptionBox(object):
10 | """Class that wraps Maya's option box functionality.
11 |
12 | Maya's menu option box functionality is a bit convoluted and not well documented
13 | so this class can be used to simplify working with the option box.
14 |
15 | Users can derive from this class and implement the following four methods:
16 |
17 | * create_ui - Create any UI elements to display in the option box.
18 | * on_apply - Implement what should happen when the user hits Apply.
19 | * on_reset - Reset all your widgets to their default or saved values.
20 | * on_save - Save all the widget settings to optionVar or QSettings
21 |
22 | See cmt.rig.twistdecomposition.Options for a sample implementation.
23 | """
24 |
25 | def __init__(self, title, help_url=None):
26 | layout = mel.eval("getOptionBox")
27 | cmds.setParent(layout)
28 | mel.eval('setOptionBoxTitle("{}");'.format(title))
29 | self.create_ui()
30 |
31 | apply_close_button = mel.eval("getOptionBoxApplyAndCloseBtn;")
32 | cmds.button(apply_close_button, e=True, command=self._apply_and_close)
33 | apply_button = mel.eval("getOptionBoxApplyBtn;")
34 | cmds.button(apply_button, e=True, command=self._on_apply)
35 | close_button = mel.eval("getOptionBoxCloseBtn;")
36 | cmds.button(close_button, e=True, command=self._close)
37 |
38 | if help_url:
39 | help_item = mel.eval("getOptionBoxHelpItem;")
40 | cmds.menuItem(
41 | help_item,
42 | e=True,
43 | label="Help on {}".format(title),
44 | command='import webbrowser; webbrowser.open("{}")'.format(help_url),
45 | )
46 |
47 | def show(self):
48 | mel.eval("showOptionBox")
49 | # In getOptionBox.mel showOptionBox, it sets the Reset and Save menu item
50 | # commands in MEL so they expect MEL code. We want Python so override the
51 | # commands after showing the option box in order to use Python
52 | reset_item = mel.eval("$tmp = $gOptionBoxEditMenuResetItem")
53 | cmds.menuItem(reset_item, e=True, command=self._on_reset)
54 | save_item = mel.eval("$tmp = $gOptionBoxEditMenuSaveItem")
55 | cmds.menuItem(save_item, e=True, command=self._on_save)
56 |
57 | def create_ui(self):
58 | raise NotImplementedError("OptionBox.create_ui not implemented")
59 |
60 | def _on_apply(self, *args):
61 | """Call back called when the Apply button is pressed.
62 |
63 | The only reason this method exists is so the derived on_apply doesn't have to
64 | have any args.
65 |
66 | :param args: Callback args.
67 | """
68 | self.on_apply()
69 |
70 | def on_apply(self):
71 | raise NotImplementedError("OptionBox.on_apply not implemented")
72 |
73 | def _on_reset(self, *args):
74 | """Call back called when the Reset settings menu item is pressed.
75 |
76 | The only reason this method exists is so the derived on_reset doesn't have to
77 | have any args.
78 |
79 | :param args: Callback args.
80 | """
81 | self.on_reset()
82 |
83 | def on_reset(self):
84 | raise NotImplementedError("OptionBox.on_reset not implemented")
85 |
86 | def _on_save(self, *args):
87 | """Call back called when the Save settings menu item is pressed.
88 |
89 | The only reason this method exists is so the derived on_save doesn't have to
90 | have any args.
91 |
92 | :param args: Callback args.
93 | """
94 | self.on_save()
95 |
96 | def on_save(self):
97 | raise NotImplementedError("OptionBox.on_save not implemented")
98 |
99 | def _apply_and_close(self, *args, **kwargs):
100 | """Create the twist decomposition and close the option box."""
101 | self.on_apply()
102 | mel.eval("saveOptionBoxSize")
103 | self._close()
104 |
105 | def _close(self, *args, **kwargs):
106 | mel.eval("hideOptionBox")
107 |
--------------------------------------------------------------------------------
/scripts/cmt/ui/stringcache.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from PySide2.QtCore import QStringListModel
4 |
5 | from cmt import shortcuts as shortcuts
6 |
7 |
8 | class StringCache(QStringListModel):
9 | """A QStringListModel that saves its values in a persistent cache."""
10 |
11 | def __init__(self, name, max_values=10, parent=None):
12 | """Constructor
13 |
14 | :param name: Name used to query persistent data
15 | :param max_values: Maximum number of values to store in the cache
16 | :param parent: QWidget parent
17 | """
18 | super(StringCache, self).__init__(parent)
19 | self._name = name
20 | self.max_values = max_values
21 | data = shortcuts.get_setting(self._name)
22 | if data:
23 | data = json.loads(data)
24 | self.setStringList(data)
25 |
26 | def push(self, value):
27 | """Push a new value onto the cache stack.
28 |
29 | :param value: New value.
30 | """
31 | values = self.stringList()
32 | if value in values:
33 | values.remove(value)
34 | values.insert(0, value)
35 | if len(values) > self.max_values:
36 | values = values[: self.max_values]
37 | self.setStringList(values)
38 | self._save()
39 |
40 | def _save(self):
41 | """Saves the string list to the persistent cache."""
42 | shortcuts.set_setting(self._name, json.dumps(self.stringList()))
--------------------------------------------------------------------------------
/scripts/cmt/ui/widgets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/ui/widgets/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/ui/widgets/filepathwidget.py:
--------------------------------------------------------------------------------
1 | """A widget to select a file path.
2 |
3 | The widget stores previously selected paths in QSettings
4 |
5 | Example
6 | -------
7 | def func(t):
8 | print(t)
9 |
10 | from cmt.widgets.filepathwidget import FilePathWidget
11 | widget = FilePathWidget(label='My File',
12 | file_mode=FilePathWidget.existing_file,
13 | name='unique_name',
14 | file_filter='Python Files (*.py)')
15 | widget.path_changed.connect(func)
16 | widget.show()
17 | """
18 |
19 | from __future__ import absolute_import
20 | from __future__ import division
21 | from __future__ import print_function
22 |
23 | import os
24 |
25 | from PySide2.QtCore import Signal
26 | from PySide2.QtWidgets import (
27 | QWidget,
28 | QHBoxLayout,
29 | QLabel,
30 | QComboBox,
31 | QSizePolicy,
32 | QPushButton,
33 | QDialog,
34 | QFileDialog,
35 | )
36 |
37 | from cmt.ui.stringcache import StringCache
38 |
39 |
40 | class FilePathWidget(QWidget):
41 | """Widget allowing file path selection with a persistent cache.
42 |
43 | Users should connect to the path_changed signal.
44 | """
45 |
46 | any_file = 0
47 | existing_file = 1
48 | directory = 2
49 | path_changed = Signal(str)
50 |
51 | def __init__(
52 | self, label=None, file_mode=any_file, file_filter=None, name=None, parent=None
53 | ):
54 | """Constructor
55 |
56 | :param label: Optional label text.
57 | :param file_mode: Sets the file dialog mode. One of
58 | FilePathWidget.[any_file|existing_file|directory].
59 | :param file_filter: File filter text example 'Python Files (*.py)'.
60 | :param name: Unique name used to query persistent data.
61 | :param parent: Parent QWidget.
62 | """
63 | super(FilePathWidget, self).__init__(parent)
64 | self.file_mode = file_mode
65 | if file_filter is None:
66 | file_filter = "Any File (*)"
67 | self.file_filter = file_filter
68 | self.cache = StringCache("cmt.filepathwidget.{}".format(name), parent=self)
69 | self._layout = QHBoxLayout(self)
70 | self._layout.setContentsMargins(0, 0, 0, 0)
71 | self.setLayout(self._layout)
72 |
73 | if label:
74 | label = QLabel(label, self)
75 | label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
76 | self._layout.addWidget(label)
77 |
78 | self._combo_box = QComboBox(self)
79 | self._combo_box.setEditable(True)
80 | self._combo_box.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
81 | self._combo_box.setInsertPolicy(QComboBox.InsertAtTop)
82 | self._combo_box.setMinimumWidth(50)
83 | self._combo_box.setModel(self.cache)
84 | self._combo_box.editTextChanged.connect(self.edit_changed)
85 | self._layout.addWidget(self._combo_box)
86 |
87 | button = QPushButton("Browse", self)
88 | button.released.connect(self.show_dialog)
89 | button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
90 | self._layout.addWidget(button)
91 |
92 | @property
93 | def path(self):
94 | return self._combo_box.currentText()
95 |
96 | @path.setter
97 | def path(self, value):
98 | self._combo_box.setEditText(value)
99 |
100 | def edit_changed(self, text):
101 | """Slot called whenever the text changes in the combobox.
102 |
103 | :param text: New text.
104 | """
105 | if not text:
106 | return
107 | text = text.replace("\\", "/")
108 | if (os.path.isfile(text) and self.file_mode != FilePathWidget.directory) or (
109 | os.path.isdir(text) and self.file_mode == FilePathWidget.directory
110 | ):
111 | self.path_changed.emit(text)
112 | self._combo_box.blockSignals(True)
113 | self._push(text)
114 | self._combo_box.blockSignals(False)
115 |
116 | def show_dialog(self):
117 | """Show the file browser dialog."""
118 | dialog = QFileDialog(self)
119 | dialog.setNameFilter(self.file_filter)
120 | file_mode = [
121 | QFileDialog.AnyFile,
122 | QFileDialog.ExistingFile,
123 | QFileDialog.Directory,
124 | ][self.file_mode]
125 | dialog.setFileMode(file_mode)
126 | dialog.setModal(True)
127 | if self.cache:
128 | dialog.setHistory(self.cache.stringList())
129 |
130 | for value in self.cache.stringList():
131 | if os.path.exists(value):
132 | if os.path.isfile(value):
133 | directory = os.path.dirname(value)
134 | dialog.selectFile(value)
135 | else:
136 | directory = value
137 | dialog.setDirectory(directory)
138 | break
139 | if dialog.exec_() == QDialog.Accepted:
140 | path = dialog.selectedFiles()
141 | if path:
142 | self._push(path[0])
143 |
144 | def _push(self, path):
145 | """Push a new path onto the cache.
146 |
147 | :param path: Path value.
148 | """
149 | self.cache.push(path)
150 | self._combo_box.setCurrentIndex(0)
151 |
--------------------------------------------------------------------------------
/scripts/cmt/ui/widgets/mayanodewidget.py:
--------------------------------------------------------------------------------
1 | """A widget to select a file path.
2 |
3 | The widget stores previously selected paths in QSettings
4 |
5 | Example
6 | -------
7 | def func(t):
8 | print(t)
9 |
10 | from cmt.widgets.filepathwidget import FilePathWidget
11 | widget = FilePathWidget(label='My File',
12 | file_mode=FilePathWidget.existing_file,
13 | name='unique_name',
14 | file_filter='Python Files (*.py)')
15 | widget.path_changed.connect(func)
16 | widget.show()
17 | """
18 |
19 | from __future__ import absolute_import
20 | from __future__ import print_function
21 |
22 | import os
23 |
24 | from PySide2.QtCore import Signal
25 | from PySide2.QtWidgets import (
26 | QWidget,
27 | QHBoxLayout,
28 | QLabel,
29 | QComboBox,
30 | QSizePolicy,
31 | QPushButton,
32 | )
33 |
34 | import maya.cmds as cmds
35 |
36 | import cmt.shortcuts as shortcuts
37 | from cmt.ui.stringcache import StringCache
38 |
39 |
40 | class MayaNodeWidget(QWidget):
41 | """Widget allowing Maya node selection with a persistent cache.
42 |
43 | Users should connect to the node_changed signal.
44 | """
45 |
46 | node_changed = Signal(str)
47 |
48 | def __init__(self, label=None, name=None, parent=None):
49 | """Constructor
50 |
51 | :param label: Optional label text.
52 | :param name: Unique name used to query persistent data.
53 | :param parent: Parent QWidget.
54 | """
55 | super(MayaNodeWidget, self).__init__(parent)
56 | self.cache = StringCache("cmt.mayanodewidget.{}".format(name), parent=self)
57 | self._layout = QHBoxLayout(self)
58 | self._layout.setContentsMargins(0, 0, 0, 0)
59 | self.setLayout(self._layout)
60 |
61 | if label:
62 | label = QLabel(label, self)
63 | label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
64 | self._layout.addWidget(label)
65 |
66 | self._combo_box = QComboBox(self)
67 | self._combo_box.setEditable(True)
68 | self._combo_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
69 | self._combo_box.setInsertPolicy(QComboBox.InsertAtTop)
70 | self._combo_box.setModel(self.cache)
71 | self._combo_box.editTextChanged.connect(self.edit_changed)
72 | self._layout.addWidget(self._combo_box)
73 |
74 | button = QPushButton("<", self)
75 | button.released.connect(self.use_selected)
76 | button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
77 | self._layout.addWidget(button)
78 |
79 | @property
80 | def node(self):
81 | return self._combo_box.currentText()
82 |
83 | @node.setter
84 | def node(self, value):
85 | self._combo_box.setEditText(value)
86 |
87 | def edit_changed(self, text):
88 | """Slot called whenever the text changes in the combobox.
89 |
90 | :param text: New text.
91 | """
92 | if not text:
93 | return
94 | if cmds.objExists(text):
95 | self.node_changed.emit(text)
96 | self._combo_box.blockSignals(True)
97 | self._push(text)
98 | self._combo_box.blockSignals(False)
99 |
100 | def use_selected(self):
101 | """Populate the combobox with the name of the selected node."""
102 | selected = cmds.ls(sl=True)
103 | if selected:
104 | self._push(selected[0])
105 |
106 | def _push(self, node):
107 | """Push a new node onto the cache.
108 |
109 | :param path: Node name.
110 | """
111 | self.cache.push(node)
112 | self._combo_box.setCurrentIndex(0)
113 |
--------------------------------------------------------------------------------
/scripts/cmt/ui/widgets/outputconsole.py:
--------------------------------------------------------------------------------
1 | """A colored output console.
2 |
3 | Example
4 | -------
5 | from cmt.ui.widgets.outputconsole import OutputConsole
6 | widget = OutputConsole()
7 | widget.add_color("^Error", 217, 83, 79)
8 | widget.add_color("^Fail", 240, 173, 78)
9 | widget.add_color("^Success", 92, 184, 92)
10 | widget.show()
11 | widget.write("And now some text\n")
12 | widget.write("ERROR: This is an error\n")
13 | widget.write("FAIL: We have failed\n")
14 | widget.write("SUCCESS: We did it!\n")
15 | """
16 |
17 | import re
18 |
19 | from PySide2.QtGui import *
20 | from PySide2.QtCore import *
21 | from PySide2.QtWidgets import *
22 |
23 |
24 | class OutputConsole(QTextEdit):
25 | """Colored text output console."""
26 |
27 | normal_color = QColor(200, 200, 200)
28 |
29 | def __init__(self, parent=None):
30 | """Constructor
31 |
32 | :param parent: Parent QWidget.
33 | """
34 | super(OutputConsole, self).__init__(parent)
35 | self.setReadOnly(True)
36 | self.color_regex = {}
37 | self.setTextColor(OutputConsole.normal_color)
38 |
39 | def add_color(self, regex, r, g, b):
40 | """Add a regex with associated color.
41 |
42 | :param regex: Regular expression pattern
43 | :param r: Red 0-255
44 | :param g: Green 0-255
45 | :param b: Blue 0-255
46 | """
47 | regex = re.compile(regex, re.IGNORECASE)
48 | self.color_regex[regex] = QColor(r, g, b)
49 |
50 | def write(self, text):
51 | """Write text into the QTextEdit."""
52 | # Color the output if it matches any regex
53 | for regex, color in self.color_regex.items():
54 | if regex.search(text):
55 | self.setTextColor(color)
56 | break
57 | self.insertPlainText(text)
58 | self.setTextColor(OutputConsole.normal_color)
59 |
60 | def flush(self):
61 | """Required for stream purposes"""
62 | pass
63 |
--------------------------------------------------------------------------------
/scripts/cmt/utility/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chadmv/cmt/1b1a9a4fb154d1d10e73373cf899e4d83c95a6a1/scripts/cmt/utility/__init__.py
--------------------------------------------------------------------------------
/scripts/cmt/utility/timing.py:
--------------------------------------------------------------------------------
1 | """Contains a context manager class used to measure execution time of blocks of code
2 |
3 | Example Usage
4 | =============
5 |
6 | with Section("Mesh Processor", "Import files"):
7 | # Code to run
8 |
9 | with Section("Mesh Processor", "Process sata"):
10 | # Code to run
11 |
12 | with Section("Publish Asset", "Upload data"):
13 | # Code to run
14 |
15 | Section.print_timing()
16 |
17 | """
18 | import functools
19 | import time
20 | from collections import OrderedDict
21 |
22 | _workspaces = OrderedDict()
23 |
24 |
25 | class Section(object):
26 | @classmethod
27 | def clear(cls, workspace=None):
28 | """Clears the stored timing data.
29 |
30 | :param workspace: Optional workspace to clear. If omitted, all data is cleared.
31 | """
32 | global _workspaces
33 | if workspace:
34 | del _workspaces[workspace]
35 | else:
36 | _workspaces = OrderedDict()
37 |
38 | @classmethod
39 | def print_timing(cls):
40 | """Prints the existing timing data"""
41 | global _workspaces
42 | for workspace, tasks in _workspaces.items():
43 | total_time = sum(tasks.values())
44 | print("-- {}: {:.6f} seconds".format(workspace, total_time))
45 | for task, run_time in tasks.items():
46 | print(" - {}: {:.6f} seconds".format(task, run_time))
47 |
48 | def __init__(self, workspace, task):
49 | self.workspace = workspace
50 | self.task = task
51 |
52 | def __enter__(self):
53 | self.start_time = time.time()
54 |
55 | def __exit__(self, exc_type, exc_val, exc_tb):
56 | global _workspaces
57 | run_time = time.time() - self.start_time
58 | workspace = _workspaces.setdefault(self.workspace, OrderedDict())
59 | workspace[self.task] = run_time
60 |
61 |
62 | def timed(workspace, task):
63 | def decorator_timed(func):
64 | @functools.wraps(func)
65 | def wrapper_timed(*args, **kwargs):
66 | with Section(workspace, task):
67 | result = func(*args, **kwargs)
68 | return result
69 |
70 | return wrapper_timed
71 |
72 | return decorator_timed
73 |
--------------------------------------------------------------------------------
/scripts/pyparsing/LICENSE:
--------------------------------------------------------------------------------
1 | Permission is hereby granted, free of charge, to any person obtaining
2 | a copy of this software and associated documentation files (the
3 | "Software"), to deal in the Software without restriction, including
4 | without limitation the rights to use, copy, modify, merge, publish,
5 | distribute, sublicense, and/or sell copies of the Software, and to
6 | permit persons to whom the Software is furnished to do so, subject to
7 | the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be
10 | included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
16 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
17 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 |
--------------------------------------------------------------------------------
/scripts/userSetup.py:
--------------------------------------------------------------------------------
1 | import maya.utils
2 |
3 | maya.utils.executeDeferred("import cmt; cmt.initialize()")
4 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | configure_file(cmtConfig.h.in cmtConfig.h)
2 |
3 | set(SOURCE_FILES
4 | "pluginMain.cpp"
5 | "cmtConfig.h.in"
6 | "common.h"
7 | "common.cpp"
8 | "linearRegressionSolver.h"
9 | "linearRegressionSolver.cpp"
10 | "swingTwistNode.h"
11 | "swingTwistNode.cpp"
12 | "swingTwistCmd.h"
13 | "swingTwistCmd.cpp"
14 | "demBonesCmd.h"
15 | "demBonesCmd.cpp"
16 | "rbfNode.h"
17 | "rbfNode.cpp"
18 | "ikRigNode.h"
19 | "ikRigNode.cpp"
20 | )
21 |
22 | SET(DEMBONES_SOURCE
23 | "DemBones/ConvexLS.h"
24 | "DemBones/DemBones.h"
25 | "DemBones/DemBonesExt.h"
26 | "DemBones/Indexing.h"
27 | "DemBones/MatBlocks.h"
28 | )
29 | source_group(dembones FILES ${DEMBONES_SOURCE})
30 | find_package(OpenMP)
31 |
32 | if (OPENMP_FOUND)
33 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
34 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
35 | set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
36 | endif()
37 |
38 | # Eigen requires /bigobj to compile in DEBUG
39 | add_compile_options("$<$,$>:/bigobj>")
40 |
41 |
42 | find_package(Maya REQUIRED)
43 | find_package(Eigen3 REQUIRED)
44 |
45 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${DEMBONES_SOURCE})
46 |
47 | target_link_libraries(${PROJECT_NAME} PRIVATE Maya::Maya Eigen3::Eigen)
48 | target_include_directories(${PROJECT_NAME}
49 | PRIVATE Maya::Maya Eigen3::Eigen
50 | PUBLIC "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}"
51 | )
52 | MAYA_PLUGIN(${PROJECT_NAME})
53 |
54 | install(TARGETS ${PROJECT_NAME} ${MAYA_TARGET_TYPE} DESTINATION plug-ins/${MAYA_VERSION})
55 |
56 |
--------------------------------------------------------------------------------
/src/DemBones/ConvexLS.h:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // Dem Bones - Skinning Decomposition Library //
3 | // Copyright (c) 2019, Electronic Arts. All rights reserved. //
4 | ///////////////////////////////////////////////////////////////////////////////
5 |
6 |
7 |
8 | #ifndef DEM_BONES_CONVEX_LS
9 | #define DEM_BONES_CONVEX_LS
10 |
11 | #include
12 | #include
13 | #include "Indexing.h"
14 |
15 | namespace Dem
16 | {
17 |
18 | /** @class ConvexLS ConvexLS.h "DemBones/ConvexLS.h"
19 | @brief Linear least squares solver with non-negativity constraint and optional affinity constraint
20 | @details Solve:
21 | @f{eqnarray*}{
22 | min &||Ax-b||^2 \\
23 | \mbox{Subject to: } & x(0).. x(n-1) \geq 0, \\
24 | \mbox{(optional) } & x(0) +.. + x(n-1) = 1
25 | @f}
26 | The solver implements active set method to handle non-negativity constraint and QR decomposition to handle affinity constraint.
27 |
28 | @b _Scalar is the floating-point data type.
29 | */
30 | template
31 | class ConvexLS {
32 | public:
33 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW
34 | using MatrixX=Eigen::Matrix<_Scalar, Eigen::Dynamic, Eigen::Dynamic>;
35 | using VectorX=Eigen::Matrix<_Scalar, Eigen::Dynamic, 1>;
36 |
37 | /** Constructor, just call init()
38 | @param[in] maxSize is the maximum size of the unknown @f$ x @f$ if the affinity constraint is imposed.
39 | */
40 | ConvexLS(int maxSize=1) {
41 | q2.resize(0);
42 | init(maxSize);
43 | }
44 |
45 | /** Init matrices @f$ Q @f$ in the QR decomposition used for affinity constraint
46 | @param[in] maxSize is the maximum size of the unknown @f$ x @f$ if the affinity constraint is imposed.
47 | */
48 | void init(int maxSize) {
49 | int curN=(int)q2.size()+1;
50 | if (curN0) idx[np++]=i; else idx[n-i+np-1]=i;
74 |
75 | VectorX p;
76 |
77 | for (int rep=0; rep=0) {
81 | x+=p;
82 | if (np==n) break;
83 | Eigen::Index iMax;
84 | (indexing_vector(aTb, idx.tail(n-np))-indexing_row(aTa, idx.tail(n-np))*x).maxCoeff(&iMax);
85 | std::swap(idx[iMax+np], idx[np]);
86 | np++;
87 | } else {
88 | _Scalar alpha;
89 | int iMin=-1;
90 | for (int i=0; i> q2;
110 |
111 | /** Solve the gradient
112 | @param[in] aTa is the cross product matrix @f$ A^TA @f$
113 | @param[in] aTb is the vector @f$ A^Tb @f$
114 | @param[in] x is the current solution
115 | @param[in] idx indicates the current active set, @p idx(0).. @p idx(np-1) are passive (free) variables
116 | @param[in] np is the size of the active set
117 | @param[in] zeroSum=true will impose zer-sum of gradient
118 | @param[output] p is the by-reference negative gradient output
119 | */
120 | void solveP(const MatrixX& aTa, const VectorX& aTb, const VectorX& x, const Eigen::ArrayXi& idx, int np, bool zeroSum, VectorX& p) {
121 | VectorX z;
122 | p.setZero(aTb.size());
123 | if (!zeroSum) {
124 | z= indexing_row_col(aTa, idx.head(np), idx.head(np)).colPivHouseholderQr().solve( //A
125 | indexing_vector(aTb, idx.head(np))-indexing_row(aTa, idx.head(np))*x); //b
126 | for (int ip=0; ip1) {
128 | z=q2[np-2]*( //Re-project
129 | (q2[np-2].transpose()*indexing_row_col(aTa, idx.head(np), idx.head(np))*q2[np-2]).colPivHouseholderQr().solve( //A
130 | q2[np-2].transpose()*(indexing_vector(aTb, idx.head(np))-indexing_row(aTa, idx.head(np))*x) )); //b
131 | for (int ip=0; ip
16 |
17 | namespace Dem
18 | {
19 |
20 | /** NullaryOp forward mapping for matrix with row indices and column indices,
21 | check: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html
22 | */
23 | template
24 | class indexing_functor_row_col {
25 | const ArgType &m_arg;
26 | const RowIndexType &m_rowIndices;
27 | const ColIndexType &m_colIndices;
28 | public:
29 | typedef Eigen::Matrix MatrixType;
35 | indexing_functor_row_col(const ArgType& arg, const RowIndexType& row_indices, const ColIndexType& col_indices)
36 | : m_arg(arg), m_rowIndices(row_indices), m_colIndices(col_indices) {}
37 | const typename ArgType::Scalar& operator() (Eigen::Index row, Eigen::Index col) const {
38 | return m_arg(m_rowIndices[row], m_colIndices[col]);
39 | }
40 | };
41 |
42 | /** Function forward mapping for matrix with row indices and column indices,
43 | check: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html
44 | */
45 | template
46 | Eigen::CwiseNullaryOp, typename indexing_functor_row_col::MatrixType>
47 | indexing_row_col(const Eigen::MatrixBase& arg, const RowIndexType& row_indices, const ColIndexType& col_indices) {
48 | typedef indexing_functor_row_col Func;
49 | typedef typename Func::MatrixType MatrixType;
50 | return MatrixType::NullaryExpr(row_indices.size(), col_indices.size(), Func(arg.derived(), row_indices, col_indices));
51 | }
52 |
53 |
54 |
55 | /** NullaryOp forward mapping for matrix with row indices,
56 | check: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html
57 | */
58 | template
59 | class indexing_functor_row {
60 | const ArgType &m_arg;
61 | const RowIndexType &m_rowIndices;
62 | public:
63 | typedef Eigen::Matrix MatrixType;
69 | indexing_functor_row(const ArgType& arg, const RowIndexType& row_indices)
70 | : m_arg(arg), m_rowIndices(row_indices) {}
71 | const typename ArgType::Scalar& operator() (Eigen::Index row, Eigen::Index col) const {
72 | return m_arg(m_rowIndices[row], col);
73 | }
74 | };
75 |
76 | /** Function forward mapping for matrix with row indices,
77 | check: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html
78 | */
79 | template
80 | Eigen::CwiseNullaryOp, typename indexing_functor_row::MatrixType>
81 | indexing_row(const Eigen::MatrixBase& arg, const RowIndexType& row_indices) {
82 | typedef indexing_functor_row Func;
83 | typedef typename Func::MatrixType MatrixType;
84 | return MatrixType::NullaryExpr(row_indices.size(), arg.cols(), Func(arg.derived(), row_indices));
85 | }
86 |
87 |
88 |
89 | /** NullaryOp forward mapping for vector with indices,
90 | check: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html
91 | */
92 | template
93 | class indexing_functor_vector {
94 | const ArgType &m_arg;
95 | const IndexType &m_indices;
96 | public:
97 | typedef Eigen::Matrix VectorType;
103 | indexing_functor_vector(const ArgType& arg, const IndexType& indices)
104 | : m_arg(arg), m_indices(indices) {}
105 | const typename ArgType::Scalar& operator() (Eigen::Index idx) const {
106 | return m_arg(m_indices[idx]);
107 | }
108 | };
109 |
110 | /** Function forward mapping for vector with indices,
111 | check: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html
112 | */
113 | template
114 | Eigen::CwiseNullaryOp, typename indexing_functor_vector::VectorType>
115 | indexing_vector(const Eigen::MatrixBase& arg, const IndexType& indices) {
116 | typedef indexing_functor_vector Func;
117 | typedef typename Func::VectorType VectorType;
118 | return VectorType::NullaryExpr(indices.size(), Func(arg.derived(), indices));
119 | }
120 |
121 | }
122 |
123 | #endif
124 |
--------------------------------------------------------------------------------
/src/DemBones/LICENSE.md:
--------------------------------------------------------------------------------
1 | # BSD 3-Clause License
2 |
3 | Copyright (C) 2019 Electronic Arts Inc. All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions
7 | are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 | 2. Redistributions in binary form must reproduce the above copyright
12 | notice, this list of conditions and the following disclaimer in the
13 | documentation and/or other materials provided with the distribution.
14 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
15 | its contributors may be used to endorse or promote products derived
16 | from this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
19 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/src/DemBones/MatBlocks.h:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // Dem Bones - Skinning Decomposition Library //
3 | // Copyright (c) 2019, Electronic Arts. All rights reserved. //
4 | ///////////////////////////////////////////////////////////////////////////////
5 |
6 |
7 |
8 | /** @file "DemBones/MatBlocks.h"
9 | @brief Defines some macros to access sub-blocks of packing transformation/position matrices for convenience
10 |
11 | @details These definitions are not included by default although they are used in @p DemBones and @p DemBonesExt
12 | (they are undefined at the end of the files).
13 | */
14 |
15 | #ifndef DEM_BONES_MAT_BLOCKS
16 | #define DEM_BONES_MAT_BLOCKS
17 |
18 | //! A 4*4 sub-block that represents a transformation matrix, typically @p k denotes frame number and @p j denotes bone index
19 | #define blk4(k, j) template block<4, 4>((k)*4, (j)*4)
20 |
21 | //! The 3*3 rotation part or the transformation matrix #blk4(@p k, @p j)
22 | #define rotMat(k, j) template block<3, 3>((k)*4, (j)*4)
23 |
24 | //! The 3*1 translation vector part or the transformation matrix #blk4(@p k, @p j)
25 | #define transVec(k, j) col((j)*4+3).template segment<3>((k)*4)
26 |
27 | //! A 3*1 sub-block that represents position of a vertex, typically @p k denotes frame number and @p i denotes vertex index
28 | #define vec3(k, i) col(i).template segment<3>((k)*3)
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/cmtConfig.h.in:
--------------------------------------------------------------------------------
1 | #define CMT_VERSION_MAJOR @cmt_VERSION_MAJOR@
2 | #define CMT_VERSION_MINOR @cmt_VERSION_MINOR@
3 |
--------------------------------------------------------------------------------
/src/common.cpp:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | MStatus JumpToElement(MArrayDataHandle& hArray, unsigned int index) {
14 | MStatus status;
15 | status = hArray.jumpToElement(index);
16 | if (MFAIL(status)) {
17 | MArrayDataBuilder builder = hArray.builder(&status);
18 | CHECK_MSTATUS_AND_RETURN_IT(status);
19 | builder.addElement(index, &status);
20 | CHECK_MSTATUS_AND_RETURN_IT(status);
21 | status = hArray.set(builder);
22 | CHECK_MSTATUS_AND_RETURN_IT(status);
23 | status = hArray.jumpToElement(index);
24 | CHECK_MSTATUS_AND_RETURN_IT(status);
25 | }
26 | return status;
27 | }
28 |
29 | void StartProgress(const MString& title, unsigned int count) {
30 | if (MGlobal::mayaState() == MGlobal::kInteractive) {
31 | MString message = "progressBar -e -bp -ii true -st \"";
32 | message += title;
33 | message += "\" -max ";
34 | message += count;
35 | message += " $gMainProgressBar;";
36 | MGlobal::executeCommand(message);
37 | }
38 | }
39 |
40 | void StepProgress(int step) {
41 | if (MGlobal::mayaState() == MGlobal::kInteractive) {
42 | MString message = "progressBar -e -s ";
43 | message += step;
44 | message += " $gMainProgressBar;";
45 | MGlobal::executeCommand(message);
46 | }
47 | }
48 |
49 | bool ProgressCancelled() {
50 | if (MGlobal::mayaState() == MGlobal::kInteractive) {
51 | int cmdResult = 0;
52 | MGlobal::executeCommand("progressBar -query -isCancelled $gMainProgressBar", cmdResult);
53 | return cmdResult != 0;
54 | }
55 | return false;
56 | }
57 |
58 | void EndProgress() {
59 | if (MGlobal::mayaState() == MGlobal::kInteractive) {
60 | MGlobal::executeCommand("progressBar -e -ep $gMainProgressBar;");
61 | }
62 | }
63 |
64 | bool isShapeNode(MDagPath& path) {
65 | return path.node().hasFn(MFn::kMesh) || path.node().hasFn(MFn::kNurbsCurve) ||
66 | path.node().hasFn(MFn::kNurbsSurface);
67 | }
68 |
69 | MStatus getShapeNode(MDagPath& path, bool intermediate) {
70 | MStatus status;
71 |
72 | if (isShapeNode(path)) {
73 | // Start at the transform so we can honor the intermediate flag.
74 | path.pop();
75 | }
76 |
77 | if (path.hasFn(MFn::kTransform)) {
78 | unsigned int shapeCount = path.childCount();
79 |
80 | for (unsigned int i = 0; i < shapeCount; ++i) {
81 | status = path.push(path.child(i));
82 | CHECK_MSTATUS_AND_RETURN_IT(status);
83 | if (!isShapeNode(path)) {
84 | path.pop();
85 | continue;
86 | }
87 |
88 | MFnDagNode fnNode(path, &status);
89 | CHECK_MSTATUS_AND_RETURN_IT(status);
90 | if ((!fnNode.isIntermediateObject() && !intermediate) ||
91 | (fnNode.isIntermediateObject() && intermediate)) {
92 | return MS::kSuccess;
93 | }
94 | // Go to the next shape
95 | path.pop();
96 | }
97 | }
98 |
99 | // No valid shape node found.
100 | return MS::kFailure;
101 | }
102 |
103 | MStatus getDagPath(const MString& name, MDagPath& path) {
104 | MStatus status;
105 | MSelectionList list;
106 | status = MGlobal::getSelectionListByName(name, list);
107 | CHECK_MSTATUS_AND_RETURN_IT(status);
108 | status = list.getDagPath(0, path);
109 | CHECK_MSTATUS_AND_RETURN_IT(status);
110 | return MS::kSuccess;
111 | }
112 |
113 | MStatus getDependNode(const MString& name, MObject& oNode) {
114 | MStatus status;
115 | MSelectionList list;
116 | status = MGlobal::getSelectionListByName(name, list);
117 | CHECK_MSTATUS_AND_RETURN_IT(status);
118 | status = list.getDependNode(0, oNode);
119 | CHECK_MSTATUS_AND_RETURN_IT(status);
120 | return MS::kSuccess;
121 | }
122 |
123 | MStatus DeleteIntermediateObjects(MDagPath& path) {
124 | MStatus status;
125 | MDagPath pathMesh(path);
126 | while (getShapeNode(pathMesh, true) == MS::kSuccess) {
127 | status = MGlobal::executeCommand("delete " + pathMesh.partialPathName());
128 | CHECK_MSTATUS_AND_RETURN_IT(status);
129 | pathMesh = MDagPath(path);
130 | }
131 | return MS::kSuccess;
132 | }
133 |
--------------------------------------------------------------------------------
/src/common.h:
--------------------------------------------------------------------------------
1 | #ifndef CMT_COMMON_H
2 | #define CMT_COMMON_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include