├── .gitignore ├── DeformationLearningSolver ├── bin │ ├── SSDSolverCmd │ │ ├── 2014 │ │ │ └── plug-ins │ │ │ │ ├── SSDSolverCmd.bundle │ │ │ │ ├── SSDSolverCmd.mll │ │ │ │ └── SSDSolverCmd.so │ │ ├── 2015 │ │ │ └── plug-ins │ │ │ │ ├── SSDSolverCmd.bundle │ │ │ │ ├── SSDSolverCmd.mll │ │ │ │ └── SSDSolverCmd.so │ │ ├── 2016 │ │ │ └── plug-ins │ │ │ │ ├── SSDSolverCmd.bundle │ │ │ │ ├── SSDSolverCmd.mll │ │ │ │ └── SSDSolverCmd.so │ │ └── 2017 │ │ │ └── plug-ins │ │ │ ├── SSDSolverCmd.bundle │ │ │ ├── SSDSolverCmd.mll │ │ │ └── SSDSolverCmd.so │ └── wbDeltaMushDeformer │ │ ├── 2014 │ │ ├── plug-ins │ │ │ ├── wbDeltaMushDeformer.bundle │ │ │ ├── wbDeltaMushDeformer.mll │ │ │ └── wbDeltaMushDeformer.so │ │ └── scripts │ │ │ └── AEwbDeltaMushTemplate.mel │ │ ├── 2015 │ │ ├── plug-ins │ │ │ ├── wbDeltaMushDeformer.bundle │ │ │ ├── wbDeltaMushDeformer.mll │ │ │ └── wbDeltaMushDeformer.so │ │ └── scripts │ │ │ └── AEwbDeltaMushTemplate.mel │ │ ├── 2016 │ │ ├── plug-ins │ │ │ ├── wbDeltaMushDeformer.bundle │ │ │ ├── wbDeltaMushDeformer.mll │ │ │ └── wbDeltaMushDeformer.so │ │ └── scripts │ │ │ └── AEwbDeltaMushTemplate.mel │ │ └── 2017 │ │ ├── plug-ins │ │ ├── wbDeltaMushDeformer.bundle │ │ ├── wbDeltaMushDeformer.mll │ │ └── wbDeltaMushDeformer.so │ │ └── scripts │ │ └── AEwbDeltaMushTemplate.mel ├── icons │ └── wbDeltaMush.png ├── install.mel ├── modules │ └── DeformationLearningSolver.mod └── scripts │ └── DLS │ ├── __init__.py │ ├── core │ ├── __init__.py │ ├── fnData.py │ ├── learningFunc.py │ ├── miscFunc.py │ ├── samplingFunc.py │ └── utils.py │ ├── startup │ ├── __init__.py │ └── setup.py │ └── widget │ ├── __init__.py │ ├── aboutDialog.py │ ├── axisOptionWindow.py │ ├── baseOptionWindow.py │ ├── baseTab.py │ ├── config.ini │ ├── customAttributeEditor.py │ ├── learningTab.py │ ├── mainWindow.py │ ├── miscTab.py │ ├── optionWindow.py │ ├── samplingTab.py │ ├── ui │ ├── aboutDialog.ui │ ├── axisWindow.ui │ ├── customAttributeEditor.ui │ ├── learningTab.ui │ ├── miscTab.ui │ ├── optionWindow.ui │ └── samplingTab.ui │ └── utils.py ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | 7 | # Distribution / packaging 8 | .Python 9 | env/ 10 | build/ 11 | develop-eggs/ 12 | dist/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .coverage.* 40 | .cache 41 | nosetests.xml 42 | coverage.xml 43 | *,cover 44 | 45 | # Translations 46 | *.mo 47 | *.pot 48 | 49 | # Django stuff: 50 | *.log 51 | 52 | # Sphinx documentation 53 | docs/_build/ 54 | 55 | # PyBuilder 56 | target/ 57 | -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2014/plug-ins/SSDSolverCmd.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2014/plug-ins/SSDSolverCmd.bundle -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2014/plug-ins/SSDSolverCmd.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2014/plug-ins/SSDSolverCmd.mll -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2014/plug-ins/SSDSolverCmd.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2014/plug-ins/SSDSolverCmd.so -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2015/plug-ins/SSDSolverCmd.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2015/plug-ins/SSDSolverCmd.bundle -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2015/plug-ins/SSDSolverCmd.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2015/plug-ins/SSDSolverCmd.mll -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2015/plug-ins/SSDSolverCmd.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2015/plug-ins/SSDSolverCmd.so -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2016/plug-ins/SSDSolverCmd.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2016/plug-ins/SSDSolverCmd.bundle -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2016/plug-ins/SSDSolverCmd.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2016/plug-ins/SSDSolverCmd.mll -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2016/plug-ins/SSDSolverCmd.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2016/plug-ins/SSDSolverCmd.so -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2017/plug-ins/SSDSolverCmd.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2017/plug-ins/SSDSolverCmd.bundle -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2017/plug-ins/SSDSolverCmd.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2017/plug-ins/SSDSolverCmd.mll -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/SSDSolverCmd/2017/plug-ins/SSDSolverCmd.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/SSDSolverCmd/2017/plug-ins/SSDSolverCmd.so -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2014/plug-ins/wbDeltaMushDeformer.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2014/plug-ins/wbDeltaMushDeformer.bundle -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2014/plug-ins/wbDeltaMushDeformer.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2014/plug-ins/wbDeltaMushDeformer.mll -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2014/plug-ins/wbDeltaMushDeformer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2014/plug-ins/wbDeltaMushDeformer.so -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2014/scripts/AEwbDeltaMushTemplate.mel: -------------------------------------------------------------------------------- 1 | global proc AEwbDeltaMushTemplate( string $nodeName ) 2 | { 3 | editorTemplate -beginScrollLayout; 4 | 5 | // Add Delta Mush Attributes section 6 | editorTemplate -beginLayout "Delta Mush Attributes" -collapse 0; 7 | editorTemplate -addControl "smoothingIterations"; 8 | editorTemplate -addControl "smoothingAlgorithm"; 9 | editorTemplate -addControl "smoothingStep"; 10 | editorTemplate -addControl "pinBorderVertices"; 11 | editorTemplate -addControl "displacement"; 12 | editorTemplate -addControl "scale"; 13 | editorTemplate -addControl "tangentMode"; 14 | editorTemplate -endLayout; 15 | 16 | AEweightGeometryFilterTemplate $nodeName; 17 | 18 | editorTemplate -addExtraControls; 19 | editorTemplate -suppress "cache"; 20 | editorTemplate -endScrollLayout; 21 | } 22 | -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2015/plug-ins/wbDeltaMushDeformer.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2015/plug-ins/wbDeltaMushDeformer.bundle -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2015/plug-ins/wbDeltaMushDeformer.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2015/plug-ins/wbDeltaMushDeformer.mll -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2015/plug-ins/wbDeltaMushDeformer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2015/plug-ins/wbDeltaMushDeformer.so -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2015/scripts/AEwbDeltaMushTemplate.mel: -------------------------------------------------------------------------------- 1 | global proc AEwbDeltaMushTemplate( string $nodeName ) 2 | { 3 | editorTemplate -beginScrollLayout; 4 | 5 | // Add Delta Mush Attributes section 6 | editorTemplate -beginLayout "Delta Mush Attributes" -collapse 0; 7 | editorTemplate -addControl "smoothingIterations"; 8 | editorTemplate -addControl "smoothingAlgorithm"; 9 | editorTemplate -addControl "smoothingStep"; 10 | editorTemplate -addControl "pinBorderVertices"; 11 | editorTemplate -addControl "displacement"; 12 | editorTemplate -addControl "scale"; 13 | editorTemplate -addControl "tangentMode"; 14 | editorTemplate -endLayout; 15 | 16 | AEweightGeometryFilterTemplate $nodeName; 17 | 18 | editorTemplate -addExtraControls; 19 | editorTemplate -suppress "cache"; 20 | editorTemplate -endScrollLayout; 21 | } 22 | -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2016/plug-ins/wbDeltaMushDeformer.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2016/plug-ins/wbDeltaMushDeformer.bundle -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2016/plug-ins/wbDeltaMushDeformer.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2016/plug-ins/wbDeltaMushDeformer.mll -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2016/plug-ins/wbDeltaMushDeformer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2016/plug-ins/wbDeltaMushDeformer.so -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2016/scripts/AEwbDeltaMushTemplate.mel: -------------------------------------------------------------------------------- 1 | global proc AEwbDeltaMushTemplate( string $nodeName ) 2 | { 3 | editorTemplate -beginScrollLayout; 4 | 5 | // Add Delta Mush Attributes section 6 | editorTemplate -beginLayout "Delta Mush Attributes" -collapse 0; 7 | editorTemplate -addControl "smoothingIterations"; 8 | editorTemplate -addControl "smoothingAlgorithm"; 9 | editorTemplate -addControl "smoothingStep"; 10 | editorTemplate -addControl "pinBorderVertices"; 11 | editorTemplate -addControl "displacement"; 12 | editorTemplate -addControl "scale"; 13 | editorTemplate -addControl "tangentMode"; 14 | editorTemplate -endLayout; 15 | 16 | AEweightGeometryFilterTemplate $nodeName; 17 | 18 | editorTemplate -addExtraControls; 19 | editorTemplate -suppress "cache"; 20 | editorTemplate -endScrollLayout; 21 | } 22 | -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2017/plug-ins/wbDeltaMushDeformer.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2017/plug-ins/wbDeltaMushDeformer.bundle -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2017/plug-ins/wbDeltaMushDeformer.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2017/plug-ins/wbDeltaMushDeformer.mll -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2017/plug-ins/wbDeltaMushDeformer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/bin/wbDeltaMushDeformer/2017/plug-ins/wbDeltaMushDeformer.so -------------------------------------------------------------------------------- /DeformationLearningSolver/bin/wbDeltaMushDeformer/2017/scripts/AEwbDeltaMushTemplate.mel: -------------------------------------------------------------------------------- 1 | global proc AEwbDeltaMushTemplate( string $nodeName ) 2 | { 3 | editorTemplate -beginScrollLayout; 4 | 5 | // Add Delta Mush Attributes section 6 | editorTemplate -beginLayout "Delta Mush Attributes" -collapse 0; 7 | editorTemplate -addControl "smoothingIterations"; 8 | editorTemplate -addControl "smoothingAlgorithm"; 9 | editorTemplate -addControl "smoothingStep"; 10 | editorTemplate -addControl "pinBorderVertices"; 11 | editorTemplate -addControl "displacement"; 12 | editorTemplate -addControl "scale"; 13 | editorTemplate -addControl "tangentMode"; 14 | editorTemplate -endLayout; 15 | 16 | AEweightGeometryFilterTemplate $nodeName; 17 | 18 | editorTemplate -addExtraControls; 19 | editorTemplate -suppress "cache"; 20 | editorTemplate -endScrollLayout; 21 | } 22 | -------------------------------------------------------------------------------- /DeformationLearningSolver/icons/wbDeltaMush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebberHuang/DeformationLearningSolver/c58f2c7eb8e4f172948de9acd2b3e6cb39bb8bc2/DeformationLearningSolver/icons/wbDeltaMush.png -------------------------------------------------------------------------------- /DeformationLearningSolver/install.mel: -------------------------------------------------------------------------------- 1 | /* 2 | #---------------------------------------------------------------------- 3 | # Author: Webber Huang 4 | # Contact: xracz.fx@gmail.com 5 | # Homepage: http://riggingtd.com 6 | #---------------------------------------------------------------------- 7 | */ 8 | 9 | 10 | global string $gShelfTopLevel; 11 | string $currentShelf = `tabLayout -query -selectTab $gShelfTopLevel`; 12 | setParent $currentShelf; 13 | 14 | string $scriptLocation=`scriptLocation`; 15 | string $scriptName="Deformation Learning Solver"; 16 | string $command="import DLS\nDLS.launch()"; 17 | 18 | // Setup module 19 | python("import os"); 20 | python("home = os.path.expanduser(\"~\")"); 21 | string $mayaModDir = python("home+\"/maya/modules/\""); 22 | if (`about -os` == "mac") $mayaModDir = python("home+\"/Library/Preferences/Autodesk/maya/modules/\""); 23 | python("try:\n\tmodDir=os.path.relpath(\""+$scriptLocation+"\",\""+$mayaModDir+"\").replace('\\\\', '/')\nexcept:\n\tmodDir=\"\""); 24 | string $modDir = python("modDir"); 25 | if ($modDir == "") $modDir = `substring $scriptLocation 1 (size($scriptLocation)-1)`; 26 | 27 | string $modName = "DeformationLearningSolver"; 28 | string $modFileName = $modName+".mod"; 29 | string $modFile = $scriptLocation + "modules/" + $modFileName; 30 | string $newModFile = $mayaModDir + $modFileName ; 31 | string $toBeReplacedStr = "REPLACE_TO_YOUR_PATH"; 32 | 33 | int $copySuccess = `sysFile -cp $newModFile $modFile`; 34 | if (!$copySuccess) sysFile -md $mayaModDir; 35 | 36 | $inFileId=`fopen $modFile "r"`; 37 | $outFileId=`fopen $newModFile "w"`; 38 | string $nextLine = `fgetline $inFileId`; 39 | while ( size( $nextLine ) > 0 ) { 40 | $nextLine = `substitute $toBeReplacedStr $nextLine $modDir`; 41 | fprint($outFileId, $nextLine); 42 | $nextLine = `fgetline $inFileId`; 43 | } 44 | fclose $inFileId; 45 | fclose $outFileId; 46 | 47 | // load script path for current session 48 | loadModule -a; 49 | string $modScriptDir = ($scriptLocation+"scripts"); 50 | print ($modScriptDir +"\n"); 51 | python ("import sys") ; 52 | string $pyPaths[] = python ("sys.path") ; 53 | if ( stringArrayCount ($modScriptDir, $pyPaths) == 0 ) 54 | python ("sys.path.insert(0, '" + $modScriptDir + "')") ; 55 | 56 | //string $icon=$scriptLocation+"icons/deformationLearningIcon.png"; 57 | 58 | // Install button to current shelf 59 | shelfButton 60 | -command $command 61 | -annotation $scriptName 62 | -label $scriptName 63 | //-image $icon 64 | -imageOverlayLabel $scriptName 65 | -image "pythonFamily.png" 66 | -style "iconOnly" 67 | -sourceType "python" 68 | ; 69 | 70 | print ("// "+$scriptName+" has been added to current shelf.\n"); 71 | 72 | // Helper functions for locating script's location 73 | global proc scriptLocator (){} 74 | 75 | global proc string scriptLocation () 76 | { 77 | string $whatIs=`whatIs scriptLocator`; 78 | string $fullPath=`substring $whatIs 25 999`; 79 | string $buffer[]; 80 | int $numTok=`tokenize $fullPath "/" $buffer`; 81 | int $numLetters=size($fullPath); 82 | int $numLettersLastFolder=size($buffer[$numTok-1]); 83 | string $scriptLocation=`substring $fullPath 1 ($numLetters-$numLettersLastFolder)`; 84 | return $scriptLocation; 85 | } -------------------------------------------------------------------------------- /DeformationLearningSolver/modules/DeformationLearningSolver.mod: -------------------------------------------------------------------------------- 1 | + DeformationLearningSolver any REPLACE_TO_YOUR_PATH 2 | 3 | + MAYAVERSION:2014 SSDSolverCmd any REPLACE_TO_YOUR_PATH/bin/SSDSolverCmd/2014 4 | + MAYAVERSION:2015 SSDSolverCmd any REPLACE_TO_YOUR_PATH/bin/SSDSolverCmd/2015 5 | + MAYAVERSION:2016 SSDSolverCmd any REPLACE_TO_YOUR_PATH/bin/SSDSolverCmd/2016 6 | + MAYAVERSION:2017 SSDSolverCmd any REPLACE_TO_YOUR_PATH/bin/SSDSolverCmd/2017 7 | 8 | + MAYAVERSION:2014 wbDeltaMushDeformer any REPLACE_TO_YOUR_PATH/bin/wbDeltaMushDeformer/2014 9 | + MAYAVERSION:2015 wbDeltaMushDeformer any REPLACE_TO_YOUR_PATH/bin/wbDeltaMushDeformer/2015 10 | + MAYAVERSION:2016 wbDeltaMushDeformer any REPLACE_TO_YOUR_PATH/bin/wbDeltaMushDeformer/2016 11 | + MAYAVERSION:2017 wbDeltaMushDeformer any REPLACE_TO_YOUR_PATH/bin/wbDeltaMushDeformer/2017 -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | 6 | #---------------------------------------------------------------------- 7 | def launch(): 8 | """""" 9 | from DLS.startup import setup 10 | reload(setup) 11 | setup.launch() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/core/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/core/fnData.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | 6 | import maya.cmds as cmds 7 | import maya.OpenMaya as om 8 | import maya.OpenMayaAnim as oma 9 | from DLS.core import utils 10 | 11 | 12 | class FnSkinCluster(object): 13 | 14 | def __init__(self, skinCluster=None): 15 | """ 16 | Args: 17 | skinCluster (str, Optional): Defaults to None 18 | """ 19 | self.skinCluster = skinCluster 20 | if skinCluster: 21 | self.fn = oma.MFnSkinCluster(utils.getDependNode(skinCluster)) 22 | 23 | def setSkinCluster(self, skinCluster): 24 | """ 25 | Args: 26 | skinCluster (str, Optional): Defaults to None 27 | 28 | Returns: 29 | SkinClusterFn 30 | """ 31 | self.skinCluster = skinCluster 32 | self.fn = oma.MFnSkinCluster(utils.getDependNode(skinCluster)) 33 | return self 34 | 35 | def getLogicalInfluenceIndex(self,influence): 36 | """ 37 | Args: 38 | influence (str) 39 | 40 | Returns: 41 | int 42 | """ 43 | try: 44 | dagPath = utils.getDagPath(influence) 45 | except: 46 | raise utils.UserInputError("Could not find influence '%s' in %s" % 47 | (influence, self.skinCluster)) 48 | 49 | return self.fn.indexForInfluenceObject(dagPath) 50 | 51 | #---------------------------------------------------------------------- 52 | def getPhysicalInfluenceIndex(self, influence): 53 | """ 54 | Args: 55 | influence (str) 56 | 57 | Returns: 58 | int 59 | """ 60 | matrices = cmds.listConnections("%s.matrix" % self.skinCluster, s=1, d=0) 61 | return matrices.index(influence) 62 | 63 | #---------------------------------------------------------------------- 64 | def getInfluenceData(self, influence): 65 | """ 66 | Args: 67 | influence (str) 68 | 69 | Returns: 70 | WeightData 71 | """ 72 | try: 73 | dagPath = utils.getDagPath(influence) 74 | except: 75 | raise utils.UserInputError("Could not find influence '%s' in %s" % 76 | (influence, self.skinCluster)) 77 | selList = om.MSelectionList() 78 | weights = om.MDoubleArray() 79 | 80 | self.fn.getPointsAffectedByInfluence(dagPath, selList, weights) 81 | 82 | componentStr = [] 83 | selList.getSelectionStrings(componentStr) 84 | componentStr = cmds.ls(componentStr, ap=1, fl=1) 85 | weights = [w for w in weights] 86 | 87 | return WeightData(componentStr, weights) 88 | 89 | #---------------------------------------------------------------------- 90 | def listInfluences(self, asDagPath=True): 91 | """ 92 | Returns: 93 | list 94 | """ 95 | dagPaths = om.MDagPathArray() 96 | self.fn.influenceObjects(dagPaths) 97 | if asDagPath: return dagPaths 98 | else: return [dagPaths[i].partialPathName() for i in xrange(dagPaths.length())] 99 | 100 | #---------------------------------------------------------------------- 101 | def getWeightData(self, elements): 102 | """ 103 | Args: 104 | elements (list) 105 | 106 | Returns: 107 | SkinWeightData 108 | """ 109 | dagPath, components = utils.getDagPathComponents(elements) 110 | 111 | # Get all influences 112 | infs = self.listInfluences(asDagPath=False) 113 | influenceIndices = om.MIntArray() 114 | [influenceIndices.append(self.getPhysicalInfluenceIndex(inf)) for inf in infs] 115 | 116 | # Get all weights 117 | weights = om.MDoubleArray() 118 | self.fn.getWeights(dagPath, components, influenceIndices, weights) 119 | weights = [w for w in weights] 120 | 121 | return SkinWeightData(elements, infs, weights) 122 | 123 | #---------------------------------------------------------------------- 124 | def setWeightData(self, data, normalize=True): 125 | """ 126 | Args: 127 | data (SkinWeightData) 128 | normalize (bool, Optional): Defaults to True 129 | """ 130 | # Construct dagPath and components 131 | compList = data.getComponents() 132 | dagPath, components = utils.getDagPathComponents(compList) 133 | 134 | # Construct influence indices 135 | influenceIndices = om.MIntArray() 136 | [influenceIndices.append(self.getPhysicalInfluenceIndex(inf)) for inf in data.getInfluences()] 137 | 138 | # Construct weights 139 | weights = om.MDoubleArray() 140 | [weights.append(w) for w in data.getWeights()] 141 | oldValues = om.MDoubleArray() 142 | self.fn.getWeights(dagPath, components, influenceIndices, oldValues) 143 | 144 | self.fn.setWeights(dagPath, components, influenceIndices, weights, normalize, oldValues) 145 | 146 | #---------------------------------------------------------------------- 147 | def flushWeights(self, influence): 148 | """ 149 | Args: 150 | influence (str) 151 | """ 152 | weightData = self.getInfluenceData(influence) 153 | skinData = SkinWeightData(weightData.getElements(), [influence], weightData.getWeights()) 154 | [skinData.addInfluence(comp, influence, 0.0) for comp in skinData.getComponents()] 155 | self.setWeightData(skinData) 156 | 157 | #---------------------------------------------------------------------- 158 | def getInfluenceTransforms(self, space=om.MSpace.kObject): 159 | infs = self.listInfluences() 160 | 161 | if space == om.MSpace.kWorld: 162 | return [infs[i].inclusiveMatrix() for i in xrange(infs.length())] 163 | 164 | return [om.MFnTransform(infs[i]).transformation().asMatrix() 165 | for i in xrange(infs.length())] -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/core/learningFunc.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | 6 | import maya.cmds as cmds 7 | import maya.OpenMaya as om 8 | 9 | from DLS.core import utils 10 | from DLS.core import fnData 11 | reload(utils) 12 | 13 | 14 | #---------------------------------------------------------------------- 15 | def solve(numBones, maxInfs, targetMesh, isAlternativeUpdate, start, end, maxIters=10, isKeepOriginal=True, 16 | pruneBelow=0.0, epsilon=1.0, isDeleteDeltaMush=False): 17 | """ 18 | Args: 19 | numBones (int) 20 | maxInfs (int) 21 | start (int) 22 | end (int) 23 | maxIters (int) 24 | epsilon (float) 25 | """ 26 | try: 27 | mesh = cmds.ls(sl=1)[0]; 28 | except: 29 | om.MGlobal.displayError("Select mesh first.") 30 | return 31 | 32 | mode = 0 33 | 34 | skinCluster = utils.findRelatedSkinCluster(mesh) 35 | if skinCluster: 36 | fnSkin = fnData.FnSkinCluster(skinCluster) 37 | bones = fnSkin.listInfluences(False) 38 | 39 | if targetMesh: # Solve transformations from existing weights 40 | if not isAlternativeUpdate: # Alternative update transformations and weights with new mesh sequences 41 | mode = 2 42 | else: # Solve weights from existing transformations 43 | targetMesh = mesh 44 | mode = 1 45 | cmds.ssdSolver(mesh, 46 | tm=targetMesh, 47 | m=mode, 48 | mit=maxIters, 49 | mi=maxInfs, 50 | ib=bones, 51 | isc=skinCluster, 52 | st=start, 53 | et=end, 54 | pb=pruneBelow, 55 | e=epsilon) 56 | else: 57 | if isKeepOriginal: 58 | # Duplicate a new mesh, then transfer deformation with blendshape 59 | cmds.currentTime(start) 60 | new_mesh = cmds.duplicate(mesh, name="%s_solved" % mesh, rc=1, rr=1)[0] 61 | blendshape = cmds.blendShape(mesh, new_mesh, o="world")[0] 62 | attrs = cmds.listAttr('%s.weight' % blendshape, m=1) 63 | cmds.setAttr("%s.%s" % (blendshape, attrs[0]), 1) 64 | mesh = new_mesh 65 | 66 | targetMesh = mesh 67 | cmds.ssdSolver(mesh, 68 | tm=targetMesh, 69 | m=mode, 70 | mi=maxInfs, 71 | nb=numBones, 72 | st=start, 73 | et=end, 74 | mit=maxIters, 75 | pb=pruneBelow, 76 | e=epsilon) 77 | 78 | if isKeepOriginal: 79 | cmds.delete(blendshape) 80 | 81 | # postprocessing 82 | if isDeleteDeltaMush: 83 | deltaMushNode = utils.findRelatedDeltaMush(mesh) 84 | if deltaMushNode: 85 | cmds.delete(deltaMushNode) 86 | 87 | #---------------------------------------------------------------------- 88 | def measure(start, end): 89 | """""" 90 | src, tgt = '', '' 91 | try: 92 | src, tgt = cmds.ls(sl=1, ap=1) 93 | except: 94 | om.MGlobal.displayError("Please select two meshes.") 95 | return 96 | 97 | cmds.ssdSolver(src, st=start, et=end, cw=tgt) 98 | 99 | #---------------------------------------------------------------------- 100 | def getMeshFromSelection(): 101 | """""" 102 | try: 103 | node = cmds.ls(sl=1, ap=1)[0] 104 | dagPath = utils.getDagPath(node) 105 | if dagPath.hasFn(om.MFn.kMesh): 106 | return node 107 | else: 108 | om.MGlobal.displayError("\"%s\" isn't mesh type." % node) 109 | except: 110 | return "" -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/core/miscFunc.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | 6 | import maya.cmds as cmds 7 | import maya.OpenMaya as om 8 | 9 | from DLS.core import utils 10 | 11 | 12 | #---------------------------------------------------------------------- 13 | def applyRigidSkin(): 14 | """""" 15 | sel = cmds.ls(sl=1, ap=1) 16 | if len(sel) < 2: 17 | om.MGlobal.displayError("Please select joints first, then mesh.") 18 | return 19 | mesh = sel.pop() 20 | cmds.skinCluster(sel, mesh, tsb=1, mi=0, nw=1, bm=1) 21 | 22 | #---------------------------------------------------------------------- 23 | def applyDeltaMush(smooth=1.0, iterations=20, useBuildIn=False): 24 | """ 25 | Args: 26 | smooth (float) 27 | iterations (int) 28 | """ 29 | sel = cmds.ls(sl=1, ap=1) 30 | 31 | if not sel: 32 | om.MGlobal.displayError("Please select a few meshes.") 33 | return 34 | 35 | if useBuildIn: 36 | cmds.deltaMush(sel, si=iterations, ss=smooth, pbv=0) 37 | else: 38 | cmds.wbDeltaMush(sel, si=iterations, ss=smooth, pbv=0) 39 | 40 | #---------------------------------------------------------------------- 41 | def selectAllBelow(skipTips=False): 42 | try: 43 | sel = cmds.ls(sl=1, ap=1) 44 | allDescs = sel + cmds.listRelatives(sel, f=1, ad=1, s=0, ni=1) 45 | if skipTips: 46 | allDescs = [s for s in allDescs if cmds.listRelatives(s, c=1)] 47 | cmds.select(allDescs) 48 | except: 49 | om.MGlobal.displayError("Please select something.") 50 | return 51 | 52 | #---------------------------------------------------------------------- 53 | def selectInfluenceJoints(): 54 | try: 55 | sel = cmds.ls(sl=1, ap=1)[0] 56 | try: 57 | skinNode = utils.findRelatedSkinCluster(sel) 58 | infs = cmds.skinCluster(skinNode, q=1, inf=1) 59 | except: 60 | om.MGlobal.displayError("No skinCluster found in history of %s." % sel) 61 | return 62 | cmds.select(infs) 63 | except: 64 | om.MGlobal.displayError("Please select something.") 65 | return 66 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/core/samplingFunc.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | 6 | import maya.cmds as cmds 7 | import maya.OpenMaya as om 8 | 9 | from DLS.core import utils 10 | 11 | 12 | #---------------------------------------------------------------------- 13 | def attrSampling(node, attr, minVal, maxVal, interval=1): 14 | """ 15 | Args: 16 | node (str) 17 | attrs (list) 18 | minVal (float) 19 | maxVal (float) 20 | interval (int) 21 | 22 | Returns: 23 | int 24 | """ 25 | currTime = cmds.currentTime(q=1) 26 | currVal = cmds.getAttr('%s.%s' % (node, attr)) 27 | vals = [currVal, currVal+minVal, currVal+maxVal, currVal] 28 | 29 | for i, v in enumerate(vals): 30 | if i not in [0, len(vals)-1] and (currVal - v) == 0: 31 | continue 32 | 33 | cmds.setKeyframe(node, at=attr, v=v, t=currTime) 34 | currTime += interval 35 | return currTime 36 | 37 | #---------------------------------------------------------------------- 38 | def attrsSampling(attrData, interval=1): 39 | """ 40 | Args: 41 | attrData (dict): {node1: [[attr1, min, max], [attr2, min, max], ...], 42 | node2: [[attr1, min, max], [attr2, min, max], ...], 43 | ...} 44 | interval (int) 45 | 46 | Returns: 47 | int 48 | """ 49 | currTime = cmds.currentTime(q=1) 50 | for node, attrVals in attrData.iteritems(): 51 | for vals in attrVals: 52 | attr, minVal, maxVal = vals 53 | if not cmds.objExists('.'.join([node, attr])): 54 | continue 55 | currTime = attrSampling(node, attr, minVal, maxVal, interval) 56 | currTime -= 2 * interval 57 | cmds.currentTime(currTime) 58 | return currTime+1 * interval 59 | 60 | #---------------------------------------------------------------------- 61 | def customAttrsSampling(attrData, interval=1): 62 | """ 63 | Args: 64 | attrData (dict): {node1: [[attr1, min, max], [attr2, min, max], ...], 65 | node2: [[attr1, min, max], [attr2, min, max], ...], 66 | ...} 67 | interval (int) 68 | 69 | Returns: 70 | int 71 | """ 72 | start = cmds.currentTime(q=1) 73 | currTime = attrsSampling(attrData, interval) 74 | end = currTime-1 75 | utils.trimTimeRange(start, end) 76 | cmds.currentTime(start) 77 | 78 | #---------------------------------------------------------------------- 79 | def blendShapeSampling(node, interval=1): 80 | """ 81 | Args: 82 | node (str) 83 | interval (int) 84 | 85 | Returns: 86 | int 87 | """ 88 | assert cmds.nodeType(node) == 'blendShape', \ 89 | "node must be a blendShape type" 90 | start = cmds.currentTime(q=1) 91 | 92 | attrs = cmds.listAttr('%s.weight' % node, m=1) 93 | attrData = {node: [[attr, 0.0, 1.0] for attr in attrs]} 94 | 95 | currTime = attrsSampling(attrData, interval) 96 | 97 | end = currTime-1 98 | utils.trimTimeRange(start, end) 99 | cmds.currentTime(start) 100 | 101 | #---------------------------------------------------------------------- 102 | def transformSampling(translateMin, translateMax, 103 | rotateMin, rotateMax, 104 | scaleMin, scaleMax, 105 | isTranslate, isRotate, isScale, 106 | translateAttrs = ('tx', 'ty', 'tz'), 107 | rotateAttrs = ('rx', 'ry', 'rz'), 108 | scaleAttrs = ('sx', 'sy', 'sz'), 109 | interval=1): 110 | """ 111 | Args: 112 | translateMin (float) 113 | translateMax (float) 114 | rotateMin (float) 115 | rotateMax (float) 116 | scaleMin (float) 117 | scaleMax (float) 118 | isTranslate (bool) 119 | isRotate (bool) 120 | isScale (bool) 121 | interval (int) 122 | """ 123 | start = cmds.currentTime(q=1) 124 | sel = cmds.ls(sl=1, ap=1) 125 | if not sel: 126 | om.MGlobal.displayError("Please select some tranform nodes.") 127 | return 128 | 129 | attrData = {} 130 | for node in sel: 131 | if not attrData.has_key(node): 132 | attrData[node] = [] 133 | 134 | if isRotate: 135 | [attrData[node].append([attr, rotateMin, rotateMax]) for attr in rotateAttrs] 136 | 137 | if isTranslate: 138 | [attrData[node].append([attr, translateMin, translateMax]) for attr in translateAttrs] 139 | 140 | if isScale: 141 | [attrData[node].append([attr, scaleMin, scaleMax]) for attr in scaleAttrs] 142 | 143 | currTime = attrsSampling(attrData, interval) 144 | 145 | end = currTime-1 146 | utils.trimTimeRange(start, end) 147 | cmds.currentTime(start) 148 | 149 | #---------------------------------------------------------------------- 150 | def getBlendshapeFromSelection(): 151 | """ 152 | Returns: 153 | str 154 | """ 155 | try: 156 | return cmds.ls(sl=1, type='blendShape')[0] 157 | except: 158 | om.MGlobal.displayError("No blendshape found in your selection.") 159 | return 160 | 161 | #---------------------------------------------------------------------- 162 | def deleteAnimations(): 163 | """""" 164 | animCurveTypes = ['animCurveTU', 'animCurveTA', 'animCurveTL', 'animCurveTT'] 165 | 166 | sel = cmds.ls(sl=1, ap=1) 167 | if not sel: 168 | om.MGlobal.displayError("Please select something first.") 169 | return 170 | 171 | for node in sel: 172 | connects = cmds.listConnections(node, s=1, d=0, scn=1) 173 | animCurves = cmds.ls(connects, type=animCurveTypes) 174 | cmds.delete(animCurves) 175 | 176 | 177 | if __name__ == '__main__': 178 | node = 'locator1' 179 | bsNode = 'headGEO_IMBS' 180 | attr = 'tx' 181 | maxVal = 1 182 | minVal = -1 183 | interval = 1 184 | sel = cmds.ls(sl=1, ap=1) 185 | for s in sel: 186 | rotateSampling(s, -90, 90, interval) 187 | currTime = translateSampling(s, minVal, maxVal, interval) 188 | cmds.currentTime(currTime+1) 189 | # currTime = blendShapeSampling(bsNode, interval) 190 | # cmds.currentTime(currTime) -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/core/utils.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import maya.cmds as cmds 6 | import maya.mel as mel 7 | import maya.OpenMaya as om 8 | import maya.OpenMayaAnim as oma 9 | 10 | 11 | 12 | # Create exception class 13 | class UserInputError(Exception): pass 14 | 15 | #---------------------------------------------------------------------- 16 | def mayaVersion(): 17 | """ 18 | need to manage this better and use the API version, 19 | eg: 2013.5 returns 2013 20 | """ 21 | return mel.eval('getApplicationVersionAsFloat') 22 | 23 | #---------------------------------------------------------------------- 24 | def getDependNode(name): 25 | """ 26 | Args: 27 | name (str) 28 | 29 | Returns: 30 | MOBject 31 | """ 32 | selList = om.MSelectionList() 33 | selList.add (name) 34 | node = om.MObject() 35 | selList.getDependNode(0, node) 36 | return node 37 | 38 | #---------------------------------------------------------------------- 39 | def getDagPath(name): 40 | """ 41 | Args: 42 | name (str) 43 | 44 | Returns: 45 | MDagPath 46 | """ 47 | selList = om.MSelectionList() 48 | selList.add (name) 49 | dagPath = om.MDagPath() 50 | selList.getDagPath(0, dagPath) 51 | return dagPath 52 | 53 | #---------------------------------------------------------------------- 54 | def getComponent(name): 55 | """ 56 | Args: 57 | name (str) 58 | 59 | Returns: 60 | MOBject 61 | """ 62 | selList = om.MSelectionList() 63 | selList.add (name) 64 | dagPath = om.MDagPath() 65 | component = om.MObject() 66 | selList.getDagPath(0, dagPath, component) 67 | return component 68 | 69 | #---------------------------------------------------------------------- 70 | def getDagPathComponents(compList): 71 | """ 72 | Args: 73 | compList (list) 74 | 75 | Returns: 76 | MObject 77 | """ 78 | 79 | currSel = cmds.ls(sl=1, l=1) 80 | cmds.select(compList, r=1) 81 | selList = om.MSelectionList() 82 | om.MGlobal.getActiveSelectionList(selList) 83 | dagPath = om.MDagPath() 84 | components = om.MObject() 85 | selList.getDagPath(0, dagPath, components) 86 | cmds.select(cl=1) 87 | try: 88 | cmds.select(currSel, r=1) 89 | except: 90 | pass 91 | return dagPath, components 92 | 93 | #---------------------------------------------------------------------- 94 | def findRelatedSkinCluster(geometry): 95 | ''' 96 | Return the skinCluster attached to the specified geometry 97 | 98 | Args: 99 | geometry (str): Geometry object/transform to query 100 | 101 | Returns: 102 | str 103 | ''' 104 | # Check geometry 105 | if not cmds.objExists(geometry): 106 | om.MGlobal.displayError('Object '+geometry+' does not exist!') 107 | return 108 | 109 | # Check transform 110 | if cmds.objectType(geometry) == 'transform': 111 | try: geometry = cmds.listRelatives(geometry,s=True,ni=True,pa=True)[0] 112 | except: 113 | om.MGlobal.displayError('Object %s has no deformable geometry!' % geometry) 114 | return 115 | 116 | # Determine skinCluster 117 | skin = mel.eval('findRelatedSkinCluster \"%s\"' % geometry) 118 | if not skin: 119 | skin = cmds.ls(cmds.listHistory(geometry, pdo=1, gl=1), type='skinCluster') 120 | if skin: skin = skin[0] 121 | if not skin: skin = None 122 | 123 | # Return result 124 | return skin 125 | 126 | #---------------------------------------------------------------------- 127 | def findRelatedDeltaMush(geometry): 128 | """ 129 | Return the delta mush deformer attached to the specified geometry 130 | 131 | Args: 132 | geometry (str): Geometry object/transform to query 133 | 134 | Returns: 135 | str 136 | """ 137 | # Check geometry 138 | if not cmds.objExists(geometry): 139 | raise Exception('Object '+geometry+' does not exist!') 140 | 141 | hist = cmds.listHistory(geometry, pdo=1, gl=1) 142 | try: 143 | if mayaVersion() >= 2016: 144 | return cmds.ls(hist, type=["deltaMush", "wbDeltaMush"])[0] 145 | else: 146 | return cmds.ls(hist, type="wbDeltaMush")[0] 147 | except: 148 | return None 149 | 150 | #---------------------------------------------------------------------- 151 | def trimTimeRange(start, end): 152 | """ 153 | Args: 154 | start (float) 155 | end (float) 156 | """ 157 | animCtrl = oma.MAnimControl() 158 | startTime = om.MTime(start) 159 | endTime = om.MTime(end) 160 | animCtrl.setAnimationStartEndTime (startTime, endTime) 161 | animCtrl.setMinMaxTime(startTime, endTime) 162 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/startup/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/startup/setup.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | __buildVersionID__ = '1.5.5' 5 | __ENVIRONMENT_NAME__ = "DEFORMATION_LEARNING_SOLVER" 6 | 7 | 8 | import sys 9 | import os 10 | import maya.cmds as cmds 11 | import maya.mel as mel 12 | import maya.OpenMayaUI as omui 13 | 14 | PYSIDE_VERSION = '-1' 15 | try: 16 | import PySide 17 | PYSIDE_VERSION = PySide.__version__ 18 | from PySide import QtGui, QtCore 19 | from PySide.QtGui import * 20 | from PySide.QtCore import * 21 | from shiboken import wrapInstance 22 | except ImportError: 23 | import PySide2 24 | PYSIDE_VERSION = PySide2.__version__ 25 | from PySide2 import QtGui, QtCore, QtWidgets 26 | from PySide2.QtGui import * 27 | from PySide2.QtCore import * 28 | from PySide2.QtWidgets import * 29 | from shiboken2 import wrapInstance 30 | 31 | import logging 32 | logging.basicConfig() 33 | log = logging.getLogger(__name__) 34 | log.setLevel(logging.INFO) 35 | 36 | 37 | # Static variables 38 | SCRIPT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)).replace('\\', '/') 39 | SSD_SOLVER_PLUGIN_BASE_NAME = "SSDSolverCmd" 40 | DELTA_MUSH_PLUGIN_BASE_NAME = "wbDeltaMushDeformer" 41 | MAIN_WINDOW = "DeformationLearningSolverWin" 42 | 43 | 44 | #---------------------------------------------------------------------- 45 | def getMayaWindow(): 46 | ptr = omui.MQtUtil.mainWindow() 47 | if ptr: 48 | return wrapInstance(long(ptr), QWidget) 49 | 50 | #---------------------------------------------------------------------- 51 | def show(): 52 | """""" 53 | from DLS.widget import mainWindow 54 | reload(mainWindow) 55 | 56 | if cmds.window(MAIN_WINDOW, ex=1): 57 | cmds.deleteUI(MAIN_WINDOW) 58 | 59 | parent = getMayaWindow() 60 | win = mainWindow.MainWindow(parent) 61 | 62 | win.setWindowFlags(Qt.Window) # Make this widget a standalone window 63 | # identify a Maya-managed floating window, 64 | # which handles the z order properly and saves its positions 65 | win.setProperty("saveWindowPref", True ) 66 | 67 | win.setAttribute(Qt.WA_DeleteOnClose) 68 | win.show() 69 | 70 | #---------------------------------------------------------------------- 71 | def getEnviron(): 72 | """""" 73 | return __ENVIRONMENT_NAME__ 74 | 75 | 76 | #---------------------------------------------------------------------- 77 | def loadSSDSolverPlugin(): 78 | """""" 79 | os = cmds.about(os=1) 80 | 81 | if os == 'win64': 82 | pluginName = '%s.mll' % (SSD_SOLVER_PLUGIN_BASE_NAME) 83 | elif os == 'mac': 84 | pluginName = '%s.bundle' % (SSD_SOLVER_PLUGIN_BASE_NAME) 85 | elif os == 'linux64': 86 | pluginName = '%s.so' % (SSD_SOLVER_PLUGIN_BASE_NAME) 87 | 88 | if not cmds.pluginInfo(pluginName, q=True, l=True ): 89 | try: 90 | cmds.loadPlugin(pluginName) 91 | pluginVers = cmds.pluginInfo(pluginName, q=1, v=1) 92 | log.info('Plug-in: %s v%s loaded success!' % (pluginName, pluginVers)) 93 | except: 94 | log.info('Plug-in: %s, was not found on MAYA_PLUG_IN_PATH.' % (pluginName)) 95 | else: 96 | pluginVers = cmds.pluginInfo(pluginName, q=1, v=1) 97 | log.info('Plug-in: %s v%s has been loaded!' % (pluginName, pluginVers)) 98 | 99 | #---------------------------------------------------------------------- 100 | def loadDeltaMushPlugin(): 101 | """""" 102 | os = cmds.about(os=1) 103 | 104 | if os == 'win64': 105 | pluginName = '%s.mll' % (DELTA_MUSH_PLUGIN_BASE_NAME) 106 | elif os == 'mac': 107 | pluginName = '%s.bundle' % (DELTA_MUSH_PLUGIN_BASE_NAME) 108 | elif os == 'linux64': 109 | pluginName = '%s.so' % (DELTA_MUSH_PLUGIN_BASE_NAME) 110 | 111 | if not cmds.pluginInfo(pluginName, q=True, l=True ): 112 | try: 113 | cmds.loadPlugin(pluginName) 114 | pluginVers = cmds.pluginInfo(pluginName, q=1, v=1) 115 | log.info('Plug-in: %s v%s loaded success!' % (pluginName, pluginVers)) 116 | except: 117 | log.info('Plug-in: %s, was not found on MAYA_PLUG_IN_PATH.' % (pluginName)) 118 | else: 119 | pluginVers = cmds.pluginInfo(pluginName, q=1, v=1) 120 | log.info('Plug-in: %s v%s has been loaded!' % (pluginName, pluginVers)) 121 | 122 | #---------------------------------------------------------------------- 123 | def loadPlugin(): 124 | """""" 125 | loadSSDSolverPlugin() 126 | loadDeltaMushPlugin() 127 | 128 | #---------------------------------------------------------------------- 129 | def mayaVersion(): 130 | """ 131 | need to manage this better and use the API version, 132 | eg: 2013.5 returns 2013 133 | """ 134 | return mel.eval('getApplicationVersionAsFloat') 135 | 136 | #---------------------------------------------------------------------- 137 | def getModulePath(): 138 | ''' 139 | Returns the Main path to the root module folder 140 | ''' 141 | return os.path.join(os.path.dirname(SCRIPT_DIRECTORY),'').replace('\\', '/') 142 | 143 | #---------------------------------------------------------------------- 144 | def getVersion(): 145 | return __buildVersionID__ 146 | 147 | #---------------------------------------------------------------------- 148 | def getAuthor(): 149 | return __author__ 150 | 151 | #---------------------------------------------------------------------- 152 | def getMainWindowName(): 153 | return MAIN_WINDOW 154 | 155 | # BOOT FUNCTS - Add and Build -------------------------------------------------------------- 156 | 157 | def addScriptsPath(path): 158 | ''' 159 | Add additional folders to the ScriptPath 160 | ''' 161 | scriptsPath = os.environ.get('MAYA_SCRIPT_PATH') 162 | 163 | if os.path.exists(path): 164 | if not path in scriptsPath: 165 | log.info('Adding To Script Paths : %s' % path) 166 | os.environ['MAYA_SCRIPT_PATH']+='%s%s' % (os.pathsep, path) 167 | else: 168 | log.info('Deformation Learning Script Path already setup : %s' % path) 169 | else: 170 | log.debug('Given Script Path is invalid : %s' % path) 171 | 172 | 173 | #========================================================================================= 174 | # BOOT CALL ------------------------------------------------------------------------------ 175 | #========================================================================================= 176 | 177 | def launch(): 178 | ''' 179 | Main entry point 180 | ''' 181 | log.info('Deformation Learning v%s : Author: %s' % (getVersion(), getAuthor())) 182 | log.info('Deformation Learning Setup Calls :: Booting from >> %s' % getModulePath()) 183 | 184 | # Add module to environment 185 | os.environ[__ENVIRONMENT_NAME__] = getModulePath() 186 | # addScriptsPath(os.environ[__ENVIRONMENT_NAME__]) 187 | 188 | # Load Plug-in 189 | loadPlugin() 190 | 191 | # launch UI 192 | show() 193 | 194 | log.info('Deformation Learning initialize Complete!') 195 | 196 | def interface(): 197 | show() 198 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/aboutDialog.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import os 6 | 7 | try: 8 | from PySide import QtGui, QtCore 9 | from PySide.QtGui import * 10 | from PySide.QtCore import * 11 | except ImportError: 12 | from PySide2 import QtGui, QtCore, QtWidgets 13 | from PySide2.QtGui import * 14 | from PySide2.QtCore import * 15 | from PySide2.QtWidgets import * 16 | 17 | from DLS.widget import utils 18 | 19 | 20 | uifile = os.path.join(utils.SCRIPT_DIRECTORY, "ui/aboutDialog.ui") 21 | 22 | 23 | ######################################################################## 24 | class AboutDialog(QDialog): 25 | """""" 26 | _TITLE = 'Utility' 27 | 28 | #---------------------------------------------------------------------- 29 | def __init__(self, parent=None): 30 | """Constructor""" 31 | super(AboutDialog, self).__init__(parent) 32 | utils.loadUi(uifile, self) 33 | self.initWidgets() 34 | 35 | #---------------------------------------------------------------------- 36 | def initWidgets(self): 37 | """""" 38 | cp = QDesktopWidget().screenGeometry().center() 39 | self.move(cp) 40 | 41 | 42 | #---------------------------------------------------------------------- 43 | def main(): 44 | import sys 45 | app = QApplication(sys.argv) 46 | window = AboutDialog() 47 | window.show() 48 | app.exec_() 49 | 50 | 51 | if __name__ == "__main__": 52 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/axisOptionWindow.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import os 6 | 7 | try: 8 | from PySide import QtGui, QtCore 9 | from PySide.QtGui import * 10 | from PySide.QtCore import * 11 | except ImportError: 12 | from PySide2 import QtGui, QtCore, QtWidgets 13 | from PySide2.QtGui import * 14 | from PySide2.QtCore import * 15 | from PySide2.QtWidgets import * 16 | 17 | from DLS.widget import utils 18 | from DLS.widget import baseOptionWindow 19 | 20 | #reload(baseOptionWindow) 21 | 22 | 23 | uifile = os.path.join(utils.SCRIPT_DIRECTORY, "ui/axisWindow.ui") 24 | cfgfile = os.path.join(utils.SCRIPT_DIRECTORY, "config.ini") 25 | 26 | 27 | ######################################################################## 28 | class AxisOptionWindow(baseOptionWindow.BaseOptionWindow): 29 | """""" 30 | _TITLE = 'Axis Options' 31 | 32 | #---------------------------------------------------------------------- 33 | def __init__(self, parent=None): 34 | """Constructor""" 35 | super(AxisOptionWindow, self).__init__(parent) 36 | #utils.loadUi(uifile, self) 37 | #self.initWidgets() 38 | 39 | #---------------------------------------------------------------------- 40 | def initWidgets(self): 41 | """""" 42 | self.readSettings() 43 | 44 | self.setWindowTitle(self._TITLE) 45 | cp = QDesktopWidget().screenGeometry().center() 46 | self.move(cp) 47 | 48 | # Add actions 49 | actionReset = self.findChild(QAction, "actionReset") 50 | if actionReset != None: 51 | actionReset.triggered.connect(self.resetSettings) 52 | 53 | #---------------------------------------------------------------------- 54 | def isX(self): 55 | """""" 56 | x_chk = self.findChild(QCheckBox, "x_chk") 57 | if x_chk != None: 58 | return x_chk.isChecked() 59 | return True 60 | 61 | #---------------------------------------------------------------------- 62 | def setX(self, val): 63 | """""" 64 | x_chk = self.findChild(QCheckBox, "x_chk") 65 | if x_chk != None: 66 | x_chk.setChecked(val) 67 | 68 | #---------------------------------------------------------------------- 69 | def isY(self): 70 | """""" 71 | y_chk = self.findChild(QCheckBox, "y_chk") 72 | if y_chk != None: 73 | return y_chk.isChecked() 74 | return True 75 | 76 | #---------------------------------------------------------------------- 77 | def setY(self, val): 78 | """""" 79 | y_chk = self.findChild(QCheckBox, "y_chk") 80 | if y_chk != None: 81 | y_chk.setChecked(val) 82 | 83 | #---------------------------------------------------------------------- 84 | def isZ(self): 85 | """""" 86 | z_chk = self.findChild(QCheckBox, "z_chk") 87 | if z_chk != None: 88 | return z_chk.isChecked() 89 | return True 90 | 91 | #---------------------------------------------------------------------- 92 | def setZ(self, val): 93 | """""" 94 | z_chk = self.findChild(QCheckBox, "z_chk") 95 | if z_chk != None: 96 | z_chk.setChecked(val) 97 | 98 | 99 | ######################################################################## 100 | class TranslateAxisOptionWindow(AxisOptionWindow): 101 | """""" 102 | _TITLE = 'Translate Axis Options' 103 | 104 | #---------------------------------------------------------------------- 105 | def __init__(self, parent=None): 106 | """Constructor""" 107 | super(TranslateAxisOptionWindow, self).__init__(parent) 108 | utils.loadUi(uifile, self) 109 | self.initWidgets() 110 | 111 | #---------------------------------------------------------------------- 112 | def resetSettings(self): 113 | settings = QSettings(cfgfile, QSettings.IniFormat) 114 | 115 | settings.beginGroup("Default") 116 | self.setX(bool(int(settings.value("translateX")))) 117 | self.setY(bool(int(settings.value("translateY")))) 118 | self.setZ(bool(int(settings.value("translateZ")))) 119 | settings.endGroup() 120 | 121 | #---------------------------------------------------------------------- 122 | def readSettings(self): 123 | settings = QSettings(cfgfile, QSettings.IniFormat) 124 | 125 | settings.beginGroup("Custom") 126 | self.setX(bool(int(settings.value("translateX")))) 127 | self.setY(bool(int(settings.value("translateY")))) 128 | self.setZ(bool(int(settings.value("translateZ")))) 129 | settings.endGroup() 130 | 131 | #---------------------------------------------------------------------- 132 | def writeSettings(self): 133 | settings = QSettings(cfgfile, QSettings.IniFormat) 134 | 135 | settings.beginGroup("Custom") 136 | settings.setValue("translateX", int(self.isX())) 137 | settings.setValue("translateY", int(self.isY())) 138 | settings.setValue("translateZ", int(self.isZ())) 139 | settings.endGroup() 140 | 141 | 142 | ######################################################################## 143 | class RotateAxisOptionWindow(AxisOptionWindow): 144 | """""" 145 | _TITLE = 'Rotate Axis Options' 146 | 147 | #---------------------------------------------------------------------- 148 | def __init__(self, parent=None): 149 | """Constructor""" 150 | super(RotateAxisOptionWindow, self).__init__(parent) 151 | utils.loadUi(uifile, self) 152 | self.initWidgets() 153 | 154 | #---------------------------------------------------------------------- 155 | def resetSettings(self): 156 | settings = QSettings(cfgfile, QSettings.IniFormat) 157 | 158 | settings.beginGroup("Default") 159 | self.setX(bool(int(settings.value("rotateX")))) 160 | self.setY(bool(int(settings.value("rotateY")))) 161 | self.setZ(bool(int(settings.value("rotateZ")))) 162 | settings.endGroup() 163 | 164 | #---------------------------------------------------------------------- 165 | def readSettings(self): 166 | settings = QSettings(cfgfile, QSettings.IniFormat) 167 | 168 | settings.beginGroup("Custom") 169 | self.setX(bool(int(settings.value("rotateX")))) 170 | self.setY(bool(int(settings.value("rotateY")))) 171 | self.setZ(bool(int(settings.value("rotateZ")))) 172 | settings.endGroup() 173 | 174 | #---------------------------------------------------------------------- 175 | def writeSettings(self): 176 | settings = QSettings(cfgfile, QSettings.IniFormat) 177 | 178 | settings.beginGroup("Custom") 179 | settings.setValue("rotateX", int(self.isX())) 180 | settings.setValue("rotateY", int(self.isY())) 181 | settings.setValue("rotateZ", int(self.isZ())) 182 | settings.endGroup() 183 | 184 | 185 | ######################################################################## 186 | class ScaleAxisOptionWindow(AxisOptionWindow): 187 | """""" 188 | _TITLE = 'Scale Axis Options' 189 | 190 | #---------------------------------------------------------------------- 191 | def __init__(self, parent=None): 192 | """Constructor""" 193 | super(ScaleAxisOptionWindow, self).__init__(parent) 194 | utils.loadUi(uifile, self) 195 | self.initWidgets() 196 | 197 | #---------------------------------------------------------------------- 198 | def resetSettings(self): 199 | settings = QSettings(cfgfile, QSettings.IniFormat) 200 | 201 | settings.beginGroup("Default") 202 | self.setX(bool(int(settings.value("scaleX")))) 203 | self.setY(bool(int(settings.value("scaleY")))) 204 | self.setZ(bool(int(settings.value("scaleZ")))) 205 | settings.endGroup() 206 | 207 | #---------------------------------------------------------------------- 208 | def readSettings(self): 209 | settings = QSettings(cfgfile, QSettings.IniFormat) 210 | 211 | settings.beginGroup("Custom") 212 | self.setX(bool(int(settings.value("scaleX")))) 213 | self.setY(bool(int(settings.value("scaleY")))) 214 | self.setZ(bool(int(settings.value("scaleZ")))) 215 | settings.endGroup() 216 | 217 | #---------------------------------------------------------------------- 218 | def writeSettings(self): 219 | settings = QSettings(cfgfile, QSettings.IniFormat) 220 | 221 | settings.beginGroup("Custom") 222 | settings.setValue("scaleX", int(self.isX())) 223 | settings.setValue("scaleY", int(self.isY())) 224 | settings.setValue("scaleZ", int(self.isZ())) 225 | settings.endGroup() 226 | 227 | #---------------------------------------------------------------------- 228 | def main(): 229 | import sys 230 | app = QApplication(sys.argv) 231 | window = ScaleAxisOptionWindow() 232 | window.show() 233 | app.exec_() 234 | 235 | 236 | if __name__ == "__main__": 237 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/baseOptionWindow.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | try: 6 | from PySide import QtGui, QtCore 7 | from PySide.QtGui import * 8 | from PySide.QtCore import * 9 | except ImportError: 10 | from PySide2 import QtGui, QtCore, QtWidgets 11 | from PySide2.QtGui import * 12 | from PySide2.QtCore import * 13 | from PySide2.QtWidgets import * 14 | 15 | 16 | ######################################################################## 17 | class BaseOptionWindow(QMainWindow): 18 | """""" 19 | _TITLE = '' 20 | 21 | #---------------------------------------------------------------------- 22 | def __init__(self, parent = None): 23 | """Constructor""" 24 | super(BaseOptionWindow, self).__init__(parent) 25 | #QMainWindow.__init__(self, parent) 26 | #self.initWidgets() 27 | 28 | #---------------------------------------------------------------------- 29 | def initWidgets(self): 30 | NotImplemented 31 | 32 | #---------------------------------------------------------------------- 33 | def resetSettings(self): 34 | NotImplemented 35 | 36 | #---------------------------------------------------------------------- 37 | def readSettings(self): 38 | NotImplemented 39 | 40 | #---------------------------------------------------------------------- 41 | def writeSettings(self): 42 | NotImplemented 43 | 44 | #---------------------------------------------------------------------- 45 | @Slot() 46 | def on_save_btn_clicked(self): 47 | self.writeSettings() 48 | self.close() 49 | 50 | #---------------------------------------------------------------------- 51 | @Slot() 52 | def on_cancel_btn_clicked(self): 53 | self.close() 54 | 55 | #---------------------------------------------------------------------- 56 | def showUI(self): 57 | """""" 58 | self.readSettings() 59 | self.show() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/baseTab.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | try: 6 | from PySide import QtGui, QtCore 7 | from PySide.QtGui import * 8 | from PySide.QtCore import * 9 | from PySide.QtUiTools import QUiLoader 10 | except ImportError: 11 | from PySide2 import QtGui, QtCore, QtWidgets 12 | from PySide2.QtGui import * 13 | from PySide2.QtCore import * 14 | from PySide2.QtWidgets import * 15 | from PySide2.QtUiTools import QUiLoader 16 | 17 | from DLS.widget import utils 18 | #reload(utils) 19 | 20 | 21 | ######################################################################## 22 | class BaseTab(QWidget): 23 | _TITLE = 'Untitle' 24 | 25 | #---------------------------------------------------------------------- 26 | def __init__(self, parent=None): 27 | super(BaseTab, self).__init__(parent) 28 | #self.parent = parent 29 | #loader = QUiLoader() 30 | #f = QFile(uifile) 31 | #f.open(QFile.ReadOnly) 32 | #widget = loader.load(f, self) 33 | #f.close() 34 | 35 | #layout = QVBoxLayout() 36 | #layout.addWidget(widget) 37 | #self.setLayout(layout) 38 | #utils.loadUi(uifile) 39 | 40 | #---------------------------------------------------------------------- 41 | def title(self): 42 | return self._TITLE 43 | 44 | #---------------------------------------------------------------------- 45 | def readSettings(self): 46 | pass 47 | 48 | #---------------------------------------------------------------------- 49 | def writeSettings(self): 50 | pass 51 | 52 | #---------------------------------------------------------------------- 53 | def resetSettings(self): 54 | pass 55 | 56 | #---------------------------------------------------------------------- 57 | def closeEvent(self, event): 58 | """""" 59 | self.writeSettings() 60 | event.accept() 61 | 62 | 63 | def main(): 64 | import sys 65 | app = QApplication(sys.argv) 66 | window = BaseTab() 67 | window.show() 68 | app.exec_() 69 | 70 | 71 | if __name__ == "__main__": 72 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/config.ini: -------------------------------------------------------------------------------- 1 | [Custom] 2 | epsilon=1 3 | isBlendshape=0 4 | isCustomAttrs=0 5 | isDeleteDeltaMush=0 6 | isKeepOriginal=1 7 | isRotate=1 8 | isScale=0 9 | isTranslate=0 10 | maxInfs=4 11 | maxIters=10 12 | numBones=1 13 | pruneBeblow=0 14 | rotateMax=90 15 | rotateMin=-90 16 | rotateX=1 17 | rotateY=1 18 | rotateZ=1 19 | scaleMax=1 20 | scaleMin=-1 21 | scaleX=1 22 | scaleY=1 23 | scaleZ=1 24 | skipTips=1 25 | translateMax=1 26 | translateMin=-1 27 | translateX=1 28 | translateY=1 29 | translateZ=1 30 | useBuildInDeltaMush=0 31 | 32 | [Default] 33 | blendshapeName= 34 | epsilon=1 35 | isBlendshape=0 36 | isCustomAttrs=0 37 | isDeleteDeltaMush=0 38 | isKeepOriginal=1 39 | isRotate=1 40 | isScale=0 41 | isTranslate=0 42 | maxInfs=4 43 | maxIters=10 44 | numBones=1 45 | pruneBeblow=0.0 46 | rotateMax=90.0 47 | rotateMin=-90.0 48 | rotateX=1 49 | rotateY=1 50 | rotateZ=1 51 | scaleMax=1.0 52 | scaleMin=-1.0 53 | scaleX=1 54 | scaleY=1 55 | scaleZ=1 56 | skipTips=1 57 | translateMax=1.0 58 | translateMin=-1.0 59 | translateX=1 60 | translateY=1 61 | translateZ=1 62 | useBuildInDeltaMush=0 63 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/customAttributeEditor.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import os 6 | 7 | try: 8 | from PySide import QtGui, QtCore 9 | from PySide.QtGui import * 10 | from PySide.QtCore import * 11 | except ImportError: 12 | from PySide2 import QtGui, QtCore, QtWidgets 13 | from PySide2.QtGui import * 14 | from PySide2.QtCore import * 15 | from PySide2.QtWidgets import * 16 | 17 | import maya.cmds as cmds 18 | import maya.OpenMaya as om 19 | 20 | 21 | from DLS.widget import baseOptionWindow 22 | from DLS.widget import utils 23 | from DLS.startup import setup 24 | 25 | 26 | uifile = os.path.join(utils.SCRIPT_DIRECTORY, "ui/customAttributeEditor.ui") 27 | cfgfile = os.path.join(utils.SCRIPT_DIRECTORY, "config.ini") 28 | 29 | 30 | ######################################################################## 31 | class CustomAttributeEditor(baseOptionWindow.BaseOptionWindow): 32 | """ 33 | self.data = {node1: [[attr1, min, max], [attr2, min, max], ...], 34 | node2: [[attr1, min, max], [attr2, min, max], ...], 35 | ...} 36 | """ 37 | 38 | _TITLE = 'Custom Attributes Editor' 39 | _HEAD_LABLE = ['Attribute','Min','Max'] 40 | 41 | #---------------------------------------------------------------------- 42 | def __init__(self, data, parent=None): 43 | """Constructor""" 44 | super(CustomAttributeEditor, self).__init__(parent) 45 | utils.loadUi(uifile, self) 46 | self.parent = parent 47 | self.table = None 48 | self.attrs = [] 49 | self.minVals = [] 50 | self.maxVals = [] 51 | self.data = data 52 | 53 | self.initWidgets() 54 | 55 | #---------------------------------------------------------------------- 56 | def initWidgets(self): 57 | """""" 58 | self.setWindowTitle(self._TITLE) 59 | cp = QDesktopWidget().screenGeometry().center() 60 | self.move(cp) 61 | 62 | # Set table 63 | self.table = self.findChild(QTableWidget, "data_table") 64 | self.table.setColumnCount(3) 65 | self.table.setHorizontalHeaderLabels(self._HEAD_LABLE) 66 | self.table.setAlternatingRowColors(True) 67 | self.table.setColumnWidth(1, 56) 68 | self.table.setColumnWidth(2, 56) 69 | 70 | if setup.PYSIDE_VERSION < 2.0: 71 | self.table.horizontalHeader().setResizeMode(0, QHeaderView.Stretch) 72 | else: 73 | self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) 74 | 75 | # Fill table 76 | i = 0 77 | for node, attrVals in self.data.iteritems(): 78 | for vals in attrVals: 79 | attr, minVal, maxVal = vals 80 | name = "%s.%s" % (node, attr) 81 | self.appendRow() 82 | self.setRow(i, [name, minVal, maxVal]) 83 | i += 1 84 | 85 | # Set delete row action 86 | delAction = QAction(self) 87 | delAction.setObjectName("del_action") 88 | delAction.triggered.connect(self.removeRow) 89 | delAction.setShortcut(QKeySequence.Delete) 90 | delAction.setShortcutContext(Qt.WidgetWithChildrenShortcut) 91 | self.addAction(delAction) 92 | 93 | # Set signal functions 94 | self.table.itemChanged.connect(self.setItems) 95 | 96 | #---------------------------------------------------------------------- 97 | def numRow(self): 98 | return self.table.rowCount() 99 | 100 | #---------------------------------------------------------------------- 101 | def numColumn(self): 102 | return self.table.columnCount() 103 | 104 | #---------------------------------------------------------------------- 105 | def appendRow(self): 106 | self.table.insertRow(self.numRow()) 107 | for i in xrange(self.numColumn()): 108 | self.table.setItem(self.numRow()-1, i, QTableWidgetItem('0')) 109 | 110 | #---------------------------------------------------------------------- 111 | def setRow(self, row, data): 112 | """ 113 | Args: 114 | row (int) 115 | data (list) 116 | """ 117 | for i in xrange(len(data)): 118 | self.table.item(row, i).setText(str(data[i])) 119 | 120 | #---------------------------------------------------------------------- 121 | def getDataOnRow(self, row): 122 | """ 123 | Args: 124 | row (int) 125 | """ 126 | data = [] 127 | for i in xrange(self.numColumn()): 128 | val = self.table.item(row, i).text() 129 | if i > 0: val = float(val) 130 | data.append(val) 131 | return data 132 | 133 | #---------------------------------------------------------------------- 134 | def setItems(self, item): 135 | """ 136 | Args: 137 | item (QTableWidgetItem) 138 | """ 139 | self.table.blockSignals(True) 140 | 141 | value = item.text() 142 | dataType = item.type() 143 | for cellIdx in self.table.selectedIndexes(): 144 | currCell = self.table.item(cellIdx.row(), cellIdx.column()) 145 | if currCell.type() == dataType: 146 | currCell.setText(value) 147 | 148 | self.table.blockSignals(False) 149 | 150 | #---------------------------------------------------------------------- 151 | def removeRow(self): 152 | """""" 153 | selRanges = self.table.selectedRanges() 154 | for sel in reversed(selRanges): 155 | if sel.columnCount() == 3: 156 | for i in xrange(sel.bottomRow(), sel.topRow()-1, -1): 157 | self.table.removeRow(i) 158 | else: 159 | # Set each cell's value to 0 160 | for i in xrange(sel.topRow(), sel.bottomRow()+1): 161 | for j in xrange(sel.leftColumn(), sel.rightColumn()+1): 162 | item = QTableWidgetItem('0') 163 | self.table.setItem(i, j, item) 164 | 165 | #---------------------------------------------------------------------- 166 | def saveData(self): 167 | """""" 168 | self.data.clear() 169 | for i in xrange(self.numRow()): 170 | nodeAttr, minVal, maxVal = self.getDataOnRow(i) 171 | node, attr = nodeAttr.split('.') 172 | if not self.data.has_key(node): 173 | self.data[node] = [] 174 | self.data[node].append([attr, minVal, maxVal]) 175 | 176 | #---------------------------------------------------------------------- 177 | @Slot() 178 | def on_add_btn_clicked(self): 179 | 180 | selNodes = cmds.ls(sl=1, ap=1) 181 | if not selNodes: 182 | om.MGlobal.displayError("Please select some nodes and attributes.") 183 | return 184 | 185 | selAttrs = (cmds.channelBox("mainChannelBox", q=1, sma=1) or []) \ 186 | + (cmds.channelBox("mainChannelBox", q=1, sha=1) or []) \ 187 | + (cmds.channelBox("mainChannelBox", q=1, ssa=1) or []) \ 188 | + (cmds.channelBox("mainChannelBox", q=1, soa=1) or []) 189 | 190 | if not selAttrs: 191 | selAttrs = cmds.listAttr(selNodes, v=1, k=1, sn=1) 192 | selAttrs = list(set(selAttrs)) 193 | try: 194 | selAttrs.remove('v') 195 | except: 196 | pass 197 | 198 | self.table.clearSelection() 199 | 200 | for node in selNodes: 201 | for attr in selAttrs: 202 | name = "%s.%s" % (node, attr) 203 | minVal, maxVal = 0.0, 1.0 204 | hasMinVal, hasMaxVal = False, False 205 | 206 | if not cmds.objExists(name): 207 | continue 208 | 209 | # Set minVal 210 | if cmds.attributeQuery(attr, node=node, minExists=1): 211 | minVal = cmds.attributeQuery(attr, node=node, min=1)[0] 212 | hasMinVal = True 213 | 214 | if cmds.attributeQuery(attr, node=node, softMinExists=1): 215 | minVal = cmds.attributeQuery(attr, node=node, smn=1)[0] 216 | hasMinVal = True 217 | 218 | # Set maxVal 219 | if cmds.attributeQuery(attr, node=node, maxExists=1): 220 | maxVal = cmds.attributeQuery(attr, node=node, max=1)[0] 221 | hasMaxVal = True 222 | 223 | if cmds.attributeQuery(attr, node=node, softMaxExists=1): 224 | maxVal = cmds.attributeQuery(attr, node=node, smx=1)[0] 225 | hasMaxVal = True 226 | 227 | currVal = cmds.getAttr(name) 228 | if hasMinVal: minVal = minVal - currVal 229 | if hasMaxVal: maxVal = maxVal - currVal 230 | 231 | self.appendRow() 232 | self.setRow(self.numRow()-1, [name, minVal, maxVal]) 233 | 234 | #---------------------------------------------------------------------- 235 | @Slot() 236 | def on_clear_btn_clicked(self): 237 | for i in xrange(self.numRow()-1, -1, -1): 238 | self.table.removeRow(i) 239 | 240 | #---------------------------------------------------------------------- 241 | @Slot() 242 | def on_save_btn_clicked(self): 243 | self.saveData() 244 | self.close() 245 | 246 | 247 | 248 | #---------------------------------------------------------------------- 249 | def main(): 250 | import sys 251 | app = QApplication(sys.argv) 252 | window = CustomAttributeEditor([]) 253 | window.show() 254 | app.exec_() 255 | 256 | 257 | if __name__ == "__main__": 258 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/learningTab.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import os 6 | 7 | try: 8 | from PySide import QtGui, QtCore 9 | from PySide.QtGui import * 10 | from PySide.QtCore import * 11 | except ImportError: 12 | from PySide2 import QtGui, QtCore, QtWidgets 13 | from PySide2.QtGui import * 14 | from PySide2.QtCore import * 15 | from PySide2.QtWidgets import * 16 | 17 | import maya.cmds as cmds 18 | 19 | from DLS.widget import baseTab 20 | from DLS.widget import utils 21 | 22 | from DLS.core import learningFunc 23 | 24 | 25 | reload(learningFunc) 26 | #reload(baseTab) 27 | #reload(utils) 28 | 29 | 30 | TAB = '' 31 | uifile = os.path.join(utils.SCRIPT_DIRECTORY, "ui/learningTab.ui") 32 | cfgfile = os.path.join(utils.SCRIPT_DIRECTORY, "config.ini") 33 | ENABLE = True 34 | INDEX = 1 35 | 36 | 37 | ######################################################################## 38 | class LearningTab(baseTab.BaseTab): 39 | """""" 40 | _TITLE = 'Learning' 41 | 42 | #---------------------------------------------------------------------- 43 | def __init__(self, parent=None): 44 | """Constructor""" 45 | super(LearningTab, self).__init__(parent) 46 | utils.loadUi(uifile, self) 47 | self.initWidgets() 48 | 49 | #---------------------------------------------------------------------- 50 | def initWidgets(self): 51 | """""" 52 | self.readSettings() 53 | 54 | # Set transformation widgets 55 | doubleVal = QDoubleValidator(decimals=3, parent=self) 56 | 57 | # Set time range widgets 58 | timeSlider_rbtn = self.findChild(QRadioButton, "timeSlider_rbtn") 59 | if timeSlider_rbtn != None: 60 | timeSlider_rbtn.setChecked(True) 61 | 62 | startEnd_rbtn = self.findChild(QRadioButton, "startEnd_rbtn") 63 | if startEnd_rbtn != None: 64 | startEnd_rbtn.setChecked(False) 65 | 66 | startTime_edit = self.findChild(QLineEdit, "startTime_edit") 67 | if startTime_edit != None: 68 | startTime_edit.setEnabled(False) 69 | startTime_edit.setValidator(doubleVal) 70 | 71 | endTime_edit = self.findChild(QLineEdit, "endTime_edit") 72 | if endTime_edit != None: 73 | endTime_edit.setEnabled(False) 74 | endTime_edit.setValidator(doubleVal) 75 | 76 | #---------------------------------------------------------------------- 77 | def getNumBones(self): 78 | """""" 79 | numBones_spn = self.findChild(QSpinBox, "numBones_spn") 80 | if numBones_spn != None: 81 | return numBones_spn.value() 82 | return 1 83 | 84 | #---------------------------------------------------------------------- 85 | def setNumBones(self, val): 86 | """""" 87 | numBones_spn = self.findChild(QSpinBox, "numBones_spn") 88 | if numBones_spn != None: 89 | numBones_spn.setValue(val) 90 | 91 | #---------------------------------------------------------------------- 92 | def getMaxInfs(self): 93 | """""" 94 | maxInfs_spn = self.findChild(QSpinBox, "maxInfs_spn") 95 | if maxInfs_spn != None: 96 | return maxInfs_spn.value() 97 | return 4 98 | 99 | #---------------------------------------------------------------------- 100 | def setMaxInfs(self, val): 101 | """""" 102 | maxInfs_spn = self.findChild(QSpinBox, "maxInfs_spn") 103 | if maxInfs_spn != None: 104 | maxInfs_spn.setValue(val) 105 | 106 | #---------------------------------------------------------------------- 107 | def getEpsilon(self): 108 | """""" 109 | epsilon_spn = self.findChild(QDoubleSpinBox, "epsilon_spn") 110 | if epsilon_spn != None: 111 | return epsilon_spn.value() 112 | return 1.0 113 | 114 | #---------------------------------------------------------------------- 115 | def setEpsilon(self, val): 116 | """""" 117 | epsilon_spn = self.findChild(QDoubleSpinBox, "epsilon_spn") 118 | if epsilon_spn != None: 119 | epsilon_spn.setValue(val) 120 | 121 | #---------------------------------------------------------------------- 122 | def getMaxIters(self): 123 | """""" 124 | maxIters_spn = self.findChild(QSpinBox, "maxIters_spn") 125 | if maxIters_spn != None: 126 | return maxIters_spn.value() 127 | 128 | #---------------------------------------------------------------------- 129 | def setMaxIters(self, val): 130 | """""" 131 | maxIters_spn = self.findChild(QSpinBox, "maxIters_spn") 132 | if maxIters_spn != None: 133 | maxIters_spn.setValue(val) 134 | 135 | #---------------------------------------------------------------------- 136 | def getTargetMesh(self): 137 | """""" 138 | targetMesh_edit = self.findChild(QLineEdit, "targetMesh_edit") 139 | if targetMesh_edit != None: 140 | return str(targetMesh_edit.text()) 141 | 142 | #---------------------------------------------------------------------- 143 | def setTargetMesh(self, val): 144 | """""" 145 | targetMesh_edit = self.findChild(QLineEdit, "targetMesh_edit") 146 | if targetMesh_edit != None: 147 | targetMesh_edit.setText(val) 148 | 149 | #---------------------------------------------------------------------- 150 | def isAlternativeUpdate(self): 151 | """""" 152 | alternativeUpdate_chk = self.findChild(QCheckBox, "alternativeUpdate_chk") 153 | if alternativeUpdate_chk != None: 154 | return alternativeUpdate_chk.isChecked() 155 | return True 156 | 157 | #---------------------------------------------------------------------- 158 | def setAlternativeUpdate(self, val): 159 | """""" 160 | alternativeUpdate_chk = self.findChild(QCheckBox, "alternativeUpdate_chk") 161 | if alternativeUpdate_chk != None: 162 | alternativeUpdate_chk.setChecked(val) 163 | 164 | #---------------------------------------------------------------------- 165 | def getStartTime(self): 166 | """""" 167 | startTime_edit = self.findChild(QLineEdit, "startTime_edit") 168 | if startTime_edit != None: 169 | return float(startTime_edit.text()) 170 | return 0.0 171 | 172 | #---------------------------------------------------------------------- 173 | def getEndTime(self): 174 | """""" 175 | endTime_edit = self.findChild(QLineEdit, "endTime_edit") 176 | if endTime_edit != None: 177 | return float(endTime_edit.text()) 178 | return 0.0 179 | 180 | #---------------------------------------------------------------------- 181 | def isTimeSlider(self): 182 | """""" 183 | timeSlider_rbtn = self.findChild(QRadioButton, "timeSlider_rbtn") 184 | if timeSlider_rbtn != None: 185 | return timeSlider_rbtn.isChecked() 186 | return True 187 | 188 | #---------------------------------------------------------------------- 189 | def isStartEnd(self): 190 | """""" 191 | startEnd_rbtn = self.findChild(QRadioButton, "startEnd_rbtn") 192 | if startEnd_rbtn != None: 193 | return startEnd_rbtn.isChecked() 194 | 195 | #---------------------------------------------------------------------- 196 | def getTimeRange(self): 197 | """""" 198 | if self.isStartEnd(): 199 | start = int(self.getStartTime()) 200 | end = int(self.getEndTime()) 201 | return start, end 202 | 203 | start = int(cmds.playbackOptions(q=1, min=1)) 204 | end = int(cmds.playbackOptions(q=1, max=1)) 205 | return start, end 206 | 207 | #---------------------------------------------------------------------- 208 | def readSettings(self): 209 | settings = QSettings(cfgfile, QSettings.IniFormat) 210 | 211 | settings.beginGroup("Custom") 212 | self.setNumBones(int(settings.value("numBones"))) 213 | self.setMaxInfs(int(settings.value("maxInfs"))) 214 | self.setEpsilon(float(settings.value("epsilon"))) 215 | self.setMaxIters(float(settings.value("maxIters"))) 216 | settings.endGroup() 217 | 218 | #---------------------------------------------------------------------- 219 | def writeSettings(self): 220 | settings = QSettings(cfgfile, QSettings.IniFormat) 221 | 222 | settings.beginGroup("Custom") 223 | settings.setValue("numBones", self.getNumBones()) 224 | settings.setValue("maxInfs", self.getMaxInfs()) 225 | settings.setValue("epsilon", float(self.getEpsilon())) 226 | settings.setValue("maxIters", self.getMaxIters()) 227 | settings.endGroup() 228 | 229 | #---------------------------------------------------------------------- 230 | def resetSettings(self): 231 | settings = QSettings(cfgfile, QSettings.IniFormat) 232 | 233 | settings.beginGroup("Default") 234 | self.setNumBones(int(settings.value("numBones"))) 235 | self.setMaxInfs(int(settings.value("maxInfs"))) 236 | self.setEpsilon(float(settings.value("epsilon"))) 237 | self.setMaxIters(int(settings.value("maxIters"))) 238 | settings.endGroup() 239 | 240 | self.setTargetMesh("") 241 | self.setAlternativeUpdate(False) 242 | 243 | #---------------------------------------------------------------------- 244 | @Slot() 245 | def on_loadTargetMesh_btn_clicked(self): 246 | mesh = learningFunc.getMeshFromSelection() 247 | self.setTargetMesh(mesh) 248 | 249 | #---------------------------------------------------------------------- 250 | @Slot(bool) 251 | def on_startEnd_rbtn_toggled(self, isChecked): 252 | startTime_edit = self.findChild(QLineEdit, "startTime_edit") 253 | if startTime_edit != None: 254 | startTime_edit.setEnabled(isChecked) 255 | 256 | endTime_edit = self.findChild(QLineEdit, "endTime_edit") 257 | if endTime_edit != None: 258 | endTime_edit.setEnabled(isChecked) 259 | 260 | #---------------------------------------------------------------------- 261 | @Slot() 262 | def on_solve_btn_clicked(self): 263 | settings = QSettings(cfgfile, QSettings.IniFormat) 264 | 265 | # Read global settings 266 | settings.beginGroup("Custom") 267 | pruneBelow = float(settings.value("pruneBeblow")) 268 | isKeepOriginal = bool(int(settings.value("isKeepOriginal"))) 269 | isDeleteDeltaMush = bool(int(settings.value("isDeleteDeltaMush"))) 270 | settings.endGroup() 271 | 272 | # Read local settings 273 | numBones = self.getNumBones() 274 | maxInfs = self.getMaxInfs() 275 | start, end = self.getTimeRange() 276 | maxIters = self.getMaxIters() 277 | epilon = self.getEpsilon() 278 | targetMesh = self.getTargetMesh() 279 | isAlternativeUpdate = self.isAlternativeUpdate() 280 | learningFunc.solve(numBones, maxInfs, targetMesh, isAlternativeUpdate, 281 | start, end, maxIters,isKeepOriginal, pruneBelow, 282 | epilon, isDeleteDeltaMush) 283 | 284 | #---------------------------------------------------------------------- 285 | @Slot() 286 | def on_measure_btn_clicked(self): 287 | start, end = self.getTimeRange() 288 | learningFunc.measure(start, end) 289 | 290 | 291 | #---------------------------------------------------------------------- 292 | def getTab(): 293 | """""" 294 | return LearningTab 295 | 296 | #---------------------------------------------------------------------- 297 | def main(): 298 | import sys 299 | app = QApplication(sys.argv) 300 | window = LearningTab() 301 | window.show() 302 | app.exec_() 303 | 304 | 305 | if __name__ == "__main__": 306 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/mainWindow.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import os 6 | try: 7 | from PySide import QtGui, QtCore 8 | from PySide.QtGui import * 9 | from PySide.QtCore import * 10 | except ImportError: 11 | from PySide2 import QtGui, QtCore, QtWidgets 12 | from PySide2.QtGui import * 13 | from PySide2.QtCore import * 14 | from PySide2.QtWidgets import * 15 | 16 | from DLS.widget import optionWindow 17 | from DLS.widget import aboutDialog 18 | from DLS.widget import utils 19 | from DLS.startup import setup 20 | from DLS.core import miscFunc, samplingFunc 21 | 22 | reload(miscFunc) 23 | reload(samplingFunc) 24 | #reload(optionWindow) 25 | #reload(aboutDialog) 26 | #reload(utils) 27 | 28 | cfgfile = os.path.join(utils.SCRIPT_DIRECTORY, "config.ini") 29 | 30 | ######################################################################## 31 | class MainWindow(QMainWindow): 32 | """""" 33 | _TITLE = 'Deformation Learning Solver' 34 | 35 | #---------------------------------------------------------------------- 36 | def __init__(self, parent=None): 37 | """Constructor""" 38 | super(MainWindow, self).__init__(parent) 39 | 40 | self.setObjectName(setup.getMainWindowName()) 41 | #self.parent = parent # this's extremely important! without this line 42 | # "Internal C++ object already deleted" happen 43 | self.initWidgets() 44 | 45 | #---------------------------------------------------------------------- 46 | def initWidgets(self): 47 | """""" 48 | self.setWindowTitle(self._TITLE) 49 | self.resize(100, 100) 50 | 51 | # Add actions 52 | openAbout = QAction("&About", self) 53 | openAbout.triggered.connect(self.showAbout) 54 | 55 | openOptions = QAction("&Options", self) 56 | openOptions.triggered.connect(self.showOption) 57 | 58 | resetSettings = QAction("&Reset", self) 59 | resetSettings.triggered.connect(self.resetSettings) 60 | 61 | selectAllBelow = QAction("Select All &Below", self) 62 | selectAllBelow.triggered.connect(self.selectAllBelowCmd) 63 | 64 | selectInfluenceJoints = QAction("Select Influence &Joints", self) 65 | selectInfluenceJoints.triggered.connect(self.selectInfluenceJointsCmd) 66 | 67 | applyRigidSkin = QAction("Apply &Rigid Skin", self) 68 | applyRigidSkin.triggered.connect(self.applyRigidSkinCmd) 69 | 70 | deleteAnimations = QAction("Delete &Animations", self) 71 | deleteAnimations.triggered.connect(self.deleteAnimationsCmd) 72 | 73 | applyDeltaMush = QAction("Apply &Delta Mush", self) 74 | applyDeltaMush.triggered.connect(self.applyDeltaMushCmd) 75 | 76 | # Add menu bar 77 | bar = self.menuBar() 78 | editMenu = bar.addMenu("&Edit") 79 | editMenu.addAction(openOptions) 80 | editMenu.addAction(resetSettings) 81 | 82 | toolMenu = bar.addMenu("&Tool") 83 | toolMenu.addAction(selectAllBelow) 84 | toolMenu.addAction(selectInfluenceJoints) 85 | toolMenu.addAction(applyRigidSkin) 86 | toolMenu.addSeparator() 87 | toolMenu.addAction(deleteAnimations) 88 | toolMenu.addSeparator() 89 | toolMenu.addAction(applyDeltaMush) 90 | 91 | helpMenu = bar.addMenu("&Help") 92 | helpMenu.addAction(openAbout) 93 | 94 | # Add base frame 95 | frame = QFrame(self) 96 | layout = QVBoxLayout(self) 97 | frame.setLayout(layout) 98 | 99 | tabWidget = QTabWidget(self) 100 | tabWidget.setObjectName("allFuncs_tab") 101 | layout.addWidget(tabWidget) 102 | 103 | self.setCentralWidget(frame) 104 | 105 | # Add tabs dynamically 106 | for cls in utils.findAllTabs(): 107 | tab = cls(self) 108 | self.addTab(tab, tabWidget) 109 | 110 | tabWidget.setCurrentIndex(0) 111 | 112 | #---------------------------------------------------------------------- 113 | def addTab(self, tab, tabWidget): 114 | """ 115 | adds tab object to tab UI, creating it's ui and attaching to main window 116 | """ 117 | tabWidget.addTab(tab, tab.title()) 118 | 119 | #---------------------------------------------------------------------- 120 | def showAbout(self): 121 | """""" 122 | aboutDialog.AboutDialog(self).show() 123 | 124 | #---------------------------------------------------------------------- 125 | def showOption(self): 126 | """""" 127 | optionWindow.OptionWindow(self).show() 128 | 129 | #---------------------------------------------------------------------- 130 | def resetSettings(self): 131 | allFuncs_tab = self.findChild(QTabWidget, "allFuncs_tab") 132 | for i in xrange(allFuncs_tab.count()): 133 | allFuncs_tab.widget(i).resetSettings() 134 | 135 | #---------------------------------------------------------------------- 136 | def selectAllBelowCmd(self): 137 | settings = QSettings(cfgfile, QSettings.IniFormat) 138 | 139 | settings.beginGroup("Custom") 140 | skipTips = bool(int(settings.value("skipTips"))) 141 | settings.endGroup() 142 | 143 | miscFunc.selectAllBelow(skipTips) 144 | 145 | #---------------------------------------------------------------------- 146 | def selectInfluenceJointsCmd(self): 147 | miscFunc.selectInfluenceJoints() 148 | 149 | #---------------------------------------------------------------------- 150 | def applyRigidSkinCmd(self): 151 | miscFunc.applyRigidSkin() 152 | 153 | #---------------------------------------------------------------------- 154 | def applyDeltaMushCmd(self): 155 | settings = QSettings(cfgfile, QSettings.IniFormat) 156 | 157 | settings.beginGroup("Custom") 158 | useBuildInDeltaMush = bool(int(settings.value("useBuildInDeltaMush"))) 159 | settings.endGroup() 160 | 161 | miscFunc.applyDeltaMush(useBuildIn=useBuildInDeltaMush) 162 | 163 | #---------------------------------------------------------------------- 164 | def deleteAnimationsCmd(self): 165 | samplingFunc.deleteAnimations() 166 | 167 | #---------------------------------------------------------------------- 168 | def closeEvent(self, event): 169 | """""" 170 | allFuncs_tab = self.findChild(QTabWidget, "allFuncs_tab") 171 | for i in xrange(allFuncs_tab.count()): 172 | allFuncs_tab.widget(i).closeEvent(event) 173 | 174 | event.accept() 175 | 176 | 177 | #---------------------------------------------------------------------- 178 | def main(): 179 | import sys 180 | app = QApplication(sys.argv) 181 | window = MainWindow() 182 | window.show() 183 | app.exec_() 184 | 185 | 186 | if __name__ == "__main__": 187 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/miscTab.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import os 6 | 7 | try: 8 | from PySide import QtGui, QtCore 9 | from PySide.QtGui import * 10 | from PySide.QtCore import * 11 | except ImportError: 12 | from PySide2 import QtGui, QtCore, QtWidgets 13 | from PySide2.QtGui import * 14 | from PySide2.QtCore import * 15 | from PySide2.QtWidgets import * 16 | 17 | from DLS.widget import baseTab 18 | from DLS.widget import utils 19 | from DLS.core import miscFunc 20 | 21 | #reload(baseTab) 22 | #reload(utils) 23 | reload(miscFunc) 24 | 25 | 26 | TAB = '' 27 | uifile = os.path.join(utils.SCRIPT_DIRECTORY, "ui/miscTab.ui") 28 | ENABLE = False 29 | INDEX = 3 30 | 31 | 32 | ######################################################################## 33 | class MiscTab(baseTab.BaseTab): 34 | """""" 35 | _TITLE = 'Misc' 36 | 37 | #---------------------------------------------------------------------- 38 | def __init__(self, parent=None): 39 | """Constructor""" 40 | super(MiscTab, self).__init__(parent) 41 | utils.loadUi(uifile, self) 42 | self.initWidgets() 43 | 44 | #---------------------------------------------------------------------- 45 | def initWidgets(self): 46 | """""" 47 | pass 48 | 49 | #---------------------------------------------------------------------- 50 | @Slot() 51 | def on_applyRigidSkinWeights_btn_clicked(self): 52 | miscFunc.applyRigidSkin() 53 | 54 | #---------------------------------------------------------------------- 55 | @Slot() 56 | def on_applyDeltaMushDeformer_btn_clicked(self): 57 | miscFunc.applyDeltaMushDeformer() 58 | 59 | #---------------------------------------------------------------------- 60 | @Slot() 61 | def on_transSkinWeights_btn_clicked(self): 62 | msg = b"This's transfer skin weights function" 63 | QMessageBox.information(self, self.trUtf8(b'Informations'), 64 | self.trUtf8(msg)) 65 | 66 | #---------------------------------------------------------------------- 67 | @Slot() 68 | def on_transBlendshapAttrs_btn_clicked(self): 69 | msg = b"This's transfer blendshape function" 70 | QMessageBox.information(self, self.trUtf8(b'Informations'), 71 | self.trUtf8(msg)) 72 | 73 | 74 | #---------------------------------------------------------------------- 75 | def getTab(): 76 | """""" 77 | return MiscTab 78 | 79 | #---------------------------------------------------------------------- 80 | def main(): 81 | import sys 82 | app = QApplication(sys.argv) 83 | window = MiscTab() 84 | window.show() 85 | app.exec_() 86 | 87 | 88 | if __name__ == "__main__": 89 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/optionWindow.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import os 6 | 7 | try: 8 | from PySide import QtGui, QtCore 9 | from PySide.QtGui import * 10 | from PySide.QtCore import * 11 | except ImportError: 12 | from PySide2 import QtGui, QtCore, QtWidgets 13 | from PySide2.QtGui import * 14 | from PySide2.QtCore import * 15 | from PySide2.QtWidgets import * 16 | from DLS.widget import utils 17 | from DLS.widget import baseOptionWindow 18 | 19 | from DLS.startup import setup 20 | 21 | #reload(baseOptionWindow) 22 | 23 | 24 | uifile = os.path.join(utils.SCRIPT_DIRECTORY, "ui/optionWindow.ui") 25 | cfgfile = os.path.join(utils.SCRIPT_DIRECTORY, "config.ini") 26 | 27 | 28 | ######################################################################## 29 | class OptionWindow(baseOptionWindow.BaseOptionWindow): 30 | """""" 31 | _TITLE = 'Options' 32 | 33 | #---------------------------------------------------------------------- 34 | def __init__(self, parent=None): 35 | """Constructor""" 36 | super(OptionWindow, self).__init__(parent) 37 | utils.loadUi(uifile, self) 38 | self.initWidgets() 39 | 40 | #---------------------------------------------------------------------- 41 | def initWidgets(self): 42 | """""" 43 | self.readSettings() 44 | 45 | self.setWindowTitle(self._TITLE) 46 | cp = QDesktopWidget().screenGeometry().center() 47 | self.move(cp) 48 | 49 | # Add actions 50 | actionReset = self.findChild(QAction, "actionReset") 51 | if actionReset != None: 52 | actionReset.triggered.connect(self.resetSettings) 53 | 54 | # Connect signal and slot 55 | pruneBelow_spn = self.findChild(QDoubleSpinBox, "pruneBelow_spn") 56 | if pruneBelow_spn != None: 57 | pruneBelow_spn.valueChanged.connect(self.changePruneBelow_slider) 58 | 59 | pruneBelow_slider = self.findChild(QSlider, "pruneBelow_slider") 60 | if pruneBelow_slider != None: 61 | pruneBelow_slider.valueChanged.connect(self.changePruneBelow_spn) 62 | 63 | # Set use build-in delta mush 64 | if setup.mayaVersion() >= 2016: 65 | self.setUseBuildInDeltaMushEnable(True) 66 | 67 | #---------------------------------------------------------------------- 68 | def getPruneBelow(self): 69 | """""" 70 | pruneBelow_spn = self.findChild(QDoubleSpinBox, "pruneBelow_spn") 71 | if pruneBelow_spn != None: 72 | return pruneBelow_spn.value() 73 | return 0.0 74 | 75 | #---------------------------------------------------------------------- 76 | def setPruneBelow(self, val): 77 | """""" 78 | pruneBelow_spn = self.findChild(QDoubleSpinBox, "pruneBelow_spn") 79 | if pruneBelow_spn != None: 80 | pruneBelow_spn.setValue(val) 81 | 82 | #---------------------------------------------------------------------- 83 | def isKeepOriginal(self): 84 | """""" 85 | keepOriginal_chk = self.findChild(QCheckBox, "keepOriginal_chk") 86 | if keepOriginal_chk != None: 87 | return keepOriginal_chk.isChecked() 88 | return True 89 | 90 | #---------------------------------------------------------------------- 91 | def setKeepOriginal(self, val): 92 | """""" 93 | keepOriginal_chk = self.findChild(QCheckBox, "keepOriginal_chk") 94 | if keepOriginal_chk != None: 95 | keepOriginal_chk.setChecked(val) 96 | 97 | #---------------------------------------------------------------------- 98 | def isDeleteDeltaMush(self): 99 | """""" 100 | deleteDeltaMush_chk = self.findChild(QCheckBox, "deleteDeltaMush_chk") 101 | if deleteDeltaMush_chk != None: 102 | return deleteDeltaMush_chk.isChecked() 103 | return False 104 | 105 | #---------------------------------------------------------------------- 106 | def setDeleteDeltaMush(self, val): 107 | """""" 108 | deleteDeltaMush_chk = self.findChild(QCheckBox, "deleteDeltaMush_chk") 109 | if deleteDeltaMush_chk != None: 110 | deleteDeltaMush_chk.setChecked(val) 111 | 112 | #---------------------------------------------------------------------- 113 | def setUseBuildInDeltaMush(self, val): 114 | """""" 115 | useBuildInDeltaMush_chk = self.findChild(QCheckBox, "useBuildInDeltaMush_chk") 116 | if useBuildInDeltaMush_chk != None: 117 | useBuildInDeltaMush_chk.setChecked(val) 118 | 119 | #---------------------------------------------------------------------- 120 | def setUseBuildInDeltaMushEnable(self, val): 121 | """""" 122 | useBuildInDeltaMush_chk = self.findChild(QCheckBox, "useBuildInDeltaMush_chk") 123 | if useBuildInDeltaMush_chk != None: 124 | useBuildInDeltaMush_chk.setEnabled(val) 125 | 126 | #---------------------------------------------------------------------- 127 | def useBuildInDeltaMush(self): 128 | """""" 129 | useBuildInDeltaMush_chk = self.findChild(QCheckBox, "useBuildInDeltaMush_chk") 130 | if useBuildInDeltaMush_chk != None: 131 | return useBuildInDeltaMush_chk.isEnabled() and useBuildInDeltaMush_chk.isChecked() 132 | 133 | #---------------------------------------------------------------------- 134 | def setSkipTips(self, val): 135 | """""" 136 | skipTips_chk = self.findChild(QCheckBox, "skipTips_chk") 137 | if skipTips_chk != None: 138 | skipTips_chk.setChecked(val) 139 | 140 | #---------------------------------------------------------------------- 141 | def skipTips(self): 142 | """""" 143 | skipTips_chk = self.findChild(QCheckBox, "skipTips_chk") 144 | if skipTips_chk != None: 145 | return skipTips_chk.isChecked() 146 | 147 | #---------------------------------------------------------------------- 148 | def resetSettings(self): 149 | settings = QSettings(cfgfile, QSettings.IniFormat) 150 | 151 | settings.beginGroup("Default") 152 | self.setPruneBelow(float(settings.value("pruneBeblow"))) 153 | self.setKeepOriginal(bool(int(settings.value("isKeepOriginal")))) 154 | self.setDeleteDeltaMush(bool(int(settings.value("isDeleteDeltaMush")))) 155 | self.setUseBuildInDeltaMush(bool(int(settings.value("useBuildInDeltaMush")))) 156 | self.setSkipTips(bool(int(settings.value("skipTips")))) 157 | settings.endGroup() 158 | 159 | #---------------------------------------------------------------------- 160 | def readSettings(self): 161 | settings = QSettings(cfgfile, QSettings.IniFormat) 162 | 163 | settings.beginGroup("Custom") 164 | self.setPruneBelow(float(settings.value("pruneBeblow"))) 165 | self.setKeepOriginal(bool(int(settings.value("isKeepOriginal")))) 166 | self.setDeleteDeltaMush(bool(int(settings.value("isDeleteDeltaMush")))) 167 | self.setUseBuildInDeltaMush(bool(int(settings.value("useBuildInDeltaMush")))) 168 | self.setSkipTips(bool(int(settings.value("skipTips")))) 169 | settings.endGroup() 170 | 171 | #---------------------------------------------------------------------- 172 | def writeSettings(self): 173 | settings = QSettings(cfgfile, QSettings.IniFormat) 174 | 175 | settings.beginGroup("Custom") 176 | settings.setValue("pruneBeblow", float(self.getPruneBelow())) 177 | settings.setValue("isKeepOriginal", int(self.isKeepOriginal())) 178 | settings.setValue("isDeleteDeltaMush", int(self.isDeleteDeltaMush())) 179 | settings.setValue("useBuildInDeltaMush", int(self.useBuildInDeltaMush())) 180 | settings.setValue("skipTips", int(self.skipTips())) 181 | settings.endGroup() 182 | 183 | #---------------------------------------------------------------------- 184 | @Slot() 185 | def changePruneBelow_spn(self): 186 | """""" 187 | val = 0 188 | pruneBelow_slider = self.findChild(QSlider, "pruneBelow_slider") 189 | if pruneBelow_slider != None: 190 | val = float(pruneBelow_slider.value()) / 100000 191 | 192 | pruneBelow_spn = self.findChild(QDoubleSpinBox, "pruneBelow_spn") 193 | if pruneBelow_spn != None: 194 | pruneBelow_spn.setValue(val) 195 | 196 | #---------------------------------------------------------------------- 197 | @Slot() 198 | def changePruneBelow_slider(self): 199 | """""" 200 | val = 0 201 | pruneBelow_spn = self.findChild(QDoubleSpinBox, "pruneBelow_spn") 202 | if pruneBelow_spn != None: 203 | val = int(pruneBelow_spn.value() * 100000) 204 | 205 | pruneBelow_slider = self.findChild(QSlider, "pruneBelow_slider") 206 | if pruneBelow_slider != None: 207 | pruneBelow_slider.setValue(val) 208 | 209 | 210 | #---------------------------------------------------------------------- 211 | def main(): 212 | import sys 213 | app = QApplication(sys.argv) 214 | window = OptionWindow() 215 | window.show() 216 | app.exec_() 217 | 218 | 219 | if __name__ == "__main__": 220 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/samplingTab.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | import os 6 | 7 | try: 8 | from PySide import QtGui, QtCore 9 | from PySide.QtGui import * 10 | from PySide.QtCore import * 11 | except ImportError: 12 | from PySide2 import QtGui, QtCore, QtWidgets 13 | from PySide2.QtGui import * 14 | from PySide2.QtCore import * 15 | from PySide2.QtWidgets import * 16 | 17 | import maya.OpenMaya as om 18 | 19 | from DLS.widget import utils 20 | 21 | from DLS.core import samplingFunc 22 | from DLS.widget import baseTab 23 | from DLS.widget import axisOptionWindow 24 | from DLS.widget import customAttributeEditor 25 | 26 | 27 | #reload(baseTab) 28 | #reload(utils) 29 | reload(samplingFunc) 30 | #reload(axisOptionWindow) 31 | reload(customAttributeEditor) 32 | 33 | TAB = '' 34 | uifile = os.path.join(utils.SCRIPT_DIRECTORY, "ui/samplingTab.ui") 35 | cfgfile = os.path.join(utils.SCRIPT_DIRECTORY, "config.ini") 36 | ENABLE = True 37 | INDEX = 2 38 | 39 | 40 | ######################################################################## 41 | class SamplingTab(baseTab.BaseTab): 42 | """ 43 | self.attrData = {node1: [[attr1, min, max], [attr2, min, max], ...], 44 | node2: [[attr1, min, max], [attr2, min, max], ...], 45 | ...} 46 | """ 47 | _TITLE = 'Sampling' 48 | 49 | #---------------------------------------------------------------------- 50 | def __init__(self, parent=None): 51 | """Constructor""" 52 | super(SamplingTab, self).__init__(parent) 53 | utils.loadUi(uifile, self) 54 | self.attrData = {} 55 | self.initWidgets() 56 | 57 | #---------------------------------------------------------------------- 58 | def initWidgets(self): 59 | """""" 60 | self.readSettings() 61 | 62 | doubleVal = QDoubleValidator(decimals=3, parent=self) 63 | 64 | # Set transformation widgets 65 | rotateMin_edit = self.findChild(QLineEdit, "rotateMin_edit") 66 | if rotateMin_edit != None: 67 | rotateMin_edit.setValidator(doubleVal) 68 | 69 | rotateMax_edit = self.findChild(QLineEdit, "rotateMax_edit") 70 | if rotateMax_edit != None: 71 | rotateMax_edit.setValidator(doubleVal) 72 | 73 | translateMin_edit = self.findChild(QLineEdit, "translateMin_edit") 74 | if translateMin_edit != None: 75 | translateMin_edit.setValidator(doubleVal) 76 | 77 | translateMax_edit = self.findChild(QLineEdit, "translateMax_edit") 78 | if translateMax_edit != None: 79 | translateMax_edit.setValidator(doubleVal) 80 | 81 | scaleMin_edit = self.findChild(QLineEdit, "scaleMin_edit") 82 | if scaleMin_edit != None: 83 | scaleMin_edit.setValidator(doubleVal) 84 | 85 | scaleMax_edit = self.findChild(QLineEdit, "scaleMax_edit") 86 | if scaleMax_edit != None: 87 | scaleMax_edit.setValidator(doubleVal) 88 | 89 | # Set blendshape widgets 90 | rx = QRegExp("^[a-zA-Z][a-zA-Z0-9_]+") 91 | val = QRegExpValidator(rx, self) 92 | blendshape_edit = self.findChild(QLineEdit, "blendshape_edit") 93 | if blendshape_edit != None: 94 | blendshape_edit.setValidator(val) 95 | 96 | #---------------------------------------------------------------------- 97 | def getTranslateMin(self): 98 | """""" 99 | translateMin_edit = self.findChild(QLineEdit, "translateMin_edit") 100 | if translateMin_edit != None: 101 | return float(translateMin_edit.text()) 102 | return -1.0 103 | 104 | #---------------------------------------------------------------------- 105 | def setTranslateMin(self, val): 106 | """""" 107 | translateMin_edit = self.findChild(QLineEdit, "translateMin_edit") 108 | if translateMin_edit != None: 109 | translateMin_edit.setText(str(val)) 110 | 111 | #---------------------------------------------------------------------- 112 | def getTranslateMax(self): 113 | """""" 114 | translateMax_edit = self.findChild(QLineEdit, "translateMax_edit") 115 | if translateMax_edit != None: 116 | return float(translateMax_edit.text()) 117 | return 1.0 118 | 119 | #---------------------------------------------------------------------- 120 | def setTranslateMax(self, val): 121 | """""" 122 | translateMax_edit = self.findChild(QLineEdit, "translateMax_edit") 123 | if translateMax_edit != None: 124 | translateMax_edit.setText(str(val)) 125 | 126 | #---------------------------------------------------------------------- 127 | def getRotateMin(self): 128 | """""" 129 | rotateMin_edit = self.findChild(QLineEdit, "rotateMin_edit") 130 | if rotateMin_edit != None: 131 | return float(rotateMin_edit.text()) 132 | return -90.0 133 | 134 | #---------------------------------------------------------------------- 135 | def setRotateMin(self, val): 136 | """""" 137 | rotateMin_edit = self.findChild(QLineEdit, "rotateMin_edit") 138 | if rotateMin_edit != None: 139 | rotateMin_edit.setText(str(val)) 140 | 141 | #---------------------------------------------------------------------- 142 | def getRotateMax(self): 143 | """""" 144 | rotateMax_edit = self.findChild(QLineEdit, "rotateMax_edit") 145 | if rotateMax_edit != None: 146 | return float(rotateMax_edit.text()) 147 | return 90.0 148 | 149 | #---------------------------------------------------------------------- 150 | def setRotateMax(self, val): 151 | """""" 152 | rotateMax_edit = self.findChild(QLineEdit, "rotateMax_edit") 153 | if rotateMax_edit != None: 154 | rotateMax_edit.setText(str(val)) 155 | 156 | #---------------------------------------------------------------------- 157 | def getScaleMin(self): 158 | """""" 159 | scaleMin_edit = self.findChild(QLineEdit, "scaleMin_edit") 160 | if scaleMin_edit != None: 161 | return float(scaleMin_edit.text()) 162 | return -1.0 163 | 164 | #---------------------------------------------------------------------- 165 | def setScaleMin(self, val): 166 | """""" 167 | scaleMin_edit = self.findChild(QLineEdit, "scaleMin_edit") 168 | if scaleMin_edit != None: 169 | scaleMin_edit.setText(str(val)) 170 | 171 | #---------------------------------------------------------------------- 172 | def getScaleMax(self): 173 | """""" 174 | scaleMax_edit = self.findChild(QLineEdit, "scaleMax_edit") 175 | if scaleMax_edit != None: 176 | return float(scaleMax_edit.text()) 177 | return 1.0 178 | 179 | #---------------------------------------------------------------------- 180 | def setScaleMax(self, val): 181 | """""" 182 | scaleMax_edit = self.findChild(QLineEdit, "scaleMax_edit") 183 | if scaleMax_edit != None: 184 | scaleMax_edit.setText(str(val)) 185 | 186 | #---------------------------------------------------------------------- 187 | def getBlendshapeName(self): 188 | """""" 189 | blendshape_edit = self.findChild(QLineEdit, "blendshape_edit") 190 | if blendshape_edit != None: 191 | return str(blendshape_edit.text()) 192 | 193 | #---------------------------------------------------------------------- 194 | def setBlendshapeName(self, val): 195 | """""" 196 | blendshape_edit = self.findChild(QLineEdit, "blendshape_edit") 197 | if blendshape_edit != None: 198 | blendshape_edit.setText(str(val)) 199 | 200 | #---------------------------------------------------------------------- 201 | def isTranslate(self): 202 | """""" 203 | translate_chk = self.findChild(QCheckBox, "translate_chk") 204 | if translate_chk != None: 205 | return translate_chk.isChecked() 206 | return False 207 | 208 | #---------------------------------------------------------------------- 209 | def setTranslate(self, val): 210 | """""" 211 | translate_chk = self.findChild(QCheckBox, "translate_chk") 212 | if translate_chk != None: 213 | translate_chk.setChecked(val) 214 | translate_chk.click() 215 | translate_chk.click() 216 | 217 | #---------------------------------------------------------------------- 218 | def isRotate(self): 219 | """""" 220 | rotate_chk = self.findChild(QCheckBox, "rotate_chk") 221 | if rotate_chk != None: 222 | return rotate_chk.isChecked() 223 | return True 224 | 225 | #---------------------------------------------------------------------- 226 | def setRotate(self, val): 227 | """""" 228 | rotate_chk = self.findChild(QCheckBox, "rotate_chk") 229 | if rotate_chk != None: 230 | rotate_chk.setChecked(val) 231 | rotate_chk.click() 232 | rotate_chk.click() 233 | 234 | #---------------------------------------------------------------------- 235 | def isScale(self): 236 | """""" 237 | scale_chk = self.findChild(QCheckBox, "scale_chk") 238 | if scale_chk != None: 239 | return scale_chk.isChecked() 240 | return False 241 | 242 | #---------------------------------------------------------------------- 243 | def setScale(self, val): 244 | """""" 245 | scale_chk = self.findChild(QCheckBox, "scale_chk") 246 | if scale_chk != None: 247 | scale_chk.setChecked(val) 248 | scale_chk.click() 249 | scale_chk.click() 250 | 251 | #---------------------------------------------------------------------- 252 | def isTransform(self): 253 | """""" 254 | transformOptions_frame = self.findChild(QFrame, "transformOptions_frame") 255 | if transformOptions_frame != None: 256 | return transformOptions_frame.isEnabled() 257 | return False 258 | 259 | #---------------------------------------------------------------------- 260 | def isBlendshape(self): 261 | """""" 262 | blendshape_chk = self.findChild(QCheckBox, "blendshape_chk") 263 | if blendshape_chk != None: 264 | return blendshape_chk.isChecked() 265 | return False 266 | 267 | #---------------------------------------------------------------------- 268 | def setBlendshape(self, val): 269 | """""" 270 | blendshape_chk = self.findChild(QCheckBox, "blendshape_chk") 271 | if blendshape_chk != None: 272 | blendshape_chk.setChecked(val) 273 | blendshape_chk.click() 274 | blendshape_chk.click() 275 | 276 | #---------------------------------------------------------------------- 277 | def isCustomAttrs(self): 278 | """""" 279 | customAttrs_chk = self.findChild(QCheckBox, "customAttrs_chk") 280 | if customAttrs_chk != None: 281 | return customAttrs_chk.isChecked() 282 | return False 283 | 284 | #---------------------------------------------------------------------- 285 | def setCustomAttrs(self, val): 286 | """""" 287 | customAttrs_chk = self.findChild(QCheckBox, "customAttrs_chk") 288 | if customAttrs_chk != None: 289 | customAttrs_chk.setChecked(val) 290 | customAttrs_chk.click() 291 | customAttrs_chk.click() 292 | 293 | #---------------------------------------------------------------------- 294 | def resetSettings(self): 295 | """""" 296 | settings = QSettings(cfgfile, QSettings.IniFormat) 297 | 298 | settings.beginGroup("Default") 299 | self.setBlendshape(bool(int(settings.value("isBlendshape")))) 300 | self.setBlendshapeName(settings.value("blendshapeName")) 301 | 302 | self.setTranslate(bool(int(settings.value("isTranslate")))) 303 | self.setTranslateMin(float(settings.value("translateMin"))) 304 | self.setTranslateMax(float(settings.value("translateMax"))) 305 | 306 | self.setRotate(bool(int(settings.value("isRotate")))) 307 | self.setRotateMin(float(settings.value("rotateMin"))) 308 | self.setRotateMax(float(settings.value("rotateMax"))) 309 | 310 | self.setScale(bool(int(settings.value("isScale")))) 311 | self.setScaleMin(float(settings.value("scaleMin"))) 312 | self.setScaleMax(float(settings.value("scaleMax"))) 313 | 314 | self.setCustomAttrs(bool(int(settings.value("isCustomAttrs")))) 315 | 316 | settings.endGroup() 317 | 318 | #---------------------------------------------------------------------- 319 | def readSettings(self): 320 | """""" 321 | settings = QSettings(cfgfile, QSettings.IniFormat) 322 | 323 | settings.beginGroup("Custom") 324 | self.setBlendshape(bool(int(settings.value("isBlendshape")))) 325 | 326 | self.setTranslate(bool(int(settings.value("isTranslate")))) 327 | self.setTranslateMin(float(settings.value("translateMin"))) 328 | self.setTranslateMax(float(settings.value("translateMax"))) 329 | 330 | self.setRotate(bool(int(settings.value("isRotate")))) 331 | self.setRotateMin(float(settings.value("rotateMin"))) 332 | self.setRotateMax(float(settings.value("rotateMax"))) 333 | 334 | self.setScale(bool(int(settings.value("isScale")))) 335 | self.setScaleMin(float(settings.value("scaleMin"))) 336 | self.setScaleMax(float(settings.value("scaleMax"))) 337 | 338 | self.setCustomAttrs(bool(int(settings.value("isCustomAttrs")))) 339 | 340 | settings.endGroup() 341 | 342 | #---------------------------------------------------------------------- 343 | def writeSettings(self): 344 | """""" 345 | settings = QSettings(cfgfile, QSettings.IniFormat) 346 | 347 | settings.beginGroup("Custom") 348 | settings.setValue("isTranslate", int(self.isTranslate())) 349 | settings.setValue("translateMin", self.getTranslateMin()) 350 | settings.setValue("translateMax", self.getTranslateMax()) 351 | 352 | settings.setValue("isRotate", int(self.isRotate())) 353 | settings.setValue("rotateMin", self.getRotateMin()) 354 | settings.setValue("rotateMax", self.getRotateMax()) 355 | 356 | settings.setValue("isScale", int(self.isScale())) 357 | settings.setValue("scaleMin", self.getScaleMin()) 358 | settings.setValue("scaleMax", self.getScaleMax()) 359 | 360 | settings.setValue("isBlendshape", int(self.isBlendshape())) 361 | 362 | settings.setValue("isCustomAttrs", int(self.isCustomAttrs())) 363 | 364 | settings.endGroup() 365 | 366 | #---------------------------------------------------------------------- 367 | @Slot(bool) 368 | def on_translate_chk_clicked(self, isChecked): 369 | translateMin_edit = self.findChild(QLineEdit, "translateMin_edit") 370 | if translateMin_edit != None: 371 | translateMin_edit.setEnabled(isChecked) 372 | 373 | translateMax_edit = self.findChild(QLineEdit, "translateMax_edit") 374 | if translateMax_edit != None: 375 | translateMax_edit.setEnabled(isChecked) 376 | 377 | #---------------------------------------------------------------------- 378 | @Slot() 379 | def on_translateOpt_btn_clicked(self): 380 | axisOptionWindow.TranslateAxisOptionWindow(self).show() 381 | 382 | #---------------------------------------------------------------------- 383 | @Slot(bool) 384 | def on_rotate_chk_clicked(self, isChecked): 385 | rotateMin_edit = self.findChild(QLineEdit, "rotateMin_edit") 386 | if rotateMin_edit != None: 387 | rotateMin_edit.setEnabled(isChecked) 388 | 389 | rotateMax_edit = self.findChild(QLineEdit, "rotateMax_edit") 390 | if rotateMax_edit != None: 391 | rotateMax_edit.setEnabled(isChecked) 392 | 393 | #---------------------------------------------------------------------- 394 | @Slot() 395 | def on_rotateOpt_btn_clicked(self): 396 | axisOptionWindow.RotateAxisOptionWindow(self).show() 397 | 398 | #---------------------------------------------------------------------- 399 | @Slot(bool) 400 | def on_scale_chk_clicked(self, isChecked): 401 | scaleMin_edit = self.findChild(QLineEdit, "scaleMin_edit") 402 | if scaleMin_edit != None: 403 | scaleMin_edit.setEnabled(isChecked) 404 | 405 | scaleMax_edit = self.findChild(QLineEdit, "scaleMax_edit") 406 | if scaleMax_edit != None: 407 | scaleMax_edit.setEnabled(isChecked) 408 | 409 | #---------------------------------------------------------------------- 410 | @Slot() 411 | def on_scaleOpt_btn_clicked(self): 412 | axisOptionWindow.ScaleAxisOptionWindow(self).show() 413 | 414 | #---------------------------------------------------------------------- 415 | @Slot(bool) 416 | def on_blendshape_chk_clicked(self, isChecked): 417 | transformOptions_frame = self.findChild(QFrame, "transformOptions_frame") 418 | if transformOptions_frame != None: 419 | transformOptions_frame.setEnabled(not isChecked) 420 | 421 | blendshape_edit = self.findChild(QLineEdit, "blendshape_edit") 422 | if blendshape_edit != None: 423 | blendshape_edit.setEnabled(isChecked) 424 | 425 | loadBlendshape_btn = self.findChild(QPushButton, "loadBlendshape_btn") 426 | if loadBlendshape_btn != None: 427 | loadBlendshape_btn.setEnabled(isChecked) 428 | 429 | customAttrsOptions_frame = self.findChild(QFrame, "customAttrsOptions_frame") 430 | if customAttrsOptions_frame != None: 431 | customAttrsOptions_frame.setEnabled(not isChecked) 432 | 433 | #---------------------------------------------------------------------- 434 | @Slot() 435 | def on_loadBlendshape_btn_clicked(self): 436 | blendshape = samplingFunc.getBlendshapeFromSelection() 437 | 438 | blendshape_edit = self.findChild(QLineEdit, "blendshape_edit") 439 | if blendshape_edit != None: 440 | blendshape_edit.setText(blendshape) 441 | 442 | #---------------------------------------------------------------------- 443 | @Slot(bool) 444 | def on_customAttrs_chk_clicked(self, isChecked): 445 | transformOptions_frame = self.findChild(QFrame, "transformOptions_frame") 446 | if transformOptions_frame != None: 447 | transformOptions_frame.setEnabled(not isChecked) 448 | 449 | blendshapeOptions_frame = self.findChild(QFrame, "blendshapeOptions_frame") 450 | if blendshapeOptions_frame != None: 451 | blendshapeOptions_frame.setEnabled(not isChecked) 452 | 453 | openCustomAttrsEditor_btn = self.findChild(QPushButton, "openCustomAttrsEditor_btn") 454 | if openCustomAttrsEditor_btn != None: 455 | openCustomAttrsEditor_btn.setEnabled(isChecked) 456 | 457 | #---------------------------------------------------------------------- 458 | @Slot() 459 | def on_openCustomAttrsEditor_btn_clicked(self): 460 | editor = customAttributeEditor.CustomAttributeEditor(self.attrData, self) 461 | editor.showUI() 462 | 463 | #---------------------------------------------------------------------- 464 | @Slot() 465 | def on_run_btn_clicked(self): 466 | # Sample transform attributes 467 | if self.isTransform(): 468 | translateMin = self.getTranslateMin() 469 | translateMax = self.getTranslateMax() 470 | rotateMin = self.getRotateMin() 471 | rotateMax = self.getRotateMax() 472 | scaleMin = self.getScaleMin() 473 | scaleMax = self.getScaleMax() 474 | isTranslate = self.isTranslate() 475 | isRotate = self.isRotate() 476 | isScale = self.isScale() 477 | 478 | translateAttrs = [] 479 | rotateAttrs = [] 480 | scaleAttrs = [] 481 | 482 | # Parse axis settings 483 | settings = QSettings(cfgfile, QSettings.IniFormat) 484 | settings.beginGroup("Custom") 485 | if bool(int(settings.value("translateX"))): translateAttrs.append("tx") 486 | if bool(int(settings.value("translateY"))): translateAttrs.append("ty") 487 | if bool(int(settings.value("translateZ"))): translateAttrs.append("tz") 488 | 489 | if bool(int(settings.value("rotateX"))): rotateAttrs.append("rx") 490 | if bool(int(settings.value("rotateY"))): rotateAttrs.append("ry") 491 | if bool(int(settings.value("rotateZ"))): rotateAttrs.append("rz") 492 | 493 | if bool(int(settings.value("scaleX"))): scaleAttrs.append("sx") 494 | if bool(int(settings.value("scaleY"))): scaleAttrs.append("sy") 495 | if bool(int(settings.value("scaleZ"))): scaleAttrs.append("sz") 496 | settings.endGroup() 497 | 498 | 499 | samplingFunc.transformSampling(translateMin, 500 | translateMax, 501 | rotateMin, 502 | rotateMax, 503 | scaleMin, 504 | scaleMax, 505 | isTranslate, 506 | isRotate, 507 | isScale, 508 | translateAttrs, 509 | rotateAttrs, 510 | scaleAttrs) 511 | 512 | # Sample blendshape attributes 513 | if self.isBlendshape(): 514 | blendshape = self.getBlendshapeName() 515 | if blendshape: 516 | samplingFunc.blendShapeSampling(blendshape) 517 | else: 518 | om.MGlobal.displayError("Please load blendshape first.") 519 | return 520 | 521 | # Sample custom attributes 522 | if self.isCustomAttrs(): 523 | if self.attrData: 524 | samplingFunc.customAttrsSampling(self.attrData) 525 | else: 526 | om.MGlobal.displayError("Please append attributes for sampling first.") 527 | return 528 | 529 | 530 | #---------------------------------------------------------------------- 531 | def getTab(): 532 | """""" 533 | return SamplingTab 534 | 535 | #---------------------------------------------------------------------- 536 | def main(): 537 | import sys 538 | app = QApplication(sys.argv) 539 | window = SamplingTab() 540 | window.show() 541 | app.exec_() 542 | 543 | 544 | if __name__ == "__main__": 545 | main() -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/ui/aboutDialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | about_dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 190 10 | 131 11 | 12 | 13 | 14 | About 15 | 16 | 17 | 18 | 19 | 20 | 21 | 75 22 | true 23 | 24 | 25 | 26 | Deformation Learning Solver 27 | 28 | 29 | Qt::AlignCenter 30 | 31 | 32 | 33 | 34 | 35 | 36 | QFrame::Box 37 | 38 | 39 | QFrame::Sunken 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | Author: 50 | 51 | 52 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 53 | 54 | 55 | 56 | 57 | 58 | 59 | Contact: 60 | 61 | 62 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 63 | 64 | 65 | 66 | 67 | 68 | 69 | Website: 70 | 71 | 72 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 73 | 74 | 75 | 76 | 77 | 78 | 79 | Version: 80 | 81 | 82 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | Webber Huang 94 | 95 | 96 | 97 | 98 | 99 | 100 | xracz.fx@gmail.com 101 | 102 | 103 | 104 | 105 | 106 | 107 | http://riggingtd.com 108 | 109 | 110 | 111 | 112 | 113 | 114 | 1.5.5 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/ui/axisWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 176 10 | 89 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | X 24 | 25 | 26 | true 27 | 28 | 29 | 30 | 31 | 32 | 33 | Y 34 | 35 | 36 | true 37 | 38 | 39 | 40 | 41 | 42 | 43 | Z 44 | 45 | 46 | true 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Save 58 | 59 | 60 | 61 | 62 | 63 | 64 | Cancel 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 0 76 | 0 77 | 176 78 | 21 79 | 80 | 81 | 82 | 83 | Edit 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Reset 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/ui/customAttributeEditor.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 270 10 | 311 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Add 24 | 25 | 26 | 27 | 28 | 29 | 30 | Clear 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Save 45 | 46 | 47 | 48 | 49 | 50 | 51 | Cancel 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Reset 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/ui/learningTab.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 272 10 | 250 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | QFrame::NoFrame 21 | 22 | 23 | QFrame::Plain 24 | 25 | 26 | 27 | 2 28 | 29 | 30 | 2 31 | 32 | 33 | 34 | 35 | 36 | 37 | Num of Bones: 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 48 46 | 16777215 47 | 48 | 49 | 50 | false 51 | 52 | 53 | true 54 | 55 | 56 | 1 57 | 58 | 59 | 999999999 60 | 61 | 62 | 1 63 | 64 | 65 | 66 | 67 | 68 | 69 | Max Infs: 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 48 78 | 16777215 79 | 80 | 81 | 82 | 1 83 | 84 | 85 | 999999999 86 | 87 | 88 | 4 89 | 90 | 91 | 92 | 93 | 94 | 95 | Epsilon: 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 48 104 | 16777215 105 | 106 | 107 | 108 | 109 | 110 | 111 | 0.100000000000000 112 | 113 | 114 | 1.000000000000000 115 | 116 | 117 | 118 | 119 | 120 | 121 | Max Iters: 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 48 130 | 16777215 131 | 132 | 133 | 134 | 999999999 135 | 136 | 137 | 10 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | Qt::Horizontal 150 | 151 | 152 | 153 | 154 | 155 | 156 | true 157 | 158 | 159 | QFrame::NoFrame 160 | 161 | 162 | QFrame::Plain 163 | 164 | 165 | 166 | 2 167 | 168 | 169 | 2 170 | 171 | 172 | 173 | 174 | 175 | 176 | Target Mesh: 177 | 178 | 179 | 180 | 181 | 182 | 183 | true 184 | 185 | 186 | 187 | 188 | 189 | 190 | true 191 | 192 | 193 | 194 | 32 195 | 16777215 196 | 197 | 198 | 199 | <-- 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | Alternative Update 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | Qt::Horizontal 219 | 220 | 221 | 222 | 223 | 224 | 225 | true 226 | 227 | 228 | false 229 | 230 | 231 | QFrame::NoFrame 232 | 233 | 234 | QFrame::Plain 235 | 236 | 237 | 1 238 | 239 | 240 | 0 241 | 242 | 243 | 244 | 2 245 | 246 | 247 | 2 248 | 249 | 250 | 251 | 252 | 253 | 254 | Time Range: 255 | 256 | 257 | 258 | 259 | 260 | 261 | Start/End: 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | Time Slider 275 | 276 | 277 | 278 | 279 | 280 | 281 | Start/End 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 0.0 293 | 294 | 295 | 296 | 297 | 298 | 299 | 0.0 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | Solve 316 | 317 | 318 | 319 | 320 | 321 | 322 | Measure 323 | 324 | 325 | 326 | 327 | 328 | 329 | timeRangeOptions_frame 330 | break2_line 331 | targetMesh_frame 332 | break1_line 333 | frame 334 | 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/ui/miscTab.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 175 10 | 165 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Apply Rigid Skin Weights 21 | 22 | 23 | 24 | 25 | 26 | 27 | Apply Delta Mush Deformer 28 | 29 | 30 | 31 | 32 | 33 | 34 | Transfer Skin Weights 35 | 36 | 37 | 38 | 39 | 40 | 41 | Transfer Blendshape Attributes 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/ui/optionWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | option_win 4 | 5 | 6 | 7 | 0 8 | 0 9 | 258 10 | 247 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | QFrame::NoFrame 22 | 23 | 24 | QFrame::Raised 25 | 26 | 27 | 28 | 29 | 30 | 31 | 0 32 | 0 33 | 34 | 35 | 36 | Prune Small Weights 37 | 38 | 39 | 40 | QLayout::SetDefaultConstraint 41 | 42 | 43 | 44 | 45 | Qt::Horizontal 46 | 47 | 48 | QSizePolicy::MinimumExpanding 49 | 50 | 51 | 52 | 8 53 | 20 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | QLayout::SetDefaultConstraint 62 | 63 | 64 | 65 | 66 | 67 | 0 68 | 0 69 | 70 | 71 | 72 | Prune below: 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 0 81 | 0 82 | 83 | 84 | 85 | false 86 | 87 | 88 | true 89 | 90 | 91 | QAbstractSpinBox::NoButtons 92 | 93 | 94 | false 95 | 96 | 97 | 4 98 | 99 | 100 | 0.100000000000000 101 | 102 | 103 | 0.005000000000000 104 | 105 | 106 | 0.000000000000000 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 72 115 | 0 116 | 117 | 118 | 119 | 10000 120 | 121 | 122 | 1 123 | 124 | 125 | 100 126 | 127 | 128 | 0 129 | 130 | 131 | Qt::Horizontal 132 | 133 | 134 | false 135 | 136 | 137 | false 138 | 139 | 140 | QSlider::NoTicks 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | Qt::Vertical 153 | 154 | 155 | QSizePolicy::MinimumExpanding 156 | 157 | 158 | 159 | 20 160 | 4 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | Keep original 169 | 170 | 171 | true 172 | 173 | 174 | 175 | 176 | 177 | 178 | Skip tips for select all below 179 | 180 | 181 | true 182 | 183 | 184 | 185 | 186 | 187 | 188 | false 189 | 190 | 191 | Use build-in delta mush (2016+) 192 | 193 | 194 | false 195 | 196 | 197 | 198 | 199 | 200 | 201 | Delete delta mush after solving 202 | 203 | 204 | false 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | Save 217 | 218 | 219 | 220 | 221 | 222 | 223 | Cancel 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 0 235 | 0 236 | 258 237 | 21 238 | 239 | 240 | 241 | 242 | Edit 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | Reset 251 | 252 | 253 | 254 | 255 | 256 | 257 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/ui/samplingTab.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 255 10 | 243 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | true 21 | 22 | 23 | QFrame::NoFrame 24 | 25 | 26 | QFrame::Plain 27 | 28 | 29 | 30 | 2 31 | 32 | 33 | 2 34 | 35 | 36 | 37 | 38 | 39 | 40 | Min 41 | 42 | 43 | 44 | 45 | 46 | 47 | Max 48 | 49 | 50 | 51 | 52 | 53 | 54 | true 55 | 56 | 57 | Translate: 58 | 59 | 60 | 61 | 62 | 63 | 64 | -1.0 65 | 66 | 67 | 68 | 69 | 70 | 71 | 1.0 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 20 80 | 16777215 81 | 82 | 83 | 84 | ... 85 | 86 | 87 | 88 | 89 | 90 | 91 | Rotate: 92 | 93 | 94 | 95 | 96 | 97 | 98 | -90.0 99 | 100 | 101 | 102 | 103 | 104 | 105 | 90.0 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 20 114 | 16777215 115 | 116 | 117 | 118 | ... 119 | 120 | 121 | 122 | 123 | 124 | 125 | Scale: 126 | 127 | 128 | 129 | 130 | 131 | 132 | -1.0 133 | 134 | 135 | 136 | 137 | 138 | 139 | true 140 | 141 | 142 | 1.0 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 20 151 | 16777215 152 | 153 | 154 | 155 | ... 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | Qt::Horizontal 168 | 169 | 170 | 171 | 172 | 173 | 174 | true 175 | 176 | 177 | QFrame::NoFrame 178 | 179 | 180 | QFrame::Plain 181 | 182 | 183 | 184 | 6 185 | 186 | 187 | 2 188 | 189 | 190 | 2 191 | 192 | 193 | 194 | 195 | 196 | 197 | true 198 | 199 | 200 | Blend Shape: 201 | 202 | 203 | true 204 | 205 | 206 | false 207 | 208 | 209 | 210 | 211 | 212 | 213 | true 214 | 215 | 216 | 217 | 218 | 219 | 220 | true 221 | 222 | 223 | 224 | 32 225 | 16777215 226 | 227 | 228 | 229 | <-- 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | Qt::Horizontal 242 | 243 | 244 | 245 | 246 | 247 | 248 | true 249 | 250 | 251 | QFrame::NoFrame 252 | 253 | 254 | QFrame::Plain 255 | 256 | 257 | 258 | 2 259 | 260 | 261 | 2 262 | 263 | 264 | 265 | 266 | 4 267 | 268 | 269 | 270 | 271 | 272 | 14 273 | 16777215 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | true 285 | 286 | 287 | 288 | 16777215 289 | 16777215 290 | 291 | 292 | 293 | Custom Attributes 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | Run 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | -------------------------------------------------------------------------------- /DeformationLearningSolver/scripts/DLS/widget/utils.py: -------------------------------------------------------------------------------- 1 | __author__ = "Webber Huang" 2 | __contact__ = "xracz.fx@gmail.com" 3 | __website__ = "http://riggingtd.com" 4 | 5 | 6 | import os 7 | import sys 8 | 9 | try: 10 | from PySide.QtCore import Slot, QMetaObject 11 | from PySide.QtUiTools import QUiLoader 12 | from PySide.QtGui import QApplication, QMainWindow, QMessageBox 13 | except ImportError: 14 | from PySide2.QtCore import Slot, QMetaObject 15 | from PySide2.QtUiTools import QUiLoader 16 | from PySide2.QtWidgets import QApplication, QMainWindow, QMessageBox 17 | 18 | 19 | SCRIPT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)).replace('\\', '/') 20 | 21 | #---------------------------------------------------------------------- 22 | def findAllFiles(fileDirectory, fileExtension): 23 | """ 24 | Args: 25 | fileDirectory (str) 26 | fileExtension (str) 27 | 28 | Returns: 29 | list 30 | """ 31 | return [f for f in os.listdir(fileDirectory) if f.lower().endswith(fileExtension)] 32 | 33 | #---------------------------------------------------------------------- 34 | def findAllModules(): 35 | """ 36 | Returns: 37 | list 38 | """ 39 | allPyFiles = findAllFiles(SCRIPT_DIRECTORY, ".py") 40 | return [f.split('.')[0] for f in allPyFiles if not f.startswith("__init__")] 41 | 42 | #---------------------------------------------------------------------- 43 | def findAllTabs(): 44 | """ 45 | Returns: 46 | list 47 | """ 48 | tabModules = [] 49 | for m in findAllModules(): 50 | mod = __import__("DLS.widget.%s" % m, '', '', [m]) 51 | if hasattr(mod, 'TAB') and mod.ENABLE: 52 | reload(mod) 53 | tabModules.append(mod) 54 | 55 | tabModules.sort(key=lambda m: m.INDEX) 56 | return [m.getTab() for m in tabModules] 57 | 58 | #---------------------------------------------------------------------- 59 | class UiLoader(QUiLoader): 60 | """ 61 | Subclass :class:`~PySide.QtUiTools.QUiLoader` to create the user interface 62 | in a base instance. 63 | 64 | Unlike :class:`~PySide.QtUiTools.QUiLoader` itself this class does not 65 | create a new instance of the top-level widget, but creates the user 66 | interface in an existing instance of the top-level class. 67 | 68 | This mimics the behaviour of :func:`PyQt4.uic.loadUi`. 69 | """ 70 | 71 | def __init__(self, baseinstance): 72 | """ 73 | Create a loader for the given ``baseinstance``. 74 | 75 | The user interface is created in ``baseinstance``, which must be an 76 | instance of the top-level class in the user interface to load, or a 77 | subclass thereof. 78 | 79 | ``parent`` is the parent object of this loader. 80 | """ 81 | QUiLoader.__init__(self, baseinstance) 82 | self.baseinstance = baseinstance 83 | 84 | def createWidget(self, class_name, parent=None, name=''): 85 | if parent is None and self.baseinstance: 86 | # supposed to create the top-level widget, return the base instance 87 | # instead 88 | return self.baseinstance 89 | else: 90 | # create a new widget for child widgets 91 | widget = QUiLoader.createWidget(self, class_name, parent, name) 92 | if self.baseinstance: 93 | # set an attribute for the new child widget on the base 94 | # instance, just like PyQt4.uic.loadUi does. 95 | setattr(self.baseinstance, name, widget) 96 | return widget 97 | 98 | 99 | def loadUi(uifile, baseinstance=None): 100 | """ 101 | Dynamically load a user interface from the given ``uifile``. 102 | 103 | ``uifile`` is a string containing a file name of the UI file to load. 104 | 105 | If ``baseinstance`` is ``None``, the a new instance of the top-level widget 106 | will be created. Otherwise, the user interface is created within the given 107 | ``baseinstance``. In this case ``baseinstance`` must be an instance of the 108 | top-level widget class in the UI file to load, or a subclass thereof. In 109 | other words, if you've created a ``QMainWindow`` interface in the designer, 110 | ``baseinstance`` must be a ``QMainWindow`` or a subclass thereof, too. You 111 | cannot load a ``QMainWindow`` UI file with a plain 112 | :class:`~PySide.QtGui.QWidget` as ``baseinstance``. 113 | 114 | :method:`~PySide.QtCore.QMetaObject.connectSlotsByName()` is called on the 115 | created user interface, so you can implemented your slots according to its 116 | conventions in your widget class. 117 | 118 | Return ``baseinstance``, if ``baseinstance`` is not ``None``. Otherwise 119 | return the newly created instance of the user interface. 120 | """ 121 | loader = UiLoader(baseinstance) 122 | widget = loader.load(uifile) 123 | QMetaObject.connectSlotsByName(widget) 124 | return widget 125 | 126 | 127 | class MainWindow(QMainWindow): 128 | 129 | def __init__(self, parent=None): 130 | QMainWindow.__init__(self, parent) 131 | loadUi(os.path.join(SCRIPT_DIRECTORY, 'mainwindow.ui'), self) 132 | 133 | @Slot(bool) 134 | def on_clickMe_clicked(self, is_checked): 135 | if is_checked: 136 | message = self.trUtf8(b'I am checked now.') 137 | else: 138 | message = self.trUtf8(b'I am unchecked now.') 139 | QMessageBox.information(self, self.trUtf8(b'You clicked me'), message) 140 | 141 | @Slot() 142 | def on_actionHello_triggered(self): 143 | QMessageBox.information(self, self.trUtf8(b'Hello world'), 144 | self.trUtf8(b'Greetings to the world.')) 145 | 146 | 147 | def main(): 148 | app = QApplication(sys.argv) 149 | window = MainWindow() 150 | window.show() 151 | app.exec_() 152 | 153 | 154 | if __name__ == '__main__': 155 | main() 156 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2016, Webber Huang 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deformation Learning Solver for Autodesk Maya 2 | 3 | **This project has been DEPRECATED and is no longer being supported.** This is just my personal experiment project that I never expected people taking it seriously, companies use this tool will end up implementing their own version, and I'm not allowed to share or sell the source code in any way, sorry about that. 4 | 5 | Please find the alternative solution from **EA's [Dem Bones](https://github.com/electronicarts/dem-bones)**, it's reliable in terms of performance and accuracy, I highly recommend everyone adapt this implementaion to your own project. 6 | 7 | Any query regarding to DLS won't get replied, thanks for your understanding. 8 | 9 | ------------------------------------------ 10 | 11 | Deformation Learning Solver is based on Smooth Skinning Decomposition with Rigid Bones which was an automated algorithm to extract the linear blend skinning (LBS) from a set of example poses, and made to convert any deformation approximation to joints and it's skinning-based. This allows there to be a savings in computing resources and a smaller data footprint. 12 | 13 | This tool haven't be verified in real production yet, since this's just a personal research project to learn SSDR and skinning technique in deep, please feel free to test it at your own risk. 14 | 15 | ## License: BSD 3-Clause 16 | 17 | ## Contact: 18 | * Author: [Webber Huang](https://uk.linkedin.com/in/webber-huang-aab076100) 19 | * Project: [https://github.com/WebberHuang/DeformationLearningSolver](https://github.com/WebberHuang/DeformationLearningSolver) 20 | 21 | ## Demo: 22 | * [Deformation Learning Solver](https://vimeo.com/130998850) 23 | * [Deformation Learning Solver v1.5](https://vimeo.com/138048608) 24 | 25 | ## Requires: 26 | Maya 2014 x64 and above, Windows, Linux and OS X 27 | 28 | The solver has been compiled success on these platforms: 29 | 30 | * Windows 7 64bit, Visual Studio 2013 31 | * CentOS 7, GCC 4.8.3 with -std=c++11 32 | * OS X 10.10, Xcode 6.1 with -std=c++11 33 | 34 | ## Install: 35 | * This tool is module based, you can place "DeformationLearningSolver" folder to any where. 36 | 37 | * Launch maya, drag install.mel into scene, a new icon will be created in current shelf, launch Deformation Learning Solver by clicking the icon. 38 | 39 | ### Manual Install: 40 | * What 'install.mel' does is to create 'DeformationLearningSolver.mod' in */YOUR/HOME/DIRECTORY/maya/modules* (ie. *C:/Users/YourName/Documents/maya/modules*), and setup the installation path, then maya will find this tool automatically. In the same way, you can put 'DeformationLearningSolver.mod' into any directory existing in 'MAYA\_MODULE\_PATH', then change the paths in it and make them point to the right position, maya will find it without difficulty. 41 | 42 | * There's a backup of 'DeformationLearningSolver.mod' in 'modules' folder, you can copy and paste it to anywhere rather than modify it, otherwise, 'install.mel' will fail to install. 43 | 44 | * Launch it with these python commands: 45 | > import DLS 46 | > DLS.launch() 47 | 48 | ## Features: 49 | * Convert deformation animation such as blend shapes, to skinned, weighted and bone joint animation. 50 | * Approximate deformation animation by solving the skinning weights with existing joints and joint animations. 51 | * Reverse skeleton animations from animated sequences with existing joints and skinning weights. 52 | 53 | ## Limitations: 54 | * Work with single mesh each time. 55 | 56 | ## Plug-ins: 57 | These plug-ins are included in this tool 58 | 59 | * SSDSolverCmd: the core functions of SSDR. 60 | * wbDeltaMushDeformer: a deformer based on [Delta Mush: Smoothing Deformations While Preserving Detail](http://dl.acm.org/citation.cfm?id=2633376), it's also a component in AdvanceSkeleton since 5.0. 61 | 62 | ## Usage: 63 | - There's no document for this tool, the only instruction you can find are those two Demos mentioned above. 64 | 65 | - This tool can either solve the best weight map with pre-define joints by user or extract specify number of joints, animations and weight map from a mesh sequences, the first case is extremely fast since it only need to solve the weight map with one iteration. 66 | 67 | - To solve weight map from existing joints, please bind mesh with skin cluster first, this tool will find joints involve, then put them into solver. Otherwise, it will solve mesh sequences with specify number of joints within max iterations. 68 | 69 | ### Parameters: 70 | Here are key parameters you should understand: 71 | 72 | - **Num of Bones**: specifies the number of joints will be created. 73 | - **Max Infs**: specifies the maximum number of weighted influences for a given point. 74 | - **Epsilon**: the computation will finish before it reaches the max iteration if the subtraction between Current Total Error and Previous Total Error is less than epsilon. 75 | - **Max Iters**: in general, more iterations can result in more accurate approximation, but I found 10 is sufficient in most cases. 76 | - **Target Mesh**: input animated mesh here will enable reverse enginnering feature as showed in [Demo v1.5](https://vimeo.com/138048608). 77 | 78 | ## History: 79 | #### 2017-11-13: v1.5.5 by Webber Huang 80 | - FIXED: unable to support arbitrary FPS 81 | 82 | #### 2017-07-31: v1.5.4 by Webber Huang 83 | - UPDATE: wbDeltaMush v1.8.1, fixed crash issue when mesh contains wrong UV 84 | - Compile against Maya 2017 85 | 86 | #### 2015-11-21: v1.5.3 by Webber Huang 87 | - UPDATE: wbDeltaMush v1.8.0, better performance and minor bugs fixed 88 | 89 | #### 2015-09-02: v1.5.0 by Webber Huang 90 | - NEW: wbDeltaMush is included 91 | - NEW: reverse bone animation from animated sequence 92 | - NEW: alternative update with existing bones and weights 93 | - NEW: a editor for sampling any attribute 94 | - UPDATE: parallelize bone transformation updating function, 30~40% faster than before 95 | - minor bugs fixed 96 | 97 | #### 2015-06-18: v1.0.0 by Webber Huang 98 | - Initial release 99 | 100 | 101 | ## References: 102 | 1. B. H. Le and Z. Deng, “Smooth Skinning Decomposition with Rigid Bones,” ACM Trans. Graph., vol. 31, no. 6, pp. 199:1–199:10, Nov. 2012. 103 | --------------------------------------------------------------------------------