├── __init__.py ├── .gitignore ├── maya ├── __init__.py ├── rig │ ├── __init__.py │ ├── dish │ │ ├── __init__.py │ │ ├── lunchBox │ │ │ ├── __init__.py │ │ │ ├── LocalAIM.zip │ │ │ ├── brownie.zip │ │ │ ├── caramel.zip │ │ │ ├── flamby.zip │ │ │ ├── reglisse.zip │ │ │ ├── tortilla.zip │ │ │ ├── worldAim.zip │ │ │ ├── twistKnot.zip │ │ │ ├── stringBlender.zip │ │ │ ├── geodesicWeight.zip │ │ │ └── reglisseFromSlice.zip │ │ ├── .gitignore │ │ ├── Tool.py │ │ ├── data.py │ │ ├── manager.py │ │ ├── core.py │ │ └── builder.py │ └── meal │ │ └── __init__.py └── plug-ins │ ├── numToString.py │ ├── twistKnot.py │ ├── toggleArray.py │ ├── recipe.py │ ├── heimer.py │ ├── twistReader.py │ ├── geodesicWeight.py │ ├── reglisse.py │ ├── yakisoba.py │ ├── caramel.py │ ├── tortilla.py │ └── brownie.py ├── Maya.env ├── INSTALL.md ├── license.md ├── README.md └── rbfTool.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /maya/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maya/rig/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maya/rig/dish/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maya/rig/meal/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maya/rig/dish/.gitignore: -------------------------------------------------------------------------------- 1 | src/ 2 | Edits/ -------------------------------------------------------------------------------- /Maya.env: -------------------------------------------------------------------------------- 1 | ccwLocation = D:\GitHub 2 | MAYA_PLUG_IN_PATH = %ccwLocation%\circeCharacterWorksTools\maya\plug-ins 3 | 4 | -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/LocalAIM.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/LocalAIM.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/brownie.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/brownie.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/caramel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/caramel.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/flamby.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/flamby.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/reglisse.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/reglisse.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/tortilla.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/tortilla.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/worldAim.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/worldAim.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/twistKnot.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/twistKnot.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/stringBlender.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/stringBlender.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/geodesicWeight.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/geodesicWeight.zip -------------------------------------------------------------------------------- /maya/rig/dish/lunchBox/reglisseFromSlice.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedricB/circeCharacterWorksTools/HEAD/maya/rig/dish/lunchBox/reglisseFromSlice.zip -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | ''' 2 | Install 3 | ======= 4 | -- extract or copy 'circeCharacterWorksTools' in a 'TargetDirectory'( called ccwLocation from now on ) 5 | -- change ccwLocation into maya.env( then copy this content into your local scripts/maya.env file) 6 | ''' 7 | 8 | #------------------------ copy paste this code in your script editor 9 | import sys, os 10 | TargetDirectory = 'D:\GitHub' 11 | if TargetDirectory not in sys.path: 12 | sys.path.append(TargetDirectory) 13 | 14 | #You will then invoke this package with 15 | import circeCharacterWorksTools as ccwLib -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Cedric BAZILLOU 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | circeCharacterWorksTools 2 | ======================== 3 | 4 | A set of tool for maya designed to handle character deformation effectively 5 | 6 | Feature |Description 7 | ---------------------------------|:-----------: 8 | Template based | All aspect of deformation organized into a logical unit : a dish 9 | Highly optimized | Each dish covers a simple task by using a custom foodNode 10 | Faster rig and smaller files | A foodNode is node baking lot of operations inside a black box, we interact with maya with nodes and need less scripting 11 | 12 | ### Installing 13 | 14 | 1. Download a [release][] 15 | 2. Unpack into a target folder 16 | 17 | ### maya environment variable 18 | ``` 19 | ccwLocation = D:\GitHub 20 | MAYA_PLUG_IN_PATH = %ccwLocation%\circeCharacterWorksTools\maya\plug-ins 21 | ``` 22 | 1. copy the above lines into your local maya.env text file 23 | 2. modify ccwLocation by your target folder 24 | 25 | ### USE 26 | 1. in your script editor 27 | ``` 28 | import maya.cmds as mc 29 | import sys, os 30 | TargetDirectory = 'D:\GitHub' 31 | if TargetDirectory not in sys.path: 32 | sys.path.append(TargetDirectory) 33 | 34 | import circeCharacterWorksTools.maya.rig.dish.Tool as bento 35 | bento.Tool().show() 36 | ``` 37 | -------------------------------------------------------------------------------- /maya/rig/dish/Tool.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | import maya.cmds as mc 3 | import maya.OpenMaya as OpenMaya 4 | import inspect 5 | import zipfile 6 | from functools import partial 7 | import json 8 | import uuid 9 | import datetime 10 | 11 | if 'dish.data' not in sys.modules.keys(): 12 | frme = inspect.currentframe() 13 | frameData = inspect.getframeinfo(frme) 14 | modulePath = os.path.dirname(frameData[0]) 15 | modulePath = os.path.dirname(modulePath) 16 | sys.path.append(modulePath) 17 | 18 | import dish.data as attrToFilter 19 | import dish.builder as dishBuilder 20 | import dish.manager as dishManager 21 | import dish.core as dishCore 22 | 23 | reload(attrToFilter) 24 | reload(dishBuilder) 25 | reload(dishManager) 26 | reload(dishCore) 27 | 28 | author = 'cedric bazillou 2013' 29 | version = 0.055 30 | 31 | class UI: 32 | def __init__(self): 33 | self.windowRef ='CCW_bentoUI' 34 | self.canvasSize =[430,400] 35 | self.UI_TAB = '' 36 | self.ToDelete = [] 37 | self.toresizeCtrl = '' 38 | self.toresizeCtrlB = '' 39 | self.modeMenu = '' 40 | self.tmpleLib = dishCore.IO() 41 | self.dishBuilder = dishBuilder.UI() 42 | self.dishManager = dishManager.UI() 43 | def show(self): 44 | if mc.window(self.windowRef,q=True,ex=True) == True: 45 | mc.deleteUI(self.windowRef) 46 | mc.window(self.windowRef , title="CCW_Bento Tools %s"%version, widthHeight=(self.canvasSize[0],self.canvasSize[1]),rtf=True,s=False ) 47 | FrameAnchor = mc.frameLayout(cll=False,lv=False,mw=5,w=self.canvasSize[0]) 48 | mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='out',mw=2,mh=2 ) 49 | 50 | self.modeMenu = mc.optionMenu( label='' ,w=self.canvasSize[0]+16,cc=self.showModUI ) 51 | mc.menuItem( label='Manager' ) 52 | mc.menuItem( label='Builder' ) 53 | 54 | self.UI_TAB = mc.columnLayout(p=FrameAnchor,adjustableColumn=True) 55 | self.dishManager.widget(self.UI_TAB) 56 | 57 | mc.textField( 'copyrigth_txFld',ed=False ,tx=' AUTHOR : cedric BAZILLOU 2014 -- http://circecharacterworks.wordpress.com/ ',p= FrameAnchor ) 58 | 59 | mc.showWindow( self.windowRef) 60 | mc.window( self.windowRef,e=True, widthHeight=(self.canvasSize[0],self.canvasSize[1]) ) 61 | def showModUI(self,*args): 62 | dishMode = mc.optionMenu( self.modeMenu,q=True,sl=True) 63 | dishList = self.tmpleLib.exposeZipTemplate() 64 | 65 | childArray = mc.columnLayout( self.UI_TAB ,q=True,childArray=True) 66 | if childArray is not None: 67 | for obj in childArray: 68 | mc.deleteUI(obj) 69 | 70 | if dishMode == 1: 71 | self.dishManager.widget(self.UI_TAB) 72 | else: 73 | self.dishBuilder.widget(self.UI_TAB) 74 | -------------------------------------------------------------------------------- /maya/plug-ins/numToString.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # numToString.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | L I C E N S E: 10 | Copyright (c) 2013 Cedric BAZILLOU All rights reserved. 11 | 12 | Permission is hereby granted 13 | -to modify the file 14 | -distribute 15 | -share 16 | -do derivative work 17 | 18 | The above copyright notice and this permission notice shall be included in all copies of the Software 19 | and is subject to the following conditions: 20 | - These 3 companies uses the same type of license 21 | - credit the original author 22 | - does not claim patent nor copyright from the original work 23 | - this plugin is not sold to third parties 24 | 25 | P U R P O S E: 26 | Control a rear or frond quadruped leg 27 | - compact several nodes and parameter in one place 28 | 29 | I N S T A L L A T I O N: 30 | Copy the "numToString.py" to your Maya plugins directory 31 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 32 | 33 | or better in your maya user directory: 34 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 35 | ''' 36 | 37 | 38 | import math, sys 39 | import maya.OpenMaya as OpenMaya 40 | import maya.OpenMayaMPx as OpenMayaMPx 41 | 42 | kPluginNodeName = "numToString" 43 | kPluginNodeId = OpenMaya.MTypeId(0x24BCD179) 44 | 45 | class numToString(OpenMayaMPx.MPxNode): 46 | labelStr = OpenMaya.MObject() 47 | inputNum = OpenMaya.MObject() 48 | output = OpenMaya.MObject() 49 | 50 | def __init__(self): 51 | OpenMayaMPx.MPxNode.__init__(self) 52 | 53 | def compute(self,Plug,Data): 54 | if Plug == self.output: 55 | labelStr_Hdle = Data.inputValue(self.labelStr) 56 | inputNum_Hdle = Data.inputValue(self.inputNum) 57 | output_Handle = Data.outputValue(self.output) 58 | 59 | inDouble = inputNum_Hdle.asDouble() 60 | inlabel = labelStr_Hdle.asString() 61 | resStream = inlabel + '_' + str(round( inDouble , 3)) 62 | if len ( inlabel ) == 0: 63 | resStream = str(round( inDouble , 3)) 64 | 65 | output_Handle.setString( resStream ) 66 | output_Handle.setClean() 67 | def nodeCreator(): 68 | return OpenMayaMPx.asMPxPtr(numToString()) 69 | 70 | def nodeInitializer(): 71 | 72 | labelStr_Attr = OpenMaya.MFnTypedAttribute() 73 | numToString.labelStr = labelStr_Attr.create( "labelStr", "lss", OpenMaya.MFnData.kString ) 74 | labelStr_Attr.setStorable(1) 75 | labelStr_Attr.setKeyable(0) 76 | labelStr_Attr.setHidden(False) 77 | numToString.addAttribute( numToString.labelStr ) 78 | 79 | 80 | inputShape_Attr = OpenMaya.MFnNumericAttribute() 81 | numToString.inputNum = inputShape_Attr.create( "inputNum", "num", OpenMaya.MFnNumericData.kDouble ) 82 | inputShape_Attr.setStorable(0) 83 | inputShape_Attr.setKeyable(0) 84 | inputShape_Attr.setHidden(0) 85 | numToString.addAttribute( numToString.inputNum ) 86 | 87 | output_Attr = OpenMaya.MFnTypedAttribute() 88 | numToString.output = output_Attr.create( "output", "out", OpenMaya.MFnData.kString ) 89 | output_Attr.setStorable(0) 90 | output_Attr.setKeyable(0) 91 | output_Attr.setHidden(False) 92 | numToString.addAttribute( numToString.output) 93 | 94 | numToString.attributeAffects( numToString.inputNum , numToString.output ) 95 | numToString.attributeAffects( numToString.labelStr , numToString.output ) 96 | 97 | 98 | def initializePlugin(mobject): 99 | mplugin = OpenMayaMPx.MFnPlugin(mobject, "Bazillou2010", "1.0", "Any") 100 | try: 101 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 102 | except: 103 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 104 | 105 | 106 | def uninitializePlugin(mobject): 107 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 108 | try: 109 | mplugin.deregisterNode( kPluginNodeId ) 110 | except: 111 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /maya/plug-ins/twistKnot.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # twistKnot.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | L I C E N S E: 10 | Copyright (c) 2014 Cedric BAZILLOU All rights reserved. 11 | 12 | Permission is hereby granted 13 | -to modify the file 14 | -distribute 15 | -share 16 | -do derivative work 17 | 18 | The above copyright notice and this permission notice shall be included in all copies of the Software 19 | and is subject to the following conditions: 20 | - Te user uses the same type of license 21 | - credit the original author 22 | - does not claim patent nor copyright from the original work 23 | 24 | P U R P O S E: 25 | - compute an aim constraint without using any up vector 26 | - use quaternion to build a reliable orientation 27 | 28 | I N S T A L L A T I O N: 29 | Copy the "twistKnot.py" to your Maya plugins directory 30 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 31 | 32 | or better in your maya user directory: 33 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 34 | ''' 35 | __plug_in__Version = "0.15.2" 36 | __author = "Bazillou2013" 37 | 38 | import math 39 | import maya.OpenMaya as OpenMaya 40 | import maya.OpenMayaMPx as OpenMayaMPx 41 | 42 | kPluginNodeName = "twistKnot" 43 | kPluginNodeId = OpenMaya.MTypeId(0x1CB7131) 44 | 45 | 46 | 47 | 48 | class twistKnot(OpenMayaMPx.MPxNode): 49 | def __init__(self): 50 | OpenMayaMPx.MPxNode.__init__(self) 51 | 52 | def compute(self,Plug,Data): 53 | refMatrixValue = Data.inputValue(self.refMatrix).asMatrix() 54 | driverMatrixValue = Data.inputValue(self.driverMatrix).asMatrix() 55 | 56 | aimVector = (OpenMaya.MVector(1,0,0)*driverMatrixValue*refMatrixValue.inverse()).normal() 57 | referenceVector = OpenMaya.MVector(1,0,0) 58 | 59 | aimQuaternion = OpenMaya.MQuaternion() 60 | aimMat = referenceVector.rotateTo(aimVector).asMatrix() 61 | 62 | newMat = aimMat #*refMatrixValue 63 | eulerRotationValue = OpenMaya.MTransformationMatrix(newMat).eulerRotation() 64 | 65 | outputHandle = Data.outputValue(self.outRotate ) 66 | outputHandle.set3Double( eulerRotationValue.x,eulerRotationValue.y,eulerRotationValue.z ) 67 | 68 | Data.setClean(Plug) 69 | def nodeCreator(): 70 | return OpenMayaMPx.asMPxPtr(twistKnot()) 71 | def nodeInitializer(): 72 | typed_Attr = OpenMaya.MFnTypedAttribute() 73 | nAttr = OpenMaya.MFnNumericAttribute() 74 | unitAttr = OpenMaya.MFnUnitAttribute() 75 | matAttr = OpenMaya.MFnMatrixAttribute() 76 | cAttr = OpenMaya.MFnCompoundAttribute() 77 | 78 | 79 | twistKnot.refMatrix = matAttr.create("refMatrix", "rMat",OpenMaya.MFnMatrixAttribute.kDouble) 80 | matAttr.setStorable(1) 81 | matAttr.setKeyable(0) 82 | matAttr.setHidden(True) 83 | twistKnot.addAttribute(twistKnot.refMatrix) 84 | 85 | twistKnot.driverMatrix = matAttr.create("driverMatrix", "drMat",OpenMaya.MFnMatrixAttribute.kDouble) 86 | matAttr.setStorable(1) 87 | matAttr.setKeyable(0) 88 | matAttr.setHidden(True) 89 | twistKnot.addAttribute(twistKnot.driverMatrix) 90 | 91 | #---------------------------------------------------------------------------- Output Attributes 92 | defaultAngle = OpenMaya.MAngle ( 0.0, OpenMaya.MAngle.kDegrees ) 93 | twistKnot.outRotateX = unitAttr.create( "outRotateX", "orx", defaultAngle) 94 | twistKnot.outRotateY = unitAttr.create( "outRotateY", "ory", defaultAngle) 95 | twistKnot.outRotateZ = unitAttr.create( "outRotateZ", "orz", defaultAngle) 96 | twistKnot.outRotate = nAttr.create( "outRotate", "or", twistKnot.outRotateX,twistKnot.outRotateY,twistKnot.outRotateZ) 97 | nAttr.setStorable(1) 98 | nAttr.setKeyable(0) 99 | nAttr.setHidden(0) 100 | twistKnot.addAttribute( twistKnot.outRotate ) 101 | 102 | twistKnot.attributeAffects( twistKnot.refMatrix, twistKnot.outRotate) 103 | twistKnot.attributeAffects( twistKnot.driverMatrix, twistKnot.outRotate) 104 | 105 | def initializePlugin(mobject): 106 | mplugin = OpenMayaMPx.MFnPlugin(mobject, __author, __plug_in__Version, "Any") 107 | try: 108 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 109 | except: 110 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 111 | def uninitializePlugin(mobject): 112 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 113 | try: 114 | mplugin.deregisterNode( kPluginNodeId ) 115 | except: 116 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise -------------------------------------------------------------------------------- /maya/plug-ins/toggleArray.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # toggleArray.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | L I C E N S E: 10 | Copyright (c) 2013 Cedric BAZILLOU All rights reserved. 11 | 12 | Permission is hereby granted 13 | -to modify the file 14 | -distribute 15 | -share 16 | -do derivative work 17 | 18 | The above copyright notice and this permission notice shall be included in all copies of the Software 19 | and is subject to the following conditions: 20 | - Te user uses the same type of license 21 | - credit the original author 22 | - does not claim patent nor copyright from the original work 23 | 24 | P U R P O S E: 25 | toggleArray weights for space switching, visibility, blendshape etc 26 | 27 | I N S T A L L A T I O N: 28 | Copy the "toggleArray.py" to your Maya plugins directory 29 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 30 | 31 | or better in your maya user directory: 32 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 33 | ''' 34 | 35 | import math, sys 36 | import maya.OpenMaya as OpenMaya 37 | import maya.OpenMayaMPx as OpenMayaMPx 38 | import maya.cmds as cmds 39 | 40 | kPluginNodeName = "toggleArray" 41 | kPluginNodeId = OpenMaya.MTypeId(0xACC1246) 42 | kPluginNodeAuthor = "Bazillou cedric2009" 43 | kPluginNodeVersion = "1.0.0" 44 | 45 | 46 | class toggleArray(OpenMayaMPx.MPxNode): 47 | def compute(self,Plug,Data): 48 | #data handles Layout 49 | numberofOutput_Val = Data.inputValue(self.numberofOutput ).asInt() 50 | activeIndex_Val = Data.inputValue(self.activeIndex ).asInt() 51 | outState_handle = Data.outputArrayValue(self.outState ) 52 | activeValue_Val = Data.inputValue(self.activeValue ).asInt() 53 | disableValue_Val = Data.inputValue(self.disableValue ).asInt() 54 | #FoolProof check 55 | if activeIndex_Val > (numberofOutput_Val - 1): 56 | activeIndex_Val = numberofOutput_Val - 1 57 | ThsNde = self.thisMObject() 58 | 59 | self.write_ouputState( outState_handle,numberofOutput_Val,activeIndex_Val,ThsNde,activeValue_Val,disableValue_Val ) 60 | def write_ouputState(self,outState_handle,numberofOutput_Val,activeIndex_Val,ThsNde ,activeValue_Val,disableValue_Val): 61 | cBuilder = outState_handle.builder() 62 | 63 | stateList = [] 64 | stateList = [ disableValue_Val for k in range(numberofOutput_Val) ] 65 | stateList[activeIndex_Val] = activeValue_Val 66 | 67 | currentDH = OpenMaya.MDataHandle() 68 | for n in range(0,numberofOutput_Val): 69 | currentDH = cBuilder.addElement(n) 70 | currentDH.setInt(stateList[n]) 71 | 72 | bldChck = cBuilder.elementCount() 73 | # prune unwanted index --> equivalent to removeMultiInstance... 74 | if bldChck>numberofOutput_Val: 75 | depFn = OpenMaya.MFnDependencyNode( ThsNde ) 76 | curvePointsPlug = depFn.findPlug('outState') 77 | outName = curvePointsPlug.info() 78 | for k in range(bldChck-1,numberofOutput_Val-1,-1): 79 | try: 80 | cBuilder.removeElement(k) 81 | except: 82 | # --> a bit dirty but it help when node is not connected yet we have access to the correct number of output attribute 83 | # when node is connected this fallback is not needed anymore 84 | cmds.removeMultiInstance( '%s[%s]'%(outName,k), b=True ) 85 | outState_handle.set(cBuilder) 86 | outState_handle.setAllClean() 87 | def nodeCreator(): 88 | return OpenMayaMPx.asMPxPtr(toggleArray()) 89 | def link_relashionShip( DriverList, driven_Attribute ): 90 | for driver in DriverList: 91 | toggleArray.attributeAffects(driver,driven_Attribute) 92 | def nodeInitializer(): 93 | nAttr = OpenMaya.MFnNumericAttribute() 94 | 95 | #----------------------------------------------------------------------------------------------- Input Attributes 96 | 97 | toggleArray.numberofOutput = nAttr.create( "numberOfOutput", "cn", OpenMaya.MFnNumericData.kInt,1) 98 | nAttr.setStorable(1) 99 | nAttr.setKeyable(1) 100 | nAttr.setHidden(0) 101 | nAttr.setMin(1) 102 | nAttr.setSoftMax(16) 103 | toggleArray.addAttribute( toggleArray.numberofOutput ) 104 | 105 | toggleArray.activeIndex = nAttr.create( "activeIndex", "aID", OpenMaya.MFnNumericData.kInt,0) 106 | nAttr.setStorable(1) 107 | nAttr.setKeyable(1) 108 | nAttr.setHidden(0) 109 | nAttr.setMin(0) 110 | toggleArray.addAttribute( toggleArray.activeIndex ) 111 | 112 | toggleArray.activeValue = nAttr.create( "activeValue", "aVle", OpenMaya.MFnNumericData.kInt,1) 113 | nAttr.setStorable(1) 114 | nAttr.setKeyable(1) 115 | nAttr.setHidden(0) 116 | nAttr.setMin(0) 117 | toggleArray.addAttribute( toggleArray.activeValue ) 118 | 119 | toggleArray.disableValue = nAttr.create( "disableValue", "dVle", OpenMaya.MFnNumericData.kInt,0) 120 | nAttr.setStorable(1) 121 | nAttr.setKeyable(1) 122 | nAttr.setHidden(0) 123 | toggleArray.addAttribute( toggleArray.disableValue ) 124 | 125 | toggleArray.outState = nAttr.create( "outState", "oSt", OpenMaya.MFnNumericData.kInt) 126 | nAttr.setStorable(1) 127 | nAttr.setKeyable(0) 128 | nAttr.setHidden(0) 129 | nAttr.setArray(1) 130 | nAttr.setUsesArrayDataBuilder(1) 131 | toggleArray.addAttribute( toggleArray.outState ) 132 | 133 | DriverList = [ toggleArray.numberofOutput, toggleArray.activeIndex, toggleArray.activeValue , toggleArray.disableValue ] 134 | link_relashionShip(DriverList,toggleArray.outState ) 135 | 136 | def initializePlugin(mobject): 137 | mplugin = OpenMayaMPx.MFnPlugin(mobject, kPluginNodeAuthor, kPluginNodeVersion, "Any") 138 | try: 139 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 140 | except: 141 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 142 | def uninitializePlugin(mobject): 143 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 144 | try: 145 | mplugin.deregisterNode( kPluginNodeId ) 146 | except: 147 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise -------------------------------------------------------------------------------- /maya/plug-ins/recipe.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # recipe.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | L I C E N S E: 10 | Copyright (c) 2013 Cedric BAZILLOU All rights reserved. 11 | 12 | Permission is hereby granted 13 | -to modify the file 14 | -distribute 15 | -share 16 | -do derivative work 17 | 18 | P U R P O S E: 19 | Compute twist on a per segment level --> we expect normalize u values.... 20 | I N S T A L L A T I O N: 21 | Copy the "recipe.py" to your Maya plugins directory 22 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 23 | 24 | or better in your maya user directory: 25 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 26 | ''' 27 | 28 | __plug_in__Version = "0.13" 29 | __author = "Bazillou2013" 30 | 31 | import math 32 | import maya.OpenMaya as OpenMaya 33 | import maya.OpenMayaMPx as OpenMayaMPx 34 | 35 | kPluginNodeName = "recipe" 36 | kPluginNodeId = OpenMaya.MTypeId(0xBCB7155) 37 | 38 | 39 | 40 | 41 | class recipe(OpenMayaMPx.MPxNode): 42 | def __init__(self): 43 | OpenMayaMPx.MPxNode.__init__(self) 44 | def compute(self,Plug,Data): 45 | return 46 | 47 | def nodeCreator(): 48 | return OpenMayaMPx.asMPxPtr(recipe()) 49 | def nodeInitializer(): 50 | gAttr = OpenMaya.MFnGenericAttribute() 51 | cAttr = OpenMaya.MFnCompoundAttribute() 52 | typed_Attr = OpenMaya.MFnTypedAttribute() 53 | nAttr = OpenMaya.MFnNumericAttribute() 54 | 55 | recipe.inputGrp = nAttr.create( "inputGrp", "inGr", OpenMaya.MFnNumericData.kDouble ) 56 | nAttr.setStorable(0) 57 | nAttr.setHidden(0) 58 | recipe.addAttribute(recipe.inputGrp) 59 | 60 | recipe.outputGrp = nAttr.create( "outputGrp", "outGr", OpenMaya.MFnNumericData.kDouble ) 61 | nAttr.setStorable(0) 62 | nAttr.setHidden(0) 63 | recipe.addAttribute(recipe.outputGrp) 64 | 65 | recipe.version = typed_Attr.create( "version", "vrs", OpenMaya.MFnData.kString ) 66 | typed_Attr.setStorable(1) 67 | typed_Attr.setHidden(0) 68 | recipe.addAttribute(recipe.version) 69 | 70 | recipe.foodType = typed_Attr.create( "foodType", "fdtp", OpenMaya.MFnData.kString ) 71 | typed_Attr.setStorable(1) 72 | typed_Attr.setHidden(0) 73 | recipe.addAttribute(recipe.foodType) 74 | 75 | recipe.author = typed_Attr.create( "author", "aut", OpenMaya.MFnData.kString ) 76 | typed_Attr.setStorable(1) 77 | typed_Attr.setHidden(0) 78 | recipe.addAttribute(recipe.author) 79 | 80 | recipe.gitSource = typed_Attr.create( "gitSource", "gtS", OpenMaya.MFnData.kString ) 81 | typed_Attr.setStorable(1) 82 | typed_Attr.setHidden(0) 83 | recipe.addAttribute(recipe.gitSource) 84 | 85 | recipe.releaseDate = typed_Attr.create( "releaseDate", "rls", OpenMaya.MFnData.kString ) 86 | typed_Attr.setStorable(1) 87 | typed_Attr.setHidden(0) 88 | recipe.addAttribute(recipe.releaseDate) 89 | 90 | recipe.inlink = gAttr.create( "inlink", "ilk" ) 91 | gAttr.setStorable(0) 92 | gAttr.setHidden(1) 93 | gAttr.addDataAccept ( OpenMaya.MFnData.kAny ) 94 | gAttr.addDataAccept ( OpenMaya.MFnData.kString ) 95 | gAttr.addDataAccept ( OpenMaya.MFnData.kMatrix ) 96 | gAttr.addDataAccept ( OpenMaya.MFnData.kStringArray ) 97 | gAttr.addDataAccept ( OpenMaya.MFnData.kDoubleArray ) 98 | gAttr.addDataAccept ( OpenMaya.MFnData.kIntArray ) 99 | gAttr.addDataAccept ( OpenMaya.MFnData.kPointArray ) 100 | gAttr.addDataAccept ( OpenMaya.MFnData.kVectorArray ) 101 | gAttr.addDataAccept ( OpenMaya.MFnData.kMesh ) 102 | gAttr.addDataAccept ( OpenMaya.MFnData.kLattice ) 103 | gAttr.addDataAccept ( OpenMaya.MFnData.kNurbsCurve ) 104 | gAttr.addDataAccept ( OpenMaya.MFnData.kNurbsSurface ) 105 | 106 | recipe.inLabel = typed_Attr.create( "inLabel", "ilb", OpenMaya.MFnData.kString ) 107 | typed_Attr.setStorable(1) 108 | 109 | recipe.inWidgetID = typed_Attr.create( "inWidgetID", "iwID", OpenMaya.MFnData.kString ) 110 | typed_Attr.setStorable(1) 111 | 112 | recipe.input_useParentHub = nAttr.create( "input_useParentHub", "inHB", OpenMaya.MFnNumericData.kBoolean,False ) 113 | nAttr.setStorable(1) 114 | nAttr.setHidden(1) 115 | 116 | recipe.input = cAttr.create( "input", "in" ) 117 | cAttr.addChild(recipe.inlink) 118 | cAttr.addChild(recipe.inLabel) 119 | cAttr.addChild(recipe.inWidgetID) 120 | cAttr.addChild(recipe.input_useParentHub) 121 | 122 | cAttr.setArray(1) 123 | recipe.addAttribute(recipe.input) 124 | 125 | recipe.outLink = gAttr.create( "outLink", "oLk" ) 126 | gAttr.setStorable(0) 127 | gAttr.addDataAccept ( OpenMaya.MFnData.kAny ) 128 | gAttr.addDataAccept ( OpenMaya.MFnData.kString ) 129 | gAttr.addDataAccept ( OpenMaya.MFnData.kMatrix ) 130 | gAttr.addDataAccept ( OpenMaya.MFnData.kStringArray ) 131 | gAttr.addDataAccept ( OpenMaya.MFnData.kDoubleArray ) 132 | gAttr.addDataAccept ( OpenMaya.MFnData.kIntArray ) 133 | gAttr.addDataAccept ( OpenMaya.MFnData.kPointArray ) 134 | gAttr.addDataAccept ( OpenMaya.MFnData.kVectorArray ) 135 | gAttr.addDataAccept ( OpenMaya.MFnData.kMesh ) 136 | gAttr.addDataAccept ( OpenMaya.MFnData.kLattice ) 137 | gAttr.addDataAccept ( OpenMaya.MFnData.kNurbsCurve ) 138 | gAttr.addDataAccept ( OpenMaya.MFnData.kNurbsSurface ) 139 | 140 | recipe.outLabel = typed_Attr.create( "outLabel", "olb", OpenMaya.MFnData.kString ) 141 | typed_Attr.setStorable(1) 142 | 143 | recipe.outWidgetID = typed_Attr.create( "outWidgetID", "owID", OpenMaya.MFnData.kString ) 144 | typed_Attr.setStorable(1) 145 | 146 | recipe.output_useParentHub = nAttr.create( "output_useParentHub", "outHB", OpenMaya.MFnNumericData.kBoolean,False ) 147 | nAttr.setStorable(1) 148 | nAttr.setHidden(1) 149 | 150 | recipe.output = cAttr.create( "output", "out" ) 151 | cAttr.addChild(recipe.outLink) 152 | cAttr.addChild(recipe.outLabel) 153 | cAttr.addChild(recipe.outWidgetID) 154 | cAttr.addChild(recipe.output_useParentHub) 155 | cAttr.setArray(1) 156 | recipe.addAttribute(recipe.output) 157 | 158 | 159 | def initializePlugin(mobject): 160 | mplugin = OpenMayaMPx.MFnPlugin(mobject, __author, __plug_in__Version, "Any") 161 | try: 162 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 163 | except: 164 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 165 | def uninitializePlugin(mobject): 166 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 167 | try: 168 | mplugin.deregisterNode( kPluginNodeId ) 169 | except: 170 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise -------------------------------------------------------------------------------- /maya/plug-ins/heimer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # heimer.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | L I C E N S E: 10 | 1. The MIT License (MIT) 11 | Copyright (c) 2009-2015 Cedric BAZILLOU cedricbazillou@gmail.com 12 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 13 | and associated documentation files (the "Software"), to deal in the Software without restriction, 14 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 15 | sub-license, and/or sell copies of the Software, and to permit persons 16 | to whom the Software is furnished to do so, subject to the following conditions: 17 | The above copyright notice and this permission notice shall be included in all copies 18 | or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 21 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | 24 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 25 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE, 26 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | 29 | P U R P O S E: 30 | - compute an aim constraint without using any up vector 31 | - use quaternion to build a reliable orientation 32 | 33 | I N S T A L L A T I O N: 34 | Copy the "heimer.py" to your Maya plugins directory 35 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 36 | 37 | or better in your maya user directory: 38 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 39 | @author Cedric Bazillou 40 | @blog http://circecharacterworks.wordpress.com/ 41 | @note version 0.1.0 42 | @see see statement goes here. 43 | ''' 44 | 45 | 46 | import math, sys 47 | import maya.OpenMaya as OpenMaya 48 | import maya.OpenMayaMPx as OpenMayaMPx 49 | 50 | kPluginNodeName = "heimer" 51 | kPluginNodeId = OpenMaya.MTypeId(0xAAC0F775) 52 | kPluginNodeAuthor = "Bazillou cedric2009" 53 | kPluginNodeVersion = "1.0.1" 54 | 55 | 56 | class heimer(OpenMayaMPx.MPxNode): 57 | referenceVector = OpenMaya.MVector(1,0,0) 58 | def __init__(self): 59 | OpenMayaMPx.MPxNode.__init__(self) 60 | 61 | def computeLocalOrient(self,Data): 62 | worldToLocalValue = Data.inputValue(self.worldToLocal).asMatrix() 63 | targetPosition_Hdle = Data.inputValue(self.targetPosition) 64 | parentHandle = Data.outputValue(self.local) 65 | outputHandle = parentHandle.child(self.outRotate) 66 | 67 | inVec = targetPosition_Hdle.asVector() 68 | pointCnv = OpenMaya.MPoint(inVec)*worldToLocalValue.inverse() 69 | theTargetVector = OpenMaya.MVector(pointCnv).normal() 70 | aimQuaternion = self.referenceVector.rotateTo(theTargetVector) 71 | eulerRotationValue = aimQuaternion.asEulerRotation() 72 | 73 | outputHandle.set3Double( eulerRotationValue.x,eulerRotationValue.y,eulerRotationValue.z ) 74 | parentHandle.setClean() 75 | 76 | def computeWorldData(self,Data): 77 | worldToLocalValue = Data.inputValue(self.worldToLocal).asMatrix() 78 | targetMatrixValue = Data.inputValue(self.targetMatrix).asMatrix() 79 | 80 | parentHandle = Data.outputValue(self.world) 81 | outRotate_DH = parentHandle.child(self.rotate ) 82 | outTranslate_DH = parentHandle.child(self.translate) 83 | outMatrix_DH = parentHandle.child(self.outMatrix) 84 | 85 | convertWorldToLocal_Value = Data.inputValue(self.convertWorldToLocal).asBool() 86 | 87 | worldMat = worldToLocalValue.inverse() 88 | pointCnv = OpenMaya.MPoint()*targetMatrixValue*worldMat 89 | theTargetVector = OpenMaya.MVector(pointCnv).normal() 90 | aimMatrix = self.referenceVector.rotateTo(theTargetVector).asMatrix() 91 | finalMat = aimMatrix*worldToLocalValue 92 | 93 | if convertWorldToLocal_Value == True: 94 | finalMat = aimMatrix 95 | 96 | matFn = OpenMaya.MTransformationMatrix(finalMat) 97 | blendRot = matFn.eulerRotation() 98 | outRotate_DH.set3Double(blendRot.x,blendRot.y,blendRot.z) 99 | 100 | outPnt = OpenMaya.MPoint()*finalMat 101 | outTranslate_DH.set3Double(outPnt.x,outPnt.y,outPnt.z) 102 | 103 | outMatrix_DH.setMMatrix(finalMat) 104 | parentHandle.setClean() 105 | 106 | def compute(self,Plug,Data): 107 | self.computeLocalOrient(Data) 108 | self.computeWorldData(Data) 109 | 110 | def nodeCreator(): 111 | return OpenMayaMPx.asMPxPtr(heimer()) 112 | 113 | def nodeInitializer(): 114 | nAttr = OpenMaya.MFnNumericAttribute() 115 | matAttr = OpenMaya.MFnMatrixAttribute() 116 | unitAttr = OpenMaya.MFnUnitAttribute() 117 | cAttr = OpenMaya.MFnCompoundAttribute() 118 | 119 | heimer.worldToLocal = matAttr.create("worldToLocal", "wtlMat",OpenMaya.MFnMatrixAttribute.kDouble) 120 | matAttr.setHidden(True) 121 | heimer.addAttribute(heimer.worldToLocal) 122 | 123 | heimer.targetMatrix = matAttr.create("targetMatrix", "trgMat",OpenMaya.MFnMatrixAttribute.kDouble) 124 | matAttr.setHidden(True) 125 | heimer.addAttribute(heimer.targetMatrix) 126 | 127 | heimer.targetPosition = nAttr.create( "targetPosition", "trgPos", OpenMaya.MFnNumericData.k3Double ) 128 | nAttr.setStorable(0) 129 | nAttr.setKeyable(1) 130 | nAttr.setHidden(0) 131 | heimer.addAttribute( heimer.targetPosition ) 132 | 133 | defaultAngle = OpenMaya.MAngle ( 0.0, OpenMaya.MAngle.kDegrees ) 134 | defaultDist = OpenMaya.MDistance ( 0.0, OpenMaya.MDistance.kCentimeters ) 135 | 136 | heimer.outRotateX = unitAttr.create( "outRotateX", "orx", defaultAngle) 137 | heimer.outRotateY = unitAttr.create( "outRotateY", "ory", defaultAngle) 138 | heimer.outRotateZ = unitAttr.create( "outRotateZ", "orz", defaultAngle) 139 | heimer.outRotate = nAttr.create( "outRotate", "or", heimer.outRotateX,heimer.outRotateY,heimer.outRotateZ) 140 | 141 | heimer.local = cAttr.create( "local", "lcl" ) 142 | cAttr.addChild(heimer.outRotate) 143 | cAttr.setStorable(0) 144 | cAttr.setKeyable(0) 145 | cAttr.setHidden(True) 146 | heimer.addAttribute(heimer.local) 147 | 148 | heimer.translateX = unitAttr.create( "translateX", "tx", defaultDist) 149 | heimer.translateY = unitAttr.create( "translateY", "ty", defaultDist) 150 | heimer.translateZ = unitAttr.create( "translateZ", "tz", defaultDist) 151 | heimer.translate = nAttr.create( "translate", "t",heimer.translateX,heimer.translateY,heimer.translateZ) 152 | 153 | heimer.rotateX = unitAttr.create( "rotateX", "rx", defaultAngle) 154 | heimer.rotateY = unitAttr.create( "rotateY", "ry", defaultAngle) 155 | heimer.rotateZ = unitAttr.create( "rotateZ", "rz", defaultAngle) 156 | heimer.rotate = nAttr.create( "rotate", "r", heimer.rotateX,heimer.rotateY,heimer.rotateZ) 157 | 158 | heimer.outMatrix = matAttr.create("outMatrix", "oMat",OpenMaya.MFnMatrixAttribute.kDouble) 159 | heimer.outScale = nAttr.create( "outScale", "outS", OpenMaya.MFnNumericData.k3Double,1.0 ) 160 | 161 | heimer.convertWorldToLocal = nAttr.create( "convertWorldToLocal", "cnv", OpenMaya.MFnNumericData.kBoolean,False ) 162 | heimer.addAttribute(heimer.convertWorldToLocal) 163 | 164 | heimer.world = cAttr.create( "world", "wrl" ) 165 | cAttr.addChild(heimer.rotate) 166 | cAttr.addChild(heimer.translate) 167 | cAttr.addChild( heimer.outScale) 168 | cAttr.addChild(heimer.outMatrix) 169 | cAttr.setStorable(0) 170 | cAttr.setKeyable(0) 171 | cAttr.setHidden(True) 172 | heimer.addAttribute(heimer.world) 173 | 174 | heimer.attributeAffects( heimer.convertWorldToLocal , heimer.local ) 175 | heimer.attributeAffects( heimer.targetPosition, heimer.local ) 176 | heimer.attributeAffects( heimer.worldToLocal , heimer.local ) 177 | heimer.attributeAffects( heimer.targetMatrix , heimer.local ) 178 | 179 | heimer.attributeAffects( heimer.worldToLocal , heimer.world ) 180 | heimer.attributeAffects( heimer.targetMatrix , heimer.world ) 181 | heimer.attributeAffects( heimer.convertWorldToLocal , heimer.world ) 182 | 183 | return 184 | def initializePlugin(mobject): 185 | mplugin = OpenMayaMPx.MFnPlugin(mobject, kPluginNodeAuthor, kPluginNodeVersion, "Any") 186 | try: 187 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 188 | except: 189 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 190 | 191 | 192 | def uninitializePlugin(mobject): 193 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 194 | try: 195 | mplugin.deregisterNode( kPluginNodeId ) 196 | except: 197 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /maya/plug-ins/twistReader.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # twistReader.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | L I C E N S E: 10 | 1. The MIT License (MIT) 11 | Copyright (c) 2009-2015 Cedric BAZILLOU cedricbazillou@gmail.com 12 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 13 | and associated documentation files (the "Software"), to deal in the Software without restriction, 14 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 15 | sub-license, and/or sell copies of the Software, and to permit persons 16 | to whom the Software is furnished to do so, subject to the following conditions: 17 | The above copyright notice and this permission notice shall be included in all copies 18 | or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 21 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | 24 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 25 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE, 26 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | P U R P O S E: 29 | - use quaternion to build a reliable reference space 30 | - this space will be use against a target matrix to extract a signed twist values 31 | 32 | I N S T A L L A T I O N: 33 | Copy the "twistReader.py" to your Maya plugins directory 34 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 35 | 36 | or better in your maya user directory: 37 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 38 | ''' 39 | __plug_in__Version = "0.15.2" 40 | __author = "Bazillou2013" 41 | 42 | import math 43 | import maya.OpenMaya as OpenMaya 44 | import maya.OpenMayaMPx as OpenMayaMPx 45 | 46 | kPluginNodeName = "twistReader" 47 | kPluginNodeId = OpenMaya.MTypeId(0x1CB7138) 48 | 49 | 50 | class twistReader(OpenMayaMPx.MPxNode): 51 | def __init__(self): 52 | OpenMayaMPx.MPxNode.__init__(self) 53 | 54 | def extract_plane_twist(self, aimMatrix): 55 | twist_Normal = OpenMaya.MVector.yAxis*aimMatrix 56 | angleOutput = OpenMaya.MVector.yAxis.angle(twist_Normal) 57 | 58 | if twist_Normal.z > 0.0: 59 | angleOutput *= -1.0 60 | 61 | return math.degrees(angleOutput) 62 | 63 | def compute(self,Plug,Data): 64 | refMatrixValue = Data.inputValue(self.refMatrix).asMatrix() 65 | driverMatrixValue = Data.inputValue(self.driverMatrix).asMatrix() 66 | spaceMode = int(Data.inputValue(self.aimSpace).asShort()) 67 | 68 | refMatrixRotValue = OpenMaya.MTransformationMatrix(refMatrixValue).asRotateMatrix() 69 | driverMatrixRotValue = OpenMaya.MTransformationMatrix(driverMatrixValue).asRotateMatrix() 70 | 71 | aimVector = (OpenMaya.MVector(1,0,0)*driverMatrixRotValue*refMatrixRotValue.inverse()).normal() 72 | referenceVector = OpenMaya.MVector(1,0,0) 73 | 74 | aimQuaternion = OpenMaya.MQuaternion() 75 | aimMatrix = referenceVector.rotateTo(aimVector).asMatrix() 76 | aimMatrixInWorldSpace = aimMatrix * refMatrixValue 77 | 78 | twistValue = self.extract_plane_twist(aimMatrixInWorldSpace * driverMatrixValue.inverse()) 79 | 80 | if spaceMode == 0: 81 | eulerRotationValue = OpenMaya.MTransformationMatrix(aimMatrixInWorldSpace).eulerRotation() 82 | elif spaceMode == 1: 83 | eulerRotationValue = OpenMaya.MTransformationMatrix(aimMatrix).eulerRotation() 84 | elif spaceMode == 2: 85 | eulerRotationValue = OpenMaya.MEulerRotation(-math.radians(twistValue),0,0) 86 | 87 | outputHandle = Data.outputValue(self.outRotate) 88 | outputHandle.set3Double(eulerRotationValue.x, 89 | eulerRotationValue.y, 90 | eulerRotationValue.z) 91 | 92 | outputTwistHandle = Data.outputValue(self.outTwist) 93 | outputTwistHandle.setDouble(twistValue) 94 | 95 | outputTwistHandle.setClean() 96 | outputHandle.setClean() 97 | 98 | def nodeCreator(): 99 | return OpenMayaMPx.asMPxPtr(twistReader()) 100 | 101 | 102 | def nodeInitializer(): 103 | typed_Attr = OpenMaya.MFnTypedAttribute() 104 | nAttr = OpenMaya.MFnNumericAttribute() 105 | unitAttr = OpenMaya.MFnUnitAttribute() 106 | matAttr = OpenMaya.MFnMatrixAttribute() 107 | cAttr = OpenMaya.MFnCompoundAttribute() 108 | mode_Attr = OpenMaya.MFnEnumAttribute() 109 | 110 | twistReader.aimSpace = mode_Attr.create( "aimSpace", "aim", 0) 111 | mode_Attr.addField("world",0) 112 | mode_Attr.addField("reference",1) 113 | mode_Attr.addField("driver",2) 114 | mode_Attr.setKeyable(1) 115 | mode_Attr.setHidden(0) 116 | twistReader.addAttribute(twistReader.aimSpace) 117 | 118 | 119 | twistReader.parentMatrix = matAttr.create("parentMatrix", "pMat",OpenMaya.MFnMatrixAttribute.kDouble) 120 | matAttr.setStorable(1) 121 | matAttr.setKeyable(0) 122 | matAttr.setHidden(True) 123 | twistReader.addAttribute(twistReader.parentMatrix) 124 | 125 | defaultAngle = OpenMaya.MAngle(0.0, OpenMaya.MAngle.kDegrees) 126 | 127 | twistReader.inRotateX = unitAttr.create("inRotateX", "irx", defaultAngle) 128 | twistReader.inRotateY = unitAttr.create("inRotateY", "iry", defaultAngle) 129 | twistReader.inRotateZ = unitAttr.create("inRotateZ", "irz", defaultAngle) 130 | 131 | twistReader.inRotate = nAttr.create("inRotate", 132 | "ir", 133 | twistReader.inRotateX, 134 | twistReader.inRotateY, 135 | twistReader.inRotateZ) 136 | 137 | twistReader.refMatrix = matAttr.create("refMatrix", "rMat",OpenMaya.MFnMatrixAttribute.kDouble) 138 | matAttr.setStorable(0) 139 | matAttr.setKeyable(0) 140 | matAttr.setHidden(True) 141 | matAttr.setAffectsWorldSpace(True) 142 | twistReader.addAttribute(twistReader.refMatrix) 143 | 144 | twistReader.driverMatrix = matAttr.create("driverMatrix", "drMat",OpenMaya.MFnMatrixAttribute.kDouble) 145 | matAttr.setStorable(0) 146 | matAttr.setKeyable(0) 147 | matAttr.setHidden(True) 148 | matAttr.setAffectsWorldSpace(True) 149 | twistReader.addAttribute(twistReader.driverMatrix) 150 | 151 | #---------------------------------------------------------------------------- Output Attributes 152 | 153 | twistReader.outRotateX = unitAttr.create("outRotateX", "orx", defaultAngle) 154 | twistReader.outRotateY = unitAttr.create("outRotateY", "ory", defaultAngle) 155 | twistReader.outRotateZ = unitAttr.create("outRotateZ", "orz", defaultAngle) 156 | 157 | twistReader.outRotate = nAttr.create("outRotate", 158 | "or", 159 | twistReader.outRotateX, 160 | twistReader.outRotateY, 161 | twistReader.outRotateZ) 162 | 163 | nAttr.setStorable(1) 164 | nAttr.setKeyable(0) 165 | nAttr.setHidden(0) 166 | #nAttr.setWritable(0) 167 | twistReader.addAttribute(twistReader.outRotate ) 168 | 169 | twistReader.attributeAffects(twistReader.refMatrix, twistReader.outRotate) 170 | twistReader.attributeAffects(twistReader.driverMatrix, twistReader.outRotate) 171 | twistReader.attributeAffects(twistReader.parentMatrix, twistReader.outRotate) 172 | twistReader.attributeAffects(twistReader.aimSpace, twistReader.outRotate) 173 | 174 | twistReader.outTwist = nAttr.create("outTwist", "oTw", OpenMaya.MFnNumericData.kDouble, 0.0 ) 175 | nAttr.setStorable(1) 176 | nAttr.setHidden(0) 177 | #nAttr.setWritable(0) 178 | twistReader.addAttribute( twistReader.outTwist) 179 | 180 | twistReader.attributeAffects(twistReader.refMatrix, twistReader.outTwist) 181 | twistReader.attributeAffects(twistReader.driverMatrix, twistReader.outTwist) 182 | twistReader.attributeAffects(twistReader.parentMatrix, twistReader.outTwist) 183 | twistReader.attributeAffects(twistReader.aimSpace, twistReader.outTwist) 184 | 185 | def initializePlugin(mobject): 186 | mplugin = OpenMayaMPx.MFnPlugin(mobject, __author, __plug_in__Version, "Any") 187 | try: 188 | mplugin.registerNode(kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 189 | except: 190 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 191 | 192 | 193 | def uninitializePlugin(mobject): 194 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 195 | try: 196 | mplugin.deregisterNode( kPluginNodeId ) 197 | except: 198 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise -------------------------------------------------------------------------------- /maya/plug-ins/geodesicWeight.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # geodesicWeight.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | 10 | L I C E N S E: 11 | Copyright (c) 2014 Cedric BAZILLOU All rights reserved. 12 | 13 | Permission is hereby granted 14 | -to modify the file 15 | -distribute 16 | -share 17 | -do derivative work 18 | 19 | The above copyright notice and this permission notice shall be included in all copies of the Software 20 | and is subject to the following conditions: 21 | - Te user uses the same type of license 22 | - credit the original author 23 | - does not claim patent nor copyright from the original work 24 | 25 | P U R P O S E: 26 | Trigger an array of pose space helper/blendshape 27 | 28 | I N S T A L L A T I O N: 29 | Copy the "geodesicWeight.py" to your Maya plugins directory 30 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 31 | 32 | or better in your maya user directory: 33 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 34 | ''' 35 | 36 | import math, sys 37 | import maya.OpenMaya as OpenMaya 38 | import maya.OpenMayaMPx as OpenMayaMPx 39 | 40 | kPluginNodeName = "geodesicWeight" 41 | kPluginNodeId = OpenMaya.MTypeId(0xCCB225A) 42 | 43 | class geodesicWeight(OpenMayaMPx.MPxNode): 44 | def __init__(self): 45 | OpenMayaMPx.MPxNode.__init__(self) 46 | def check_mesh_surface_plugs(self,actionData): 47 | inputMeshConnected = False 48 | if actionData.isNull() == False : 49 | inputMeshConnected = True 50 | return inputMeshConnected 51 | def extract_point_on_surface_infos(self,inputStruct): 52 | cubePointVal = inputStruct[0] 53 | polyMfnMesh = inputStruct[1] 54 | 55 | #samplePos = [round( cubePointVal[0],5),round( cubePointVal[1],5),round( cubePointVal[2],5)] 56 | VectorFloat = OpenMaya.MFloatVector(cubePointVal[0],cubePointVal[1],cubePointVal[2]) 57 | 58 | #pointer for hitFace 59 | hitFaceParam = OpenMaya.MScriptUtil() 60 | hitFaceParam.createFromInt(0) 61 | hitFacePtr = hitFaceParam.asIntPtr() 62 | 63 | InFloatPoint = OpenMaya.MFloatPoint(0, 0 , 0) 64 | hitPoint = OpenMaya.MFloatPoint() 65 | 66 | #Intersection parameter setup 67 | mmAccelParams = OpenMaya.MMeshIsectAccelParams() 68 | mmAccelParams = polyMfnMesh.autoUniformGridParams() 69 | 70 | testHit = polyMfnMesh.closestIntersection ( InFloatPoint, VectorFloat , 71 | None , None , False , OpenMaya.MSpace.kObject ,4.0, False, mmAccelParams, 72 | hitPoint, None, hitFacePtr, None, None,None, 0.001 ) 73 | 74 | #Data packing and return 75 | if testHit == False: 76 | return None 77 | else: 78 | fceNm = OpenMaya.MScriptUtil(hitFacePtr).asInt() 79 | return [ OpenMaya.MPoint(hitPoint),fceNm] 80 | def compute_weight_list(self,polyMfnMesh,numVertices,polygonId,faceIter,collisionDatas): 81 | weightList = OpenMaya.MDoubleArray(numVertices,0.0) 82 | vertexList = OpenMaya.MIntArray() 83 | polyMfnMesh.getPolygonVertices(polygonId,vertexList) 84 | prev_util = OpenMaya.MScriptUtil() 85 | prev_util.createFromInt(0) 86 | prev_ptr = prev_util.asIntPtr() 87 | faceIter.setIndex (polygonId,prev_ptr) 88 | facePntList = OpenMaya.MPointArray() 89 | faceIter.getPoints(facePntList,OpenMaya.MSpace.kObject) 90 | 91 | hitPoint = collisionDatas[0] 92 | if vertexList.length() == 3: 93 | areaParam = OpenMaya.MScriptUtil() 94 | areaParam.createFromDouble(0) 95 | areaPtr = areaParam.asDoublePtr() 96 | faceIter.getArea( areaPtr,OpenMaya.MSpace.kObject ) 97 | faceArea = OpenMaya.MScriptUtil(areaPtr).asDouble() 98 | 99 | barycenters = self.extract_barycentric_coordinates(facePntList, hitPoint,faceArea) 100 | for k in range(3): 101 | weightList[vertexList[k]] = barycenters[k] 102 | 103 | return weightList 104 | def extract_barycentric_coordinates(self, vertexPositions , hitPoint,faceArea): 105 | vertId_List = [1,2,0,1] 106 | weightList = [0.0,0.0,0.0] 107 | for k in range(2): 108 | vecA = vertexPositions[vertId_List[k]] - hitPoint 109 | vecB = vertexPositions[vertId_List[k+1]] - hitPoint 110 | subTris_Area = (vecA^vecB).length()*0.5 111 | weightList[k] = subTris_Area/faceArea 112 | weightList[2] = math.fabs(1.0 - ( weightList[0] + weightList[1] )) 113 | return weightList 114 | def compute(self,Plug,Data): 115 | #Layout necessary output / input handle to gather data 116 | InputMeshData = Data.inputValue(self.inputShape ).asMesh() 117 | pos_val = Data.inputValue(self.cartesianPosition).asDouble3() 118 | output_handle = Data.outputArrayValue(self.output) 119 | collision_Face_handle = Data.outputValue(self.collision_Face) 120 | #--------------------------------------------------------------------- Compute if a mesh is connected 121 | InputMeshConnected = self.check_mesh_surface_plugs(InputMeshData) 122 | if InputMeshConnected == False: 123 | return 124 | else: 125 | #@ 1 Mesh is connected we can processed its data 126 | polyMfnMesh = OpenMaya.MFnMesh(InputMeshData) 127 | faceIter = OpenMaya.MItMeshPolygon(InputMeshData) 128 | numPolygon = polyMfnMesh.numPolygons() 129 | 130 | 131 | collisionDatas = self.extract_point_on_surface_infos((pos_val,polyMfnMesh)) 132 | 133 | if collisionDatas is None : 134 | return 135 | else: 136 | numVertices = polyMfnMesh.numVertices() 137 | polygonId = collisionDatas[1] 138 | 139 | collision_Face_handle.setInt(polygonId) 140 | collision_Face_handle.setClean() 141 | 142 | cBuilder = output_handle.builder() 143 | weightList = self.compute_weight_list(polyMfnMesh,numVertices,polygonId,faceIter,collisionDatas) 144 | 145 | for n in range(0,numVertices): 146 | currentDH = cBuilder.addElement(n) 147 | currentDH.setDouble(weightList[n]) 148 | 149 | output_handle.set(cBuilder) 150 | output_handle.setAllClean() 151 | def link_relashionShip( DriverList, driven_Attribute): 152 | for driver in DriverList: 153 | geodesicWeight.attributeAffects(driver,driven_Attribute) 154 | def nodeInitializer(): 155 | nAttr = OpenMaya.MFnNumericAttribute() 156 | cAttr = OpenMaya.MFnCompoundAttribute() 157 | #input Attributes ---------------------------------------------------------------------------------------------------------------------------- 158 | inputShape_Attr = OpenMaya.MFnTypedAttribute() 159 | geodesicWeight.inputShape = inputShape_Attr.create( "inputShape", "inS", OpenMaya.MFnMeshData.kMesh) 160 | inputShape_Attr.setStorable(0) 161 | inputShape_Attr.setKeyable(0) 162 | inputShape_Attr.setHidden(True) 163 | geodesicWeight.addAttribute( geodesicWeight.inputShape ) 164 | 165 | geodesicWeight.cartesianPosition = nAttr.create( "cartesianPosition", "cPos", OpenMaya.MFnNumericData.k3Double ) 166 | nAttr.setStorable(1) 167 | nAttr.setKeyable(1) 168 | nAttr.setHidden(0) 169 | geodesicWeight.addAttribute( geodesicWeight.cartesianPosition ) 170 | 171 | #output Attributes ---------------------------------------------------------------------------------------------------------------------------- 172 | geodesicWeight.collision_Face = nAttr.create( "collision_Face", "col", OpenMaya.MFnNumericData.kInt,-1) 173 | nAttr.setStorable(1) 174 | geodesicWeight.addAttribute( geodesicWeight.collision_Face) 175 | 176 | geodesicWeight.output = nAttr.create( "output", "out" , OpenMaya.MFnNumericData.kDouble ) 177 | nAttr.setArray(1) 178 | nAttr.setStorable(0) 179 | nAttr.setKeyable(0) 180 | nAttr.setHidden(0) 181 | nAttr.setUsesArrayDataBuilder(1) 182 | geodesicWeight.addAttribute(geodesicWeight.output) 183 | 184 | 185 | #Affect Relationship Attributes --------------------------------------------------------------------------------------------------------------- 186 | DriverList = [geodesicWeight.cartesianPosition,geodesicWeight.inputShape ] 187 | link_relashionShip(DriverList, geodesicWeight.output) 188 | link_relashionShip(DriverList, geodesicWeight.collision_Face) 189 | 190 | def nodeCreator(): 191 | return OpenMayaMPx.asMPxPtr(geodesicWeight()) 192 | def initializePlugin(mobject): 193 | mplugin = OpenMayaMPx.MFnPlugin(mobject, "Bazillou2012", "1.0", "Any") 194 | try: 195 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 196 | except: 197 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 198 | def uninitializePlugin(mobject): 199 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 200 | try: 201 | mplugin.deregisterNode( kPluginNodeId ) 202 | except: 203 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise 204 | -------------------------------------------------------------------------------- /maya/plug-ins/reglisse.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # reglisse.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | 10 | L I C E N S E: 11 | Copyright (c) 2014 Cedric BAZILLOU All rights reserved. 12 | 13 | Permission is hereby granted 14 | -to modify the file 15 | -distribute 16 | -share 17 | -do derivative work 18 | 19 | The above copyright notice and this permission notice shall be included in all copies of the Software 20 | and is subject to the following conditions: 21 | - The user uses the same type of license 22 | - credit the original author 23 | - does not claim patent nor copyright from the original work 24 | 25 | P U R P O S E: 26 | Sample u data from multiple type of input 27 | 28 | I N S T A L L A T I O N: 29 | Copy the "reglisse.py" to your Maya plugins directory 30 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 31 | 32 | or better in your maya user directory: 33 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 34 | ''' 35 | 36 | import math, sys 37 | import maya.OpenMaya as OpenMaya 38 | import maya.OpenMayaMPx as OpenMayaMPx 39 | 40 | kPluginNodeName = "reglisse" 41 | kPluginNodeId = OpenMaya.MTypeId(0xBAC7443) 42 | kPluginNodeAuthor = "Bazillou2012" 43 | kPluginNodeVersion = "1.35" 44 | 45 | class reglisse(OpenMayaMPx.MPxNode): 46 | def __init__(self): 47 | OpenMayaMPx.MPxNode.__init__(self) 48 | def check_curve_surface_plugs(self,actionData,objAttr): 49 | inputNurbsConnected = False 50 | nodeObj = self.thisMObject() 51 | 52 | depFn = OpenMaya.MFnDependencyNode(nodeObj) 53 | inPlug = depFn.findPlug(objAttr,False) 54 | if inPlug.isConnected() == False: 55 | return inputNurbsConnected 56 | if actionData.isNull() == False : 57 | inputNurbsConnected = True 58 | return inputNurbsConnected 59 | def collect_samplePoints(self,input_Hdle): 60 | knotCount = input_Hdle.elementCount() 61 | knotPointList = OpenMaya.MPointArray(knotCount,OpenMaya.MPoint()) 62 | 63 | for k in range(knotCount): 64 | currentPnt = OpenMaya.MPoint()*input_Hdle.inputValue().asMatrix() 65 | 66 | knotPointList.set(currentPnt,k) 67 | if k != knotCount-1: 68 | input_Hdle.next() 69 | 70 | return knotPointList 71 | 72 | def compute(self,Plug,Data): 73 | if Plug == self.uParameters : 74 | #Layout necessary output / input handle to gather data 75 | inputCurveObj = Data.inputValue( self.sampleCurve ).asNurbsCurveTransformed() 76 | curveChck = self.check_curve_surface_plugs(inputCurveObj,'sampleCurve' ) 77 | uParameters_handle = Data.outputValue(self.uParameters ) 78 | 79 | if curveChck == False: 80 | return 81 | else: 82 | inputMatrix_Hdle = Data.inputArrayValue(self.inputMatrix) 83 | inMeshObj = Data.inputValue( self.inMesh ).asMeshTransformed() 84 | inMeshChck = self.check_curve_surface_plugs(inMeshObj,'inMesh' ) 85 | 86 | knotPointList = OpenMaya.MPointArray() 87 | knotCount = 0 88 | 89 | if inMeshChck == True: 90 | mshFn = OpenMaya.MFnMesh(inMeshObj) 91 | mshFn.getPoints(knotPointList,OpenMaya.MSpace.kObject) 92 | knotCount = knotPointList.length() 93 | 94 | else: 95 | knotCount = inputMatrix_Hdle.elementCount() 96 | knotPointList = self.collect_samplePoints(inputMatrix_Hdle ) 97 | 98 | if knotCount == 0: 99 | return 100 | else: 101 | nrbMFn = OpenMaya.MFnNurbsCurve( inputCurveObj ) 102 | 103 | ulist = OpenMaya.MDoubleArray(knotCount,0.0) 104 | clstPnt = OpenMaya.MPoint() 105 | 106 | uParam = OpenMaya.MScriptUtil() 107 | uParam.createFromDouble(0) 108 | uParamPtr = uParam.asDoublePtr() 109 | 110 | sortList_val = Data.inputValue( self.sortList ).asBool() 111 | for k in range(knotCount): 112 | nrbMFn.closestPoint (knotPointList[k], uParamPtr, 0.0000001, OpenMaya.MSpace.kObject ) 113 | uValue = OpenMaya.MScriptUtil(uParamPtr).asDouble() 114 | ulist.set(uValue,k) 115 | 116 | if sortList_val == True: 117 | u_InAscendingOrder = sorted(ulist) 118 | for index, uValue in enumerate(u_InAscendingOrder): 119 | ulist.set(uValue,index) 120 | 121 | DoubleArrayFn = OpenMaya.MFnDoubleArrayData() 122 | outArray = DoubleArrayFn.create(ulist) 123 | uParameters_handle.setMObject(outArray) 124 | uParameters_handle.setClean() 125 | 126 | if Plug == self.segmentParameters : #SEGMENT defines unifom division 127 | segmentParameters_handle = Data.outputValue(self.segmentParameters ) 128 | inputCurveObj = Data.inputValue( self.sampleCurve ).asNurbsCurve() 129 | curveChck = self.check_curve_surface_plugs(inputCurveObj,'sampleCurve') 130 | 131 | if curveChck == True : 132 | divVal = Data.inputValue( self.division ).asInt() 133 | nrbMFn = OpenMaya.MFnNurbsCurve( inputCurveObj ) 134 | 135 | lenVal = nrbMFn.length (0.0001) 136 | fDiv = divVal*1.0 137 | ratio = lenVal/fDiv 138 | 139 | uParameters = OpenMaya.MDoubleArray(divVal+1) 140 | for k in range(divVal+1): 141 | tmpLEN = nrbMFn.findParamFromLength (k*ratio ) 142 | uParameters.set(tmpLEN,k) 143 | 144 | DoubleArrayFn = OpenMaya.MFnDoubleArrayData() 145 | outArray = DoubleArrayFn.create(uParameters) 146 | segmentParameters_handle.setMObject(outArray) 147 | segmentParameters_handle.setClean() 148 | 149 | def nodeCreator(): 150 | return OpenMayaMPx.asMPxPtr(reglisse()) 151 | def nodeInitializer(): 152 | typed_Attr = OpenMaya.MFnTypedAttribute() 153 | nAttr = OpenMaya.MFnNumericAttribute() 154 | cAttr = OpenMaya.MFnCompoundAttribute() 155 | matAttr = OpenMaya.MFnMatrixAttribute() 156 | 157 | #General curve input 158 | reglisse.sampleCurve = typed_Attr.create( "sampleCurve", "sCrv", OpenMaya.MFnNurbsCurveData.kNurbsCurve ) 159 | typed_Attr.setHidden(1) 160 | reglisse.addAttribute(reglisse.sampleCurve) 161 | #---------------------------------------------------------------------------- Input Attributes for U value mode 162 | 163 | 164 | reglisse.inputMatrix = matAttr.create("inputMatrix", "inMat",OpenMaya.MFnMatrixAttribute.kDouble) 165 | matAttr.setArray(1) 166 | matAttr.setStorable(0) 167 | matAttr.setKeyable(0) 168 | matAttr.setHidden(True) 169 | matAttr.setDisconnectBehavior(OpenMaya.MFnAttribute.kDelete) 170 | reglisse.addAttribute(reglisse.inputMatrix) 171 | 172 | reglisse.inMesh = typed_Attr.create( "inMesh", "inMs", OpenMaya.MFnMeshData.kMesh ) 173 | typed_Attr.setHidden(1) 174 | reglisse.addAttribute(reglisse.inMesh) 175 | 176 | reglisse.sortList = nAttr.create( "sortList", "sL", OpenMaya.MFnNumericData.kBoolean,0) 177 | nAttr.setKeyable(1) 178 | nAttr.setHidden(0) 179 | reglisse.addAttribute(reglisse.sortList ) 180 | 181 | #---------------------------------------------------------------------------- Output Attributes 182 | 183 | reglisse.uParameters = typed_Attr.create( "uParameters", "uuPrm", OpenMaya.MFnData.kDoubleArray) 184 | typed_Attr.setHidden(1) 185 | reglisse.addAttribute(reglisse.uParameters) 186 | 187 | reglisse.attributeAffects(reglisse.sampleCurve, reglisse.uParameters) 188 | reglisse.attributeAffects(reglisse.inputMatrix, reglisse.uParameters) 189 | reglisse.attributeAffects(reglisse.sortList, reglisse.uParameters) 190 | reglisse.attributeAffects(reglisse.inMesh, reglisse.uParameters) 191 | 192 | # segment mode-------------------------------------------------------------------------------------- 193 | reglisse.division = nAttr.create( "division", "div", OpenMaya.MFnNumericData.kInt,2) 194 | nAttr.setKeyable(1) 195 | nAttr.setHidden(0) 196 | nAttr.setSoftMin(2) 197 | nAttr.setSoftMax(500) 198 | reglisse.addAttribute(reglisse.division ) 199 | 200 | reglisse.segmentParameters = typed_Attr.create( "segmentParameters", "sgPrm", OpenMaya.MFnData.kDoubleArray) 201 | typed_Attr.setHidden(1) 202 | reglisse.addAttribute(reglisse.segmentParameters) 203 | reglisse.attributeAffects(reglisse.sampleCurve, reglisse.segmentParameters) 204 | reglisse.attributeAffects(reglisse.division, reglisse.segmentParameters) 205 | 206 | def initializePlugin(mobject): 207 | mplugin = OpenMayaMPx.MFnPlugin(mobject,kPluginNodeAuthor, kPluginNodeVersion, "Any") 208 | try: 209 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 210 | except: 211 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 212 | def uninitializePlugin(mobject): 213 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 214 | try: 215 | mplugin.deregisterNode( kPluginNodeId ) 216 | except: 217 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise -------------------------------------------------------------------------------- /rbfTool.py: -------------------------------------------------------------------------------- 1 | """ 2 | General descrition of your module here. 3 | """ 4 | from functools import partial 5 | 6 | from maya import OpenMaya 7 | from maya import OpenMayaUI 8 | from maya import cmds 9 | 10 | 11 | from PySide import QtCore 12 | from PySide import QtGui 13 | from shiboken import wrapInstance 14 | from shiboken import getCppPointer 15 | 16 | 17 | class RbfSettings(object): 18 | """ 19 | Class for storing rbf network creation options. 20 | """ 21 | def __init__(self): 22 | self.connectMatrix = False 23 | self.connectRgbValues = False 24 | self.connectAlphaValues = False 25 | self.useAttributeAlias = False 26 | self.visualizeFalloff = False 27 | 28 | 29 | class RbfManager(object): 30 | """ 31 | Pose driver mixing contribution of various elements in n spaces. 32 | """ 33 | def __init__(self): 34 | self.pluginState = self.initPlugins() 35 | 36 | def createNetwork(self, inputRbfSettings): 37 | if self.pluginState is False: 38 | return 39 | 40 | def vizualizeSigma(self): 41 | pass 42 | 43 | def createSigmaShader(self): 44 | pass 45 | 46 | def initPlugins(self): 47 | try: 48 | #you dont seem to use the class elements nor Api related encapsulation 49 | #of pymel so basically you can stick to maya python commands? 50 | cmds.loadPlugin('jsRadial.mll') 51 | except: 52 | cmds.error('ERROR: jsRadial.mll not loaded.') 53 | 54 | 55 | class RbfOptionsWidget(QtGui.QWidget): 56 | def __init__(self, parent=None): 57 | super(RbfOptionsWidget, self).__init__(parent) 58 | self.setupUI() 59 | 60 | def setupUI(self): 61 | #create widget 62 | self.connectMatrixCheckBox = QtGui.QCheckBox('Connect Matrix') 63 | self.connectRgbCheckBox = QtGui.QCheckBox('Connect RGB Values from Material') 64 | self.connectAlphaCheckBox = QtGui.QCheckBox('Connect Alpha Values from Material') 65 | self.useAliasCheckBox = QtGui.QCheckBox('Use Aliases for Targets on RBF Node') 66 | 67 | sphereLabel = 'Create Spheres to Visualize Falloff (most accurate for Gaussian)' 68 | self.createSphereCheckBox = QtGui.QCheckBox(sphereLabel) 69 | 70 | #Create layout 71 | self.mainLayout = QtGui.QVBoxLayout() 72 | 73 | #Set properties 74 | self.mainLayout.setContentsMargins(5, 5, 5, 5) 75 | 76 | for widget in [self.connectMatrixCheckBox, 77 | self.connectRgbCheckBox, 78 | self.connectAlphaCheckBox, 79 | self.useAliasCheckBox, 80 | self.createSphereCheckBox]: 81 | #Set properties 82 | widget.setChecked(True) 83 | 84 | #Assign widget to layouts 85 | self.mainLayout.addWidget(widget) 86 | 87 | #set the main layout for this UI part 88 | self.setLayout(self.mainLayout) 89 | 90 | 91 | class RbfListWidget(QtGui.QWidget): 92 | def __init__(self, parent=None): 93 | super(RbfListWidget, self).__init__(parent) 94 | self.setupUI() 95 | 96 | def setupUI(self): 97 | #create widget 98 | self.poseListWidget = QtGui.QListView() 99 | self.targetListWidget = QtGui.QListView() 100 | 101 | #Create layout 102 | self.poselistLayout = QtGui.QVBoxLayout() 103 | 104 | #Set properties 105 | self.poseListWidget.setMaximumHeight(20) 106 | self.poseListWidget.setMinimumWidth(190) 107 | self.targetListWidget.setMinimumHeight(260) 108 | 109 | self.poselistLayout.setContentsMargins(0, 0, 0, 0) 110 | self.poselistLayout.setSpacing(14) 111 | 112 | #Assign widget to layouts 113 | self.poselistLayout.addWidget(self.poseListWidget) 114 | self.poselistLayout.addWidget(self.targetListWidget) 115 | 116 | #set the main layout for this UI part 117 | self.setLayout(self.poselistLayout) 118 | 119 | 120 | class RbfDataIoWidget(QtGui.QWidget): 121 | def __init__(self, parent=None): 122 | super(RbfDataIoWidget, self).__init__(parent) 123 | self.setupUI() 124 | 125 | def setupUI(self): 126 | #create widget 127 | self.anchorWidget = QtGui.QWidget() 128 | 129 | self.addPoseButton = QtGui.QPushButton('Add Pose') 130 | self.removePoseButton = QtGui.QPushButton('Remove Pose') 131 | 132 | self.addTargetButton= QtGui.QPushButton('Add Target') 133 | self.removeTargetButton = QtGui.QPushButton('Remove Target') 134 | 135 | #Create layout 136 | self.ioLayout = QtGui.QGridLayout() 137 | self.mainLayout = QtGui.QVBoxLayout() 138 | 139 | #Set properties 140 | ioWidth = 78 141 | self.ioLayout.setContentsMargins(0, 0, 0, 0) 142 | self.ioLayout.setColumnMinimumWidth(0, ioWidth) 143 | self.ioLayout.setColumnMinimumWidth(1, ioWidth) 144 | self.ioLayout.setSpacing(10) 145 | self.mainLayout.setContentsMargins(0, 0, 0, 0) 146 | 147 | #Assign widget to layouts 148 | self.ioLayout.addWidget(self.removePoseButton, 0 , 0) 149 | self.ioLayout.addWidget(self.addPoseButton, 0 , 1) 150 | self.ioLayout.addWidget(self.removeTargetButton, 1 , 0) 151 | self.ioLayout.addWidget(self.addTargetButton, 1 , 1) 152 | 153 | self.mainLayout.addWidget(self.anchorWidget) 154 | self.mainLayout.addStretch() 155 | 156 | #set the main layout for this UI part 157 | self.anchorWidget.setLayout(self.ioLayout) 158 | self.setLayout(self.mainLayout) 159 | 160 | #Connect signals 161 | self.addPoseButton.clicked.connect(self._addPose) 162 | self.removePoseButton.clicked.connect(self._removePose) 163 | self.addTargetButton.clicked.connect(self._addTargets) 164 | self.removeTargetButton.clicked.connect(self._removeTargets) 165 | 166 | def _addPose(self): 167 | pass 168 | 169 | def _addTargets(self): 170 | pass 171 | 172 | def _removeTargets(self): 173 | pass 174 | 175 | def _removePose(self): 176 | pass 177 | 178 | 179 | class RbfHeaderWidget(QtGui.QWidget): 180 | def __init__(self, parent=None): 181 | super(RbfHeaderWidget, self).__init__(parent) 182 | 183 | self.setupUI() 184 | 185 | def setupUI(self): 186 | #create widget 187 | self.headerLabel = QtGui.QLabel('RBF Network Builder') 188 | self.creditLabel = QtGui.QLabel('by James Sumner III') 189 | self.websiteLabel = QtGui.QLabel('www.jamessumneriii.com') 190 | 191 | #Create layout 192 | self.headerLayout = QtGui.QVBoxLayout() 193 | 194 | #Set properties 195 | self.headerLabel.setStyleSheet('font-size: 16pt' ) 196 | self.creditLabel.setStyleSheet('color: rgb(140,140,140)') 197 | self.websiteLabel.setStyleSheet('color: rgb(140,140,140); link-decoration: none;') 198 | 199 | #Assign widget to layouts 200 | self.headerLayout.addWidget(self.headerLabel) 201 | self.headerLayout.addWidget(self.creditLabel) 202 | self.headerLayout.addWidget(self.websiteLabel) 203 | 204 | #set the main layout for this UI part 205 | self.setLayout(self.headerLayout) 206 | 207 | 208 | class RbfManagerTool(QtGui.QDialog): 209 | """ 210 | General UI used to create and maintain pose drivers. 211 | """ 212 | def __init__(self, parent=None): 213 | super(RbfManagerTool, self).__init__(parent=parent) 214 | 215 | #Parent widget under Maya main window 216 | self.setParent(parent) 217 | self.setWindowFlags(QtCore.Qt.Window) 218 | 219 | self.toolName = 'RBF Tool' 220 | self.pose = [] 221 | self.targets = [] 222 | 223 | self.setupUI() 224 | 225 | def setupUI(self): 226 | #cmds.undoInfo(openChunk=True) will bundle a list of commands 227 | #which will modify the Dag or the dg hence the separation in the 228 | #API into 2 classes MDAGModifier / MDGModifier. 229 | #not sure about its usefulness for UI? 230 | 231 | #create widget 232 | self.tabWidget = QtGui.QTabWidget() 233 | self.headerWidget = RbfHeaderWidget() 234 | self.createTab = self._buildCreateTab() 235 | 236 | #Create layout 237 | self.mainLayout = QtGui.QVBoxLayout() 238 | 239 | #Set properties 240 | self.setWindowTitle(self.toolName) 241 | 242 | self.mainLayout.setContentsMargins(10, 10, 10, 10) 243 | 244 | #Assign widget to layouts 245 | self.tabWidget.addTab(self.createTab, 'Create') 246 | #self.tabWidget.addTab(self.editTab, 'Edit') 247 | 248 | self.mainLayout.addWidget(self.headerWidget) 249 | self.mainLayout.addWidget(self.tabWidget) 250 | 251 | self.setLayout(self.mainLayout) 252 | 253 | def _buildCreateTab(self): 254 | #create widget 255 | self.createTabWidget = QtGui.QWidget() 256 | self.createTabAnchor = QtGui.QWidget() 257 | self.ioWidget = RbfDataIoWidget() 258 | self.poseListWidget = RbfListWidget() 259 | 260 | self.optionsWidget = RbfOptionsWidget() 261 | 262 | #Create layout 263 | self.createTabLayout = QtGui.QHBoxLayout() 264 | self.createTabOptionLayout = QtGui.QVBoxLayout() 265 | 266 | #Set properties 267 | self.createTabLayout.setContentsMargins(5, 5, 5, 5) 268 | self.createTabOptionLayout.setContentsMargins(0, 0, 0, 0) 269 | 270 | #Assign widget to layouts 271 | self.createTabOptionLayout.addWidget(self.createTabAnchor) 272 | self.createTabOptionLayout.addWidget(self.optionsWidget) 273 | 274 | self.createTabLayout.addWidget(self.ioWidget) 275 | self.createTabLayout.addWidget(self.poseListWidget) 276 | 277 | self.createTabWidget.setLayout(self.createTabOptionLayout) 278 | self.createTabAnchor.setLayout(self.createTabLayout) 279 | 280 | return self.createTabWidget 281 | 282 | 283 | def DeleteWindowInstances(mayaMainWindow): 284 | """ 285 | Close tool by type. 286 | """ 287 | checkWidget = RbfManagerTool() 288 | 289 | #Check if window exists 290 | for child in mayaMainWindow.children(): 291 | if not isinstance(child, QtGui.QWidget): 292 | continue 293 | #delete previous UI instance (isinstance was giving weird result) 294 | if child.__class__.__name__ == checkWidget.__class__.__name__: 295 | child.deleteLater() 296 | child.parent = None 297 | 298 | checkWidget = None 299 | 300 | 301 | def Run(): 302 | mayaMainWindowPtr = OpenMayaUI.MQtUtil.mainWindow() 303 | mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QtGui.QWidget) 304 | 305 | DeleteWindowInstances(mayaMainWindow) 306 | 307 | tool = RbfManagerTool(parent=mayaMainWindow) 308 | tool.show() 309 | 310 | return tool 311 | -------------------------------------------------------------------------------- /maya/rig/dish/data.py: -------------------------------------------------------------------------------- 1 | import maya.cmds as mc 2 | def excludeParentAttribute (): 3 | nodeType = ['controlPoint','geometryShape','containerBase' ] 4 | unExposeAttr = [] 5 | for nde in nodeType: 6 | attrList = mc.attributeInfo( inherited=False, t=nde ) 7 | 8 | if attrList is not None: 9 | unExposeAttr.extend(attrList) 10 | return unExposeAttr 11 | 12 | face = ['ear','lid','brow','nose','eye','mouth','lip','chin','forehead'] 13 | limbs = ['arm','foot','hand ','leg','foot','toe','spine','head','neck'] 14 | articulations = ['shoulder','elbow','wrist','finger','thigh','knee','ankle'] 15 | groupType = ['SYS','GRP','ZERO','OFFSET','HOOK','ANCHOR','Pivot','CTRLS','Space','Input','Output','Drivers'] 16 | clothParts = [ 'sleeve','stitch','skirt','coat','shirt','pants','collar','dress'] 17 | 18 | recipeData = {'author':'cedricbazillou@gmail.com','gitSource':'https://github.com/cedricB/circeCharacterWorksTools'} 19 | 20 | surfceExclude =[u'curvePrecision', u'uDivisionsFactor', u'minValueU', u'minValueV', 21 | u'useChordHeightRatio', u'degreeV', u'degreeU', u'simplifyV', u'objSpaceChordHeight', u'formU', 22 | u'simplifyU', u'displayRenderTessellation', u'dispSF', u'vDivisionsFactor', u'chordHeight', 23 | u'degreeUV', u'tweakSizeU', u'chordHeightRatio', u'spansV', u'create', u'minMaxRangeV', 24 | u'minMaxRangeU', u'numberV', u'numberU', u'trimFace', u'patchUVIds', u'curvatureTolerance', 25 | u'selCVDisp', u'modeV', u'modeU', u'tweakSizeV', u'dispOrigin', u'smoothEdgeRatio', 26 | u'useChordHeight', u'normalsDisplayScale', u'edgeSwap', u'maxValueV', u'maxValueU', 27 | u'spansUV', u'renderTriangleCount', u'explicitTessellationAttributes', u'simplifyMode', 28 | u'curvePrecisionShaded', u'divisionsV', u'divisionsU', u'smoothEdge', u'basicTessellationType', 29 | u'fixTextureWarp', u'gridDivisionPerSpanV', u'gridDivisionPerSpanU', u'spansU', u'formV'] 30 | 31 | crveExclude = [u'degree', u'visibility', 32 | u'intermediateObject', 33 | u'spans', u'dispEP', 34 | u'minValue', 35 | u'compInstObjGroups.compObjectGroups.compObjectGrpCompList', 36 | u'header', 37 | u'worldNormal', 38 | u'minMaxValue', 39 | u'controlPoints.xValue', 40 | u'colorSet.colorSetPoints.colorSetPointsG', 41 | u'dispCurveEndPoints', 42 | u'colorSet.colorSetPoints.colorSetPointsB', 43 | u'colorSet.colorSetPoints.colorSetPointsA', 44 | u'dispGeometry', 45 | u'worldMatrix', u'template', u'compInstObjGroups.compObjectGroups', 46 | u'colorSet.colorSetPoints.colorSetPointsR', 47 | u'controlPoints.yValue', u'tweakSize', u'uvSet.uvSetPoints', 48 | u'uvSet.uvSetPoints.uvSetPointsV', 49 | u'uvSet.uvSetPoints.uvSetPointsU', 50 | u'worldNormal.worldNormalZ', 51 | u'inPlace', u'worldNormal.worldNormalX', u'colorSet.clamped', 52 | u'colorSet.colorSetPoints', u'controlPoints.zValue', 53 | u'compInstObjGroups.compObjectGroups.compObjectGroupId', 54 | u'worldNormal.worldNormalY', u'maxValue', u'uvSet.uvSetName', 55 | u'editPoints.xValueEp', u'colorSet.colorName', u'editPoints.zValueEp', 56 | u'uvSet.uvSetTweakLocation', u'form', u'editPoints.yValueEp', 57 | u'colorSet.representation', u'dispCV',u'localScaleX', 58 | u'localScale', u'localPosition', u'underWorldObject', u'localPositionZ', u'localScaleZ', u'localPositionX', u'localPositionY', u'worldPosition.worldPositionZ', u'localScaleY', u'worldPosition.worldPositionX', u'worldPosition.worldPositionY' ] 59 | 60 | latExclude = [u'origin', u'sDivisions', u'latticePointMoved', u'dispLattice', u'dispPoints', 61 | u'originY', u'originX', u'originZ' , u'uDivisions', u'tDivisions', u'displayControl'] 62 | 63 | meshExclude = [u'displayAlphaAsGreyScale', u'holeFaceData', u'displayEdges', u'numTriangles', 64 | u'vertexColor.vertexAlpha', u'backfaceCulling', u'colors', u'initialSampleRate', u'doubleSided', 65 | u'creaseVertexData', u'smoothLevel', u'useMinEdgeLength', u'vertexNormal', u'renderSmoothLevel', 66 | u'collisionOffsetVelocityMultiplier.collisionOffsetVelocityMultiplier_FloatValue', u'featureDisplacement', 67 | u'collisionDepthVelocityIncrement', u'vertexNormal.vertexNormalX', u'vertexNormal.vertexNormalY', u'uvSize', 68 | u'vertexColor.vertexFaceColor.vertexFaceColorB', u'boundaryRule', u'userTrg', u'continuity', u'vrts.vrtz', 69 | u'vrts.vrtx', u'vrts.vrty', u'parentMatrix', u'displayTangent', u'vertexBackfaceCulling', 70 | u'vertexColor.vertexFaceColor.vertexFaceColorG', u'displayTriangles', u'collisionDepthVelocityMultiplier', 71 | u'boundingBoxScaleY', u'normalPerVertex', u'vertexNormal.vertexFaceNormal.vertexFaceNormalZ', u'sofy', u'sofz', 72 | u'vertexNormal.vertexFaceNormal.vertexFaceNormalY', u'collisionDepthVelocityIncrement.collisionDepthVelocityIncrement_Interp', 73 | u'perInstanceTag', u'normalSize', u'colors.colorG', u'collisionOffsetVelocityMultiplier.collisionOffsetVelocityMultiplier_Position', 74 | u'colors.colorA', u'colors.colorB', u'outForceNodeUVUpdate', u'uvpt', u'keepMapBorders', u'useMaxEdgeLength', 75 | u'displayFacesWithGroupId', u'maxSubd', u'sofx', u'boundingBoxScaleX', 76 | u'boundingBoxScaleZ', u'displayItemNumbers', u'vertexNormal.vertexFaceNormal.vertexFaceNormalX', 77 | u'vertexColor.vertexColorG', u'vertexColor.vertexColorB', u'smoothShading', u'vertexColor.vertexFaceColor', 78 | u'dispResolution', u'borderWidth', u'parentInverseMatrix', u'maxTriangles', u'keepBorder', 79 | u'collisionOffsetVelocityIncrement.collisionOffsetVelocityIncrement_Interp', u'quadSplit', u'maxEdgeLength', 80 | u'uvTweakLocation', u'allowTopologyMod', u'collisionOffsetVelocityIncrement.collisionOffsetVelocityIncrement_FloatValue', 81 | u'displaySubdComps', u'vertexIdMap', u'vertexNormal.vertexFaceNormal', u'tangentSmoothingAngle', 82 | u'collisionOffsetVelocityIncrement.collisionOffsetVelocityIncrement_Position', 83 | u'materialBlend', u'maxUv', u'pnts', u'boundingBoxScale', u'collisionOffsetVelocityMultiplier', 84 | u'normalType', u'collisionDepthVelocityIncrement.collisionDepthVelocityIncrement_FloatValue', u'faceIdMap', 85 | u'lodVisibility', u'extraSampleRate', u'collisionDepthVelocityIncrement.collisionDepthVelocityIncrement_Position', 86 | u'minScreen', u'cachedSmoothMesh', u'pnts.pntz', u'useNumTriangles', u'pnts.pntx', u'pnts.pnty', 87 | u'vertexNormal.vertexNormalZ', u'vertexNormalMethod', u'vrts', u'smoothUVs', u'displayVertices', 88 | u'vertexColor.vertexColorRGB', u'creaseData', u'inForceNodeUVUpdate', u'keepHardEdge', 89 | u'cachedInMesh', u'displayCenter', u'tangentNormalThreshold', u'displaySmoothMesh', 90 | u'outGeometryClean', u'vertexColor.vertexFaceColor.vertexFaceColorRGB', u'displayInvisibleFaces', 91 | u'collisionDepthVelocityMultiplier.collisionDepthVelocityMultiplier_Interp', u'vertexNormal.vertexNormalXYZ', 92 | u'collisionOffsetVelocityIncrement', u'propagateEdgeHardness', 93 | u'collisionDepthVelocityMultiplier.collisionDepthVelocityMultiplier_FloatValue', u'motionVectorColorSet', 94 | u'perInstanceIndex', u'colors.colorR', u'useMinScreen', 95 | u'collisionOffsetVelocityMultiplier.collisionOffsetVelocityMultiplier_Interp', u'edgeIdMap', u'vertexColor', 96 | u'outSmoothMesh', u'worldInverseMatrix', u'face', u'collisionDepthVelocityMultiplier.collisionDepthVelocityMultiplier_Position', 97 | u'smoothMeshSelectionMode', u'uvpt.uvpy', u'uvpt.uvpx', u'vertexColor.vertexFaceColor.vertexFaceAlpha', 98 | u'useMaxSubdivisions', u'displayNormal', u'reuseTriangles', u'vertexSize', u'edge.edgh', 99 | u'minEdgeLength', u'vertexNormal.vertexFaceNormal.vertexFaceNormalXYZ', u'nodeState', u'opposite', 100 | u'displayUVs', u'normalThreshold', u'smoothWarn', u'colorPerVertex', 101 | u'vertexColor.vertexColorR', u'vertexColor.vertexFaceColor.vertexFaceColorR', u'normals.normalz', 102 | u'normals.normalx', u'normals.normaly', u'useMaxUV', u'edge.edg1', u'edge.edg2', u'displayNonPlanar', 103 | u'displayHWEnvironment', u'tangentSpace', u'displayBorders', u'textureThreshold', u'edge', 104 | u'normals', u'inverseMatrix', u'smoothOffset', u'ignoreHwShader', u'useSmoothPreviewForRender', u'matrix'] 105 | 106 | defaultNodes = [u'time1', u'sequenceManager1', u'renderPartition', 107 | u'renderGlobalsList1', u'defaultLightList1', u'defaultShaderList1', 108 | u'postProcessList1', u'defaultRenderUtilityList1', 109 | u'defaultRenderingList1', u'lightList1', 110 | u'defaultTextureList1', u'lambert1', u'particleCloud1', 111 | u'initialShadingGroup', u'initialParticleSE', u'initialMaterialInfo', 112 | u'shaderGlow1', u'dof1', u'defaultRenderGlobals', 113 | u'defaultRenderQuality', u'defaultResolution', u'defaultLightSet', 114 | u'defaultObjectSet', u'defaultViewColorManager', u'hardwareRenderGlobals', 115 | u'hardwareRenderingGlobals', u'characterPartition', u'defaultHardwareRenderGlobals', 116 | u'ikSystem', u'hyperGraphInfo', u'hyperGraphLayout', u'globalCacheControl', 117 | u'dynController1', u'strokeGlobals', u'CustomGPUCacheFilter', u'objectTypeFilter74', 118 | u'persp', u'perspShape', u'top', u'topShape', u'front', u'frontShape', u'side', u'sideShape', 119 | u'lightLinker1', u'layersFilter', u'objectTypeFilter75', u'animLayersFilter', 120 | u'objectTypeFilter76', u'notAnimLayersFilter', u'objectTypeFilter77', 121 | u'defaultRenderLayerFilter', u'objectNameFilter4', u'renderLayerFilter', 122 | u'objectTypeFilter78', u'objectScriptFilter10', u'renderingSetsFilter', 123 | u'objectTypeFilter79', u'relationshipPanel1LeftAttrFilter', u'relationshipPanel1RightAttrFilter', 124 | u'layerManager', u'defaultLayer', u'renderLayerManager', u'defaultRenderLayer'] 125 | 126 | excludeAttr = ['message', 'caching ','isHistoricallyInteresting', 127 | 'binMembership','hyperLayout', 'isCollapsed', 'blackBox', 128 | 'borderConnections','isHierarchicalConnection','publishedNodeInfo', 129 | 'publishedNodeInfo.publishedNode','publishedNodeInfo.isHierarchicalNode', 130 | 'publishedNodeInfo.publishedNodeType','rmbCommand', 131 | 'templateName','templatePath','viewName','iconName','viewMode', 132 | 'templateVersion','uiTreatment','customTreatment', 133 | 'creator','creationDate','containerType', 134 | 'boundingBox','boundingBoxMin','boundingBoxMinX','boundingBoxMinY','boundingBoxMinZ','boundingBoxMax', 135 | 'boundingBoxMaxX','boundingBoxMaxY','boundingBoxMaxZ','boundingBoxSize','boundingBoxSizeX', 136 | 'boundingBoxSizeY','boundingBoxSizeZ','center','boundingBoxCenterX','boundingBoxCenterY', 137 | 'boundingBoxCenterZ','ghosting','instObjGroups', 138 | 'instObjGroups.objectGroups','instObjGroups.objectGroups.objectGrpCompList', 139 | 'instObjGroups.objectGroups.objectGroupId','instObjGroups.objectGroups.objectGrpColor', 140 | 'useObjectColor','objectColor','drawOverride','overrideDisplayType', 141 | 'overrideLevelOfDetail','overrideShading','overrideTexturing', 142 | 'overridePlayback','overrideEnabled','overrideVisibility', 143 | 'overrideColor', 'renderInfo','identification','layerRenderable','layerOverrideColor', 144 | 'renderLayerInfo','renderLayerInfo.renderLayerId','renderLayerInfo.renderLayerRenderable', 145 | 'renderLayerInfo.renderLayerColor','ghostingControl','ghostCustomSteps', 146 | 'ghostPreSteps','ghostPostSteps','ghostStepSize','ghostFrames','ghostColorPreA', 147 | 'ghostColorPre','ghostColorPreR','ghostColorPreG','ghostColorPreB', 148 | 'ghostColorPostA','ghostColorPost','ghostColorPostR','ghostColorPostG', 149 | 'ghostColorPostB','ghostRangeStart','ghostRangeEnd','ghostDriver', 150 | 'shear','shearXY','shearXZ','shearYZ','rotatePivot','rotatePivotX', 151 | 'rotatePivotY','rotatePivotZ','rotatePivotTranslate','rotatePivotTranslateX', 152 | 'rotatePivotTranslateY','rotatePivotTranslateZ','scalePivot','scalePivotX', 153 | 'scalePivotY','scalePivotZ','scalePivotTranslate','scalePivotTranslateX','scalePivotTranslateY', 154 | 'scalePivotTranslateZ','rotateAxis','rotateAxisX','rotateAxisY','rotateAxisZ','transMinusRotatePivot', 155 | 'transMinusRotatePivotX','transMinusRotatePivotY','transMinusRotatePivotZ','minTransLimit','minTransXLimit', 156 | 'minTransYLimit','minTransZLimit','maxTransLimit','maxTransXLimit','maxTransYLimit','maxTransZLimit','minTransLimitEnable', 157 | 'minTransXLimitEnable','minTransYLimitEnable','minTransZLimitEnable','maxTransLimitEnable','maxTransXLimitEnable', 158 | 'maxTransYLimitEnable','maxTransZLimitEnable','minRotLimit','minRotXLimit','minRotYLimit','minRotZLimit','maxRotLimit', 159 | 'maxRotXLimit','maxRotYLimit','maxRotZLimit','minRotLimitEnable','minRotXLimitEnable','minRotYLimitEnable','minRotZLimitEnable', 160 | 'maxRotLimitEnable','maxRotXLimitEnable','maxRotYLimitEnable','maxRotZLimitEnable','minScaleLimit','minScaleXLimit','minScaleYLimit', 161 | 'minScaleZLimit','maxScaleLimit','maxScaleXLimit','maxScaleYLimit','maxScaleZLimit','minScaleLimitEnable','minScaleXLimitEnable', 162 | 'minScaleYLimitEnable','minScaleZLimitEnable','maxScaleLimitEnable','maxScaleXLimitEnable','maxScaleYLimitEnable', 163 | 'maxScaleZLimitEnable','geometry','xformMatrix', 'selectHandle', 'selectHandleX', 'selectHandleY', 'selectHandleZ', 164 | 'displayHandle','displayScalePivot','displayRotatePivot','displayLocalAxis','dynamics', 165 | 'showManipDefault','specifiedManipLocation','rotateQuaternion','rotateQuaternionX','rotateQuaternionY','rotateQuaternionZ', 166 | 'rotateQuaternionW','rotationInterpolation','element','foodType','uuID','cached','caching','moduleInfos', 167 | u'editPoints', u'dispHull'] 168 | 169 | unExposeAttr = excludeParentAttribute () 170 | 171 | 172 | -------------------------------------------------------------------------------- /maya/plug-ins/yakisoba.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # yakisoba.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | 10 | L I C E N S E: 11 | Copyright (c) 2014 Cedric BAZILLOU All rights reserved. 12 | 13 | Permission is hereby granted 14 | -to modify the file 15 | -distribute 16 | -share 17 | -do derivative work 18 | 19 | The above copyright notice and this permission notice shall be included in all copies of the Software 20 | and is subject to the following conditions: 21 | - Te user uses the same type of license 22 | - credit the original author 23 | - does not claim patent nor copyright from the original work 24 | P U R P O S E: 25 | Control several twist joint based on their place along a curve at bind time. 26 | --> allow non linear distribution along the spline 27 | --> compute the correct twist value and output translate/rotate values in a predefined space 28 | 29 | I N S T A L L A T I O N: 30 | Copy the "yakisoba.py" to your Maya plugins directory 31 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 32 | 33 | or better in your maya user directory: 34 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 35 | ''' 36 | 37 | 38 | import math, sys 39 | import maya.OpenMaya as OpenMaya 40 | import maya.OpenMayaMPx as OpenMayaMPx 41 | 42 | kPluginNodeName = "yakisoba" 43 | kPluginNodeId = OpenMaya.MTypeId(0xB5C41127) 44 | 45 | __plug_in__Version = "0.52" 46 | __author = "Bazillou2013" 47 | 48 | class yakisoba(OpenMayaMPx.MPxNode): 49 | def __init__(self): 50 | OpenMayaMPx.MPxNode.__init__(self) 51 | def check_curve_surface_plugs(self,argList): 52 | actionData = argList[0] 53 | inputNurbsConnected = False 54 | 55 | if actionData.isNull() == False : 56 | inputNurbsConnected = True 57 | return inputNurbsConnected 58 | def update_output_storage(self,uValue_Hdle,output_handle): 59 | curveParameterCount = uValue_Hdle.elementCount() 60 | curveParameterList = [] 61 | idxList = [] 62 | #extract parameter value 63 | for k in range(curveParameterCount): 64 | curveParameterList.append(uValue_Hdle.inputValue().asDouble()) 65 | 66 | idx = uValue_Hdle.elementIndex() 67 | idxList.append(idx) 68 | if k != curveParameterCount-1: 69 | uValue_Hdle.next() 70 | 71 | #how many entry do we need add to the current output list? 72 | cBuilder = output_handle.builder() 73 | bldChck = cBuilder.elementCount() 74 | growVal = curveParameterCount-bldChck 75 | if growVal>0: 76 | cBuilder.growArray ( growVal ) 77 | 78 | return [curveParameterList, idxList] 79 | def compute_matrix_from_2_vectors_and_u_Point(self,trX_Mat,trY_Mat,u_Point): 80 | trZ_Mat = (trX_Mat^trY_Mat).normal(); 81 | 82 | matrixValueList = [ trX_Mat.x, trX_Mat.y, trX_Mat.z, 0.0, 83 | trY_Mat.x, trY_Mat.y, trY_Mat.z, 0.0, 84 | trZ_Mat.x, trZ_Mat.y, trZ_Mat.z, 0.0, 85 | u_Point.x,u_Point.y,u_Point.z,u_Point.w ] 86 | 87 | rotMatrix = OpenMaya.MMatrix() 88 | utilB = OpenMaya.MScriptUtil() 89 | utilB.createMatrixFromList( matrixValueList, rotMatrix ) 90 | 91 | return rotMatrix.homogenize() 92 | def compute(self,Plug,Data): 93 | if Plug.parent() == self.output : 94 | inputCurveObj = Data.inputValue( self.inputCurve ).asNurbsCurveTransformed() 95 | inputRibbonObj = Data.inputValue( self.inputRibbon ).asNurbsSurfaceTransformed() 96 | output_handle = Data.outputArrayValue(self.output) 97 | 98 | uValue_Hdle = Data.inputArrayValue(self.uValue) 99 | twist_Value = Data.inputValue(self.twist).asDouble() 100 | disableRotation_val = Data.inputValue(self.disableRotation).asBool() 101 | 102 | cBuilder = output_handle.builder() 103 | 104 | InputNurbsConnected = self.check_curve_surface_plugs([inputCurveObj]) 105 | InputRibbonConnected = self.check_curve_surface_plugs([inputRibbonObj]) 106 | if InputNurbsConnected == True and InputRibbonConnected == True and uValue_Hdle.elementCount() > 0 : 107 | nrbMFn = OpenMaya.MFnNurbsCurve( inputCurveObj ) 108 | curveLen = nrbMFn.length(0.0001) 109 | surfMFn = OpenMaya.MFnNurbsSurface( inputRibbonObj ) 110 | 111 | start_util = OpenMaya.MScriptUtil() 112 | start_util.createFromDouble(0.0) 113 | startPtr = start_util.asDoublePtr() 114 | 115 | end_util = OpenMaya.MScriptUtil() 116 | end_util.createFromDouble(0.0) 117 | endPtr = end_util.asDoublePtr() 118 | 119 | nrbMFn.getKnotDomain(startPtr,endPtr) 120 | strVal = OpenMaya.MScriptUtil().getDouble(startPtr) 121 | endVal = OpenMaya.MScriptUtil().getDouble(endPtr) 122 | 123 | locSpace = OpenMaya.MSpace.kObject 124 | 125 | smplePnt = OpenMaya.MPoint() 126 | 127 | cvRange = endVal - strVal 128 | 129 | paramData = self.update_output_storage( uValue_Hdle,output_handle) 130 | idxList = paramData[1] 131 | paramList = paramData[0] 132 | curveParameterCount = len(paramList) 133 | neutralAim = OpenMaya.MVector.xAxis 134 | 135 | for n in range(0,curveParameterCount): 136 | currentDH = cBuilder.addElement(idxList[n]) 137 | outRotate_DH = currentDH.child(self.outRotate) 138 | outTranslate_DH = currentDH.child(self.outTranslate) 139 | outMatrix_DH = currentDH.child(self.outMatrix) 140 | outScale_DH = currentDH.child(self.outScale) 141 | 142 | paramValue = 0.0 143 | dif_value = 0.0 144 | if paramList[n] < strVal: 145 | paramValue = strVal 146 | dif_value = paramList[n] 147 | elif paramList[n] > endVal: 148 | paramValue = endVal 149 | dif_value = paramList[n]-endVal 150 | else: 151 | paramValue = paramList[n] 152 | 153 | nrbMFn.getPointAtParam(paramValue,smplePnt,locSpace) 154 | 155 | if disableRotation_val == False: 156 | #get Twist percentage 157 | localTwist = ((paramValue-strVal) /cvRange) * twist_Value 158 | 159 | currentTwist = math.radians(localTwist ) 160 | twistMat = OpenMaya.MEulerRotation(currentTwist,0,0, 0).asMatrix() 161 | 162 | # compute rotational value : 163 | aimVector = nrbMFn.tangent(paramValue,locSpace) 164 | normalUP_vector = surfMFn.normal(0.5,paramValue,locSpace) 165 | rotMat = self.compute_matrix_from_2_vectors_and_u_Point(aimVector,normalUP_vector,smplePnt) 166 | 167 | finalMat = twistMat*rotMat 168 | outMatrix_DH.setMMatrix(finalMat) 169 | matFn = OpenMaya.MTransformationMatrix(finalMat) 170 | 171 | blendRot = matFn.eulerRotation() 172 | outRotate_DH.set3Double(blendRot.x,blendRot.y,blendRot.z) 173 | outRotate_DH.setClean() 174 | 175 | if dif_value != 0.0: 176 | offset = OpenMaya.MPoint(dif_value,0,0)*rotMat 177 | outTranslate_DH.set3Double(offset.x,offset.y,offset.z) 178 | outTranslate_DH.setClean() 179 | else: 180 | outTranslate_DH.set3Double(smplePnt.x,smplePnt.y,smplePnt.z) 181 | outTranslate_DH.setClean() 182 | output_handle.set(cBuilder) 183 | output_handle.setAllClean() 184 | def nodeCreator(): 185 | return OpenMayaMPx.asMPxPtr(yakisoba()) 186 | def nodeInitializer(): 187 | typed_Attr = OpenMaya.MFnTypedAttribute() 188 | nAttr = OpenMaya.MFnNumericAttribute() 189 | unitAttr = OpenMaya.MFnUnitAttribute() 190 | matAttr = OpenMaya.MFnMatrixAttribute() 191 | cAttr = OpenMaya.MFnCompoundAttribute() 192 | 193 | #input worldMesh curve 194 | yakisoba.inputCurve = typed_Attr.create( "inputCurve", "inCv", OpenMaya.MFnNurbsCurveData.kNurbsCurve ) 195 | typed_Attr.setStorable(0) 196 | typed_Attr.setKeyable(0) 197 | typed_Attr.setHidden(True) 198 | yakisoba.addAttribute( yakisoba.inputCurve ) 199 | 200 | yakisoba.inputRibbon = typed_Attr.create( "inputRibbon", "inrb", OpenMaya.MFnNurbsCurveData.kNurbsSurface ) 201 | typed_Attr.setStorable(0) 202 | typed_Attr.setKeyable(0) 203 | typed_Attr.setHidden(True) 204 | yakisoba.addAttribute( yakisoba.inputRibbon ) 205 | 206 | yakisoba.uValue = nAttr.create( "uValue", "uVl", OpenMaya.MFnNumericData.kDouble,0 ) 207 | nAttr.setArray(1) 208 | nAttr.setStorable(1) 209 | nAttr.setKeyable(0) 210 | nAttr.setHidden(0) 211 | nAttr.setMin(0.0) 212 | yakisoba.addAttribute( yakisoba.uValue ) 213 | 214 | yakisoba.disableRotation = nAttr.create( "disableRotation", "dRot", OpenMaya.MFnNumericData.kBoolean,0 ) 215 | nAttr.setStorable(1) 216 | nAttr.setKeyable(1) 217 | nAttr.setHidden(0) 218 | yakisoba.addAttribute( yakisoba.disableRotation ) 219 | 220 | yakisoba.twist = nAttr.create( "twist", "tw", OpenMaya.MFnNumericData.kDouble,0 ) 221 | nAttr.setKeyable(1) 222 | yakisoba.addAttribute( yakisoba.twist) 223 | 224 | #---------------------------------------------------------------------------- Output Attributes 225 | defaultAngle = OpenMaya.MAngle ( 0.0, OpenMaya.MAngle.kDegrees ) 226 | defaultDist = OpenMaya.MDistance ( 0.0, OpenMaya.MDistance.kCentimeters ) 227 | 228 | yakisoba.outRotateX = unitAttr.create( "outRotateX", "orx", defaultAngle) 229 | yakisoba.outRotateY = unitAttr.create( "outRotateY", "ory", defaultAngle) 230 | yakisoba.outRotateZ = unitAttr.create( "outRotateZ", "orz", defaultAngle) 231 | yakisoba.outRotate = nAttr.create( "outRotate", "oRot",yakisoba.outRotateX,yakisoba.outRotateY,yakisoba.outRotateZ) 232 | 233 | yakisoba.outTranslateX = unitAttr.create( "outTranslateX", "otx", defaultDist) 234 | yakisoba.outTranslateY = unitAttr.create( "outTranslateY", "oty", defaultDist) 235 | yakisoba.outTranslateZ = unitAttr.create( "outTranslateZ", "otz", defaultDist) 236 | yakisoba.outTranslate = nAttr.create( "outTranslate", "oTrn",yakisoba.outTranslateX,yakisoba.outTranslateY,yakisoba.outTranslateZ) 237 | 238 | yakisoba.outMatrix = matAttr.create("outMatrix", "oMat",OpenMaya.MFnMatrixAttribute.kDouble) 239 | yakisoba.outScale = nAttr.create( "outScale", "outS", OpenMaya.MFnNumericData.k3Double,1.0 ) 240 | 241 | yakisoba.output = cAttr.create( "output", "out" ) 242 | cAttr.addChild(yakisoba.outRotate) 243 | cAttr.addChild(yakisoba.outTranslate) 244 | cAttr.addChild(yakisoba.outMatrix) 245 | cAttr.addChild( yakisoba.outScale) 246 | 247 | cAttr.setArray(1) 248 | cAttr.setStorable(1) 249 | cAttr.setKeyable(0) 250 | cAttr.setHidden(True) 251 | cAttr.setUsesArrayDataBuilder(1) 252 | yakisoba.addAttribute(yakisoba.output) 253 | 254 | yakisoba.attributeAffects( yakisoba.inputCurve , yakisoba.output ) 255 | yakisoba.attributeAffects( yakisoba.inputRibbon , yakisoba.output) 256 | yakisoba.attributeAffects( yakisoba.uValue , yakisoba.output) 257 | yakisoba.attributeAffects( yakisoba.twist , yakisoba.output) 258 | yakisoba.attributeAffects( yakisoba.disableRotation , yakisoba.output) 259 | 260 | yakisoba.uParameters = typed_Attr.create( "uParameters", "uuPrm", OpenMaya.MFnData.kDoubleArray) 261 | typed_Attr.setStorable(1) 262 | typed_Attr.setKeyable(0) 263 | typed_Attr.setHidden(1) 264 | yakisoba.addAttribute(yakisoba.uParameters) 265 | 266 | yakisoba.splineMatrix = typed_Attr.create( "splineMatrix", "sMat", OpenMaya.MFnData.kVectorArray) 267 | typed_Attr.setStorable(1) 268 | typed_Attr.setKeyable(0) 269 | typed_Attr.setHidden(1) 270 | yakisoba.addAttribute(yakisoba.splineMatrix) 271 | 272 | yakisoba.attributeAffects( yakisoba.inputCurve , yakisoba.splineMatrix ) 273 | yakisoba.attributeAffects( yakisoba.inputRibbon , yakisoba.splineMatrix ) 274 | yakisoba.attributeAffects( yakisoba.uParameters , yakisoba.splineMatrix ) 275 | yakisoba.attributeAffects( yakisoba.twist , yakisoba.splineMatrix ) 276 | 277 | 278 | def initializePlugin(mobject): 279 | mplugin = OpenMayaMPx.MFnPlugin(mobject, __author, __plug_in__Version, "Any") 280 | try: 281 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 282 | except: 283 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 284 | def uninitializePlugin(mobject): 285 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 286 | try: 287 | mplugin.deregisterNode( kPluginNodeId ) 288 | except: 289 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise -------------------------------------------------------------------------------- /maya/plug-ins/caramel.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # caramel.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | 10 | L I C E N S E: 11 | Copyright (c) 2014 Cedric BAZILLOU All rights reserved. 12 | 13 | Permission is hereby granted 14 | -to modify the file 15 | -distribute 16 | -share 17 | -do derivative work 18 | 19 | The above copyright notice and this permission notice shall be included in all copies of the Software 20 | and is subject to the following conditions: 21 | - Te user uses the same type of license 22 | - credit the original author 23 | - does not claim patent nor copyright from the original work 24 | 25 | P U R P O S E: 26 | Trigger an array of pose space helper/blendshape 27 | 28 | I N S T A L L A T I O N: 29 | Copy the "caramel.py" to your Maya plugins directory 30 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 31 | 32 | or better in your maya user directory: 33 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 34 | ''' 35 | 36 | import math, sys 37 | import maya.OpenMaya as OpenMaya 38 | import maya.OpenMayaMPx as OpenMayaMPx 39 | 40 | kPluginNodeName = "caramel" 41 | kPluginNodeId = OpenMaya.MTypeId(0xF1C473) 42 | kPluginVersion = "1.286" 43 | kPluginAuthor = "Bazillou2012" 44 | 45 | 46 | outFn = OpenMaya.MFnNurbsSurface() 47 | surfDataFn = OpenMaya.MFnNurbsSurfaceData() 48 | 49 | class caramel(OpenMayaMPx.MPxNode): 50 | def __init__(self): 51 | OpenMayaMPx.MPxNode.__init__(self) 52 | def check_curve_surface_plugs(self,argList): 53 | actionData = argList[0] 54 | inputNurbsConnected = False 55 | 56 | if actionData.isNull() == False : 57 | inputNurbsConnected = True 58 | return inputNurbsConnected 59 | def compute_knotData(self,input_Hdle,size_Value ): 60 | knotMatrixList = [] 61 | knotSmoothList = OpenMaya.MDoubleArray() 62 | hdleSizeList = [] 63 | aimMatB = 0 64 | knotCount = input_Hdle.elementCount() 65 | for k in range(knotCount): 66 | knotMatrix_value = input_Hdle.inputValue().asMatrix() 67 | knotMatrixList.append(knotMatrix_value ) 68 | if k != knotCount-1: 69 | input_Hdle.next() 70 | return knotMatrixList 71 | def computKnotList (self,degreeN ,vertLen): 72 | #degree N with M span 73 | #The number of knots required for a curve is M + 2N - 1 74 | 75 | path_knots = OpenMaya.MDoubleArray() 76 | 77 | spansM = float(vertLen-degreeN) 78 | ispans = vertLen-degreeN 79 | 80 | for k in range(degreeN-1): 81 | path_knots.append(0.0) 82 | 83 | for k in range(ispans +1) : 84 | path_knots.append(k) 85 | 86 | for k in range(degreeN-1): 87 | path_knots.append(spansM) 88 | 89 | 90 | return path_knots 91 | def compute(self,Plug,Data): 92 | if Plug == self.output or Plug == self.outputCurve or Plug == self.profil: 93 | #Layout necessary output / input handle to gather data 94 | input_Hdle = Data.inputArrayValue(self.input) 95 | 96 | knotCount = input_Hdle.elementCount() 97 | if knotCount > 0: 98 | output_handle = Data.outputValue(self.output) 99 | size_Value = Data.inputValue(self.size).asDouble() 100 | width_Value = Data.inputValue(self.width).asDouble() 101 | outputCurveDegree_Value = Data.inputValue(self.curveDegree).asInt() 102 | orientHandle_Value = Data.inputValue(self.orientHandle).asBool() 103 | 104 | knotMatrixList = self.compute_knotData(input_Hdle,size_Value ) 105 | 106 | neutralPoint = OpenMaya.MPoint(0,0,0) 107 | PointA = OpenMaya.MPoint(0,0,width_Value) 108 | PointB = OpenMaya.MPoint(0,0,-width_Value) 109 | 110 | pointListA = OpenMaya.MPointArray() 111 | pointListB = OpenMaya.MPointArray() 112 | if len(knotMatrixList) > 1: 113 | pointListA.append(PointA*knotMatrixList[0]) 114 | pointListB.append(PointB*knotMatrixList[0]) 115 | 116 | if len(knotMatrixList) > 2: 117 | for k in range(1,len(knotMatrixList)): 118 | pointListA.append(PointA*knotMatrixList[k]) 119 | pointListB.append(PointB*knotMatrixList[k]) 120 | knotList = self.computKnotList(outputCurveDegree_Value,pointListA.length()) 121 | 122 | newOutputObj = surfDataFn.create() 123 | 124 | uKnotSequences = OpenMaya.MDoubleArray() 125 | vKnotSequences = OpenMaya.MDoubleArray() 126 | 127 | uKnotSequences.append(0.0) 128 | uKnotSequences.append(1.0) 129 | 130 | controlVertices = OpenMaya.MPointArray() 131 | 132 | for k in range(pointListB.length()): 133 | controlVertices.append(pointListB[k]) 134 | for k in range(pointListA.length()): 135 | controlVertices.append(pointListA[k]) 136 | 137 | if Plug == self.output : 138 | for k in range(knotList.length()): 139 | vKnotSequences.append(knotList[k]) 140 | outFn.create ( controlVertices, uKnotSequences,vKnotSequences, 1, outputCurveDegree_Value, 141 | OpenMaya.MFnNurbsSurface.kOpen , OpenMaya.MFnNurbsSurface.kOpen ,True, newOutputObj) 142 | 143 | 144 | output_handle.setMObject(newOutputObj) 145 | output_handle.setClean() 146 | if Plug == self.outputCurve: 147 | output_Handle = Data.outputValue(self.outputCurve) 148 | 149 | outputCurveFn = OpenMaya.MFnNurbsCurve() 150 | crvDatStock = OpenMaya.MFnNurbsCurveData() 151 | crbOBJ = crvDatStock.create() 152 | outputCurveFn = OpenMaya.MFnNurbsCurve() 153 | 154 | cv_pointList = OpenMaya.MPointArray(pointListA.length()) 155 | for k in range(pointListA.length()): 156 | cv_pointList.set(pointListA[k] + (pointListB[k] - pointListA[k])*0.5, k) 157 | 158 | 159 | outputCurveFn.create( cv_pointList , knotList, outputCurveDegree_Value,OpenMaya.MFnNurbsCurve.kOpen, False, False, crbOBJ ) 160 | output_Handle.setMObject(crbOBJ) 161 | output_Handle.setClean() 162 | #------------------------------------------------------------------------------------------------------ 163 | if Plug == self.profil: 164 | aimMat = OpenMaya.MMatrix() 165 | if orientHandle_Value == True: 166 | neutralPnt = OpenMaya.MPoint() 167 | pointA = neutralPnt*knotMatrixList[0] 168 | pointB = neutralPnt*knotMatrixList[1] 169 | 170 | offsetVecB = pointB*knotMatrixList[0].inverse() - pointA*knotMatrixList[0].inverse() 171 | 172 | theTargetVector = offsetVecB.normal() 173 | referenceVector = OpenMaya.MVector(1,0,0) 174 | 175 | aimQuaternion = referenceVector.rotateTo(theTargetVector) 176 | neutralQuat = OpenMaya.MQuaternion() 177 | 178 | 179 | aimMat = aimQuaternion.asMatrix() * knotMatrixList[0] 180 | 181 | output_Handle = Data.outputValue(self.profil) 182 | 183 | outputCurveFn = OpenMaya.MFnNurbsCurve() 184 | crvDatStock = OpenMaya.MFnNurbsCurveData() 185 | crbOBJ = crvDatStock.create() 186 | outputCurveFn = OpenMaya.MFnNurbsCurve() 187 | 188 | cv_pointList = OpenMaya.MPointArray() 189 | cv_pointList.append(OpenMaya.MPoint(0,0,width_Value*-0.5)*aimMat ) 190 | cv_pointList.append(OpenMaya.MPoint(0,0,width_Value*0.5)*aimMat ) 191 | outputCurveFn.createWithEditPoints(cv_pointList , 1,OpenMaya.MFnNurbsCurve.kOpen, False, False, True, crbOBJ ) 192 | output_Handle.setMObject(crbOBJ) 193 | output_Handle.setClean() 194 | else: 195 | return 196 | 197 | def nodeCreator(): 198 | return OpenMayaMPx.asMPxPtr(caramel()) 199 | def nodeInitializer(): 200 | typed_Attr = OpenMaya.MFnTypedAttribute() 201 | nAttr = OpenMaya.MFnNumericAttribute() 202 | cAttr = OpenMaya.MFnCompoundAttribute() 203 | matAttr = OpenMaya.MFnMatrixAttribute() 204 | 205 | #---------------------------------------------------------------------------- Input Attributes 206 | 207 | caramel.orientHandle = nAttr.create( "orientHandle", "hDle", OpenMaya.MFnNumericData.kBoolean,0) 208 | nAttr.setWritable(1) 209 | nAttr.setStorable(1) 210 | nAttr.setReadable(1) 211 | nAttr.setKeyable(1) 212 | nAttr.setHidden(0) 213 | caramel.addAttribute(caramel.orientHandle) 214 | 215 | caramel.input = matAttr.create("input", "in",OpenMaya.MFnMatrixAttribute.kDouble) 216 | matAttr.setArray(1) 217 | matAttr.setStorable(0) 218 | matAttr.setKeyable(0) 219 | matAttr.setHidden(1) 220 | caramel.addAttribute(caramel.input) 221 | 222 | caramel.width = nAttr.create("width","wdt", OpenMaya.MFnNumericData.kDouble,0.2) 223 | nAttr.setWritable(1) 224 | nAttr.setStorable(1) 225 | nAttr.setReadable(1) 226 | nAttr.setKeyable(1) 227 | nAttr.setHidden(0) 228 | nAttr.setMin(0.001) 229 | nAttr.setSoftMax(20.0) 230 | caramel.addAttribute(caramel.width) 231 | 232 | caramel.curveDegree = nAttr.create("curveDegree","cDg", OpenMaya.MFnNumericData.kInt,2) 233 | nAttr.setWritable(1) 234 | nAttr.setStorable(1) 235 | nAttr.setReadable(1) 236 | nAttr.setKeyable(1) 237 | nAttr.setHidden(0) 238 | nAttr.setMin(1) 239 | nAttr.setMax(3) 240 | caramel.addAttribute(caramel.curveDegree) 241 | 242 | caramel.size = nAttr.create("size","sz", OpenMaya.MFnNumericData.kDouble,1.0) 243 | nAttr.setWritable(1) 244 | nAttr.setStorable(1) 245 | nAttr.setReadable(1) 246 | nAttr.setKeyable(1) 247 | nAttr.setHidden(0) 248 | nAttr.setMin(0.001) 249 | nAttr.setSoftMax(2.0) 250 | caramel.addAttribute(caramel.size) 251 | 252 | #---------------------------------------------------------------------------- Output Attributes 253 | caramel.output = typed_Attr.create( "output", "out", OpenMaya.MFnData.kNurbsSurface) 254 | typed_Attr.setStorable(0) 255 | typed_Attr.setKeyable(0) 256 | typed_Attr.setHidden(True) 257 | caramel.addAttribute(caramel.output) 258 | 259 | caramel.attributeAffects( caramel.input , caramel.output ) 260 | caramel.attributeAffects( caramel.width , caramel.output ) 261 | caramel.attributeAffects( caramel.size , caramel.output ) 262 | caramel.attributeAffects( caramel.curveDegree , caramel.output ) 263 | caramel.attributeAffects( caramel.orientHandle , caramel.output ) 264 | #---------------------------------------------------------------------------- Output Attributes 265 | caramel.outputCurve = typed_Attr.create( "outputCurve", "outCrv", OpenMaya.MFnData.kNurbsCurve) 266 | typed_Attr.setStorable(0) 267 | typed_Attr.setKeyable(0) 268 | typed_Attr.setHidden(True) 269 | caramel.addAttribute(caramel.outputCurve) 270 | 271 | caramel.attributeAffects( caramel.input , caramel.outputCurve ) 272 | caramel.attributeAffects( caramel.width , caramel.outputCurve ) 273 | caramel.attributeAffects( caramel.size , caramel.outputCurve ) 274 | caramel.attributeAffects( caramel.curveDegree , caramel.outputCurve ) 275 | caramel.attributeAffects( caramel.orientHandle , caramel.outputCurve ) 276 | 277 | caramel.profil = typed_Attr.create( "profil", "prf", OpenMaya.MFnNurbsCurveData.kNurbsCurve ) 278 | typed_Attr.setStorable(0) 279 | typed_Attr.setKeyable(0) 280 | typed_Attr.setHidden(True) 281 | caramel.addAttribute( caramel.profil ) 282 | 283 | caramel.attributeAffects( caramel.input , caramel.profil ) 284 | caramel.attributeAffects( caramel.width , caramel.profil ) 285 | caramel.attributeAffects( caramel.size , caramel.profil ) 286 | caramel.attributeAffects( caramel.curveDegree , caramel.profil ) 287 | caramel.attributeAffects( caramel.orientHandle , caramel.profil ) 288 | 289 | 290 | def initializePlugin(mobject): 291 | mplugin = OpenMayaMPx.MFnPlugin(mobject, kPluginAuthor , kPluginVersion , "Any") 292 | try: 293 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 294 | except: 295 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 296 | def uninitializePlugin(mobject): 297 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 298 | try: 299 | mplugin.deregisterNode( kPluginNodeId ) 300 | except: 301 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise -------------------------------------------------------------------------------- /maya/rig/dish/manager.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | import maya.cmds as mc 3 | import maya.OpenMaya as OpenMaya 4 | import inspect 5 | import zipfile 6 | from functools import partial 7 | import json 8 | import uuid 9 | import datetime 10 | 11 | if 'dish.data' not in sys.modules.keys(): 12 | frme = inspect.currentframe() 13 | frameData = inspect.getframeinfo(frme) 14 | modulePath = os.path.dirname(frameData[0]) 15 | modulePath = os.path.dirname(modulePath) 16 | sys.path.append(modulePath) 17 | 18 | if 'dishCore' not in sys.modules.keys(): 19 | import dish.core as dishCore 20 | reload(dishCore) 21 | 22 | 23 | author = 'cedric bazillou 2013' 24 | version = 0.02 25 | 26 | class dishComponent: 27 | def __init__(self): 28 | self.canvasSize =[430,400] 29 | def expose_list(self,tabAnchor,rootData): 30 | samplingConnections = rootData[0] 31 | caption = rootData[1] 32 | mc.textField( tx=caption,ed=False ,p=tabAnchor , font="boldLabelFont",bgc=[0.8,0.8,0.8]) 33 | mc.optionMenu( label=' Options: ' ,p=tabAnchor , w=432 -30) 34 | mc.menuItem( label='select' ) 35 | mc.menuItem( label='connect' ) 36 | mc.menuItem( label='swap' ) 37 | mc.menuItem( label='constraint' ) 38 | mc.menuItem( label='Manage Input' ) 39 | scrollWdth = mc.scrollLayout( horizontalScrollBarThickness=0,verticalScrollBarThickness=8, p=tabAnchor ,h=150,childResizable=True ) 40 | 41 | inputIdxList = mc.getAttr(samplingConnections,mi=True ) 42 | ctrlHgt = 24 43 | for idx in inputIdxList: 44 | input = mc.listConnections(samplingConnections+'[%s]'%idx) 45 | 46 | if input is not None and len(input)>0: 47 | input = input[0] 48 | else: 49 | input = samplingConnections+'[%s]'%idx 50 | 51 | mc.separator(style='none', p=scrollWdth,h=6 ) 52 | mc.flowLayout( columnSpacing=4 , p=scrollWdth ) 53 | fldLnk = mc.textField( tx=input,ed=False ,w=395 -30,h=ctrlHgt) 54 | mc.popupMenu( button=3 ,p=fldLnk) 55 | mc.menuItem(l='moveUP' ) 56 | mc.menuItem(l='moveDown' ) 57 | mc.menuItem(l='Delete' ) 58 | mc.button( label='<') 59 | def expose_component(self,tabAnchor,rootData): 60 | attrib_link = rootData[0] 61 | ctrlHgt = 24 62 | nodeData = attrib_link.split('.') 63 | typeChk = mc.attributeQuery( nodeData[-1], node=nodeData[0], attributeType=True ) 64 | numericType = ['float','double','short','long','int','bool','enum','string'] 65 | clm = mc.columnLayout( adjustableColumn=True, rs=5 ,p=tabAnchor, w=420 -30 ) 66 | 67 | stringType = mc.getAttr(attrib_link,type=True) 68 | fildCaption = mc.textField( tx=rootData[1],ed=False,w=410 -30 ,p=clm , font="boldLabelFont",bgc=[0.8,0.8,0.8]) 69 | mc.popupMenu( button=3 ,p=fildCaption) 70 | mc.menuItem(l='Open in connection Editor' ) 71 | 72 | 73 | if stringType == 'string': 74 | attrFld = mc.textField( ed=True,w=410 -30 ,p=clm ) 75 | mc.connectControl( attrFld, attrib_link ) 76 | 77 | else: 78 | if typeChk in numericType: 79 | mc.attrFieldSliderGrp( attribute=rootData[0],p=clm ) 80 | else: 81 | flw = mc.flowLayout( columnSpacing=4 , p=clm ) 82 | fldLnk = mc.textField( tx=rootData[0],ed=False ,w=385,h=ctrlHgt,p=flw) 83 | mc.button( label='<',p=flw) 84 | class UI: 85 | def __init__(self): 86 | self.module='' 87 | self.canvasSize =[430,400] 88 | self.InfosTab = '' 89 | self.bentoElements = '' 90 | self.gourmetTab = '' 91 | self.dishPrfx = '' 92 | self.pathTxFld = '' 93 | self.dishType = '' 94 | self.dishTabTool = '' 95 | self.editTool = '' 96 | self.ImportTab = '' 97 | self.EditTab = '' 98 | self.FindTab = '' 99 | self.swtTab = '' 100 | self.IO = dishCore.IO() 101 | self.factory = dishCore.factory() 102 | self.dishComponent = dishComponent() 103 | self.dishInputsComponents = '' 104 | self.dishOutputsComponents = '' 105 | self.currentEditedDish = '' 106 | self.IO_TAB = '' 107 | def widget(self,widgetParent): 108 | hook = mc.columnLayout( adjustableColumn=True, rs=5 ,p=widgetParent) 109 | mc.separator() 110 | mc.rowLayout( numberOfColumns=3, 111 | columnWidth2=(80,(self.canvasSize[0]-80-20)), 112 | adjustableColumn=2,cl2=('left','both' ) ) 113 | mc.text(l=' Current Path :') 114 | self.pathTxFld = mc.textField( 'buildEditor_UI_data_dir_txFld',ed=False ) 115 | mc.setParent('..') 116 | mc.separator() 117 | 118 | self.swtTab = mc.tabLayout( innerMarginWidth=5, innerMarginHeight=5 ) 119 | self.ImportTab = mc.frameLayout( mw=5,labelVisible=False,mh=5 ,p=self.swtTab) 120 | 121 | self.EditTab = mc.frameLayout( mw=5,labelVisible=False,mh=5 ,p=self.swtTab) 122 | 123 | mc.columnLayout( adjustableColumn=True) 124 | mc.frameLayout( borderStyle='etchedIn',collapsable=False,labelVisible=False,mw= 3 ,mh=3) 125 | mc.rowLayout( h=26,numberOfColumns=3, columnWidth3=(80,(self.canvasSize[0]-80-20),20), adjustableColumn=2,cl3=('left','both','right')) 126 | mc.text(l=' Current Dish :') 127 | self.currentEditedDish = mc.textField( ) 128 | rRootBtnC = mc.button(l='<' ,c=self.expose_dish_root) 129 | 130 | self.IO_TAB = mc.tabLayout( innerMarginWidth=5, innerMarginHeight=5,p=self.EditTab ) 131 | mc.frameLayout( borderStyle='etchedIn',collapsable=False,labelVisible=False,mw= 5 ,mh=5,p=self.IO_TAB ) 132 | mc.scrollLayout( horizontalScrollBarThickness=0,verticalScrollBarThickness=8, h=200,childResizable=True ) 133 | self.dishInputsComponents = mc.columnLayout( adjustableColumn=True,rs=3) 134 | 135 | mc.frameLayout( borderStyle='etchedIn',collapsable=False,labelVisible=False,mw= 5 ,mh=5,p=self.IO_TAB ) 136 | mc.scrollLayout( horizontalScrollBarThickness=0,verticalScrollBarThickness=8, h=200,childResizable=True) 137 | self.dishOutputsComponents = mc.columnLayout( adjustableColumn=True,rs=3) 138 | 139 | mc.tabLayout(self.IO_TAB ,e=True,tabLabelIndex=[1,'Inputs']) 140 | mc.tabLayout(self.IO_TAB ,e=True,tabLabelIndex=[2,'Outputs']) 141 | 142 | self.FindTab = mc.frameLayout( mw=5,labelVisible=False,mh=5 ,p=self.swtTab) 143 | self.createGourmetTab() 144 | mc.textScrollList( self.bentoElements , e=True,ra=True) 145 | 146 | mc.tabLayout(self.swtTab ,e=True,tabLabelIndex=[1,'Import']) 147 | mc.tabLayout(self.swtTab ,e=True,tabLabelIndex=[2,'Edit']) 148 | mc.tabLayout(self.swtTab ,e=True,tabLabelIndex=[3,'Find']) 149 | 150 | mc.tabLayout(self.swtTab,e=True,changeCommand=self.refresh_dishTabs_contents) 151 | 152 | anchorDock = mc.rowLayout( numberOfColumns=2, 153 | columnWidth2=(self.canvasSize[0]/5*2+12, 75 ), 154 | adjustableColumn=2, 155 | columnAlign=(1, 'right'), 156 | columnAttach=[(1,'both',0), (2,'both',0)] ,w=self.canvasSize[0],p=self.ImportTab) 157 | 158 | self.exposedBentos_UI(anchorDock) 159 | #------------------------------------------------------------------------------------------------------------ 160 | self.bentosFactory_UI(anchorDock) 161 | 162 | modulePath = ''.join(os.path.dirname(inspect.getfile(self.exposedBentos_UI))) 163 | mc.textField( self.pathTxFld ,e=True,tx=modulePath) 164 | def cleanUP_editDishTAB(self,anchor): 165 | mc.textField( self.currentEditedDish ,e=True,tx='' ) 166 | chldList = mc.layout(anchor,q=True,ca=True) 167 | 168 | if chldList is not None and len(chldList)>0: 169 | for chld in chldList: 170 | mc.deleteUI(chld) 171 | def expose_dish_root(self,*args): 172 | root = mc.ls(sl=True,fl=True) 173 | self.cleanUP_editDishTAB(self.dishInputsComponents) 174 | self.cleanUP_editDishTAB(self.dishOutputsComponents) 175 | if root is not None and len(root)>0: 176 | root = root[0] 177 | rootData = self.factory.retrieve_IO_Connections( root,0 ) 178 | 179 | #fILL INPUTS 180 | if rootData is None: 181 | self.cleanUP_editDishTAB(self.dishInputsComponents) 182 | self.cleanUP_editDishTAB(self.dishOutputsComponents) 183 | return 184 | else: 185 | mc.textField( self.currentEditedDish ,e=True,tx=root ) 186 | for key in rootData.keys(): 187 | componentIsList = rootData[key][-1] 188 | if componentIsList == True: 189 | self.dishComponent.expose_list(self.dishInputsComponents,rootData[key] ) 190 | else: 191 | self.dishComponent.expose_component(self.dishInputsComponents,rootData[key]) 192 | #fILL OUTPUTS 193 | rootData = self.factory.retrieve_IO_Connections( root,1) 194 | if rootData is None: 195 | self.cleanUP_editDishTAB(self.dishInputsComponents) 196 | self.cleanUP_editDishTAB(self.dishOutputsComponents) 197 | return 198 | else: 199 | mc.textField( self.currentEditedDish ,e=True,tx=root ) 200 | for key in rootData.keys(): 201 | componentIsList = rootData[key][-1] 202 | if componentIsList == True: 203 | self.dishComponent.expose_list(self.dishOutputsComponents,rootData[key] ) 204 | else: 205 | self.dishComponent.expose_component(self.dishOutputsComponents,rootData[key]) 206 | def exposedBentos_UI(self,anchor): 207 | leftPanel = mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='etchedIn',mw=5,mh=5,p=anchor ) 208 | mc.columnLayout( adjustableColumn=True, rs=5 ) 209 | mc.text(l='Available Bentos') 210 | mc.scrollLayout( horizontalScrollBarThickness=0,verticalScrollBarThickness=8) 211 | scrollWdth = mc.columnLayout( adjustableColumn=True, rs=5,w=self.canvasSize[0]/5*2-27,h=self.canvasSize[1]-20) 212 | dishList = self.IO.exposeZipTemplate() 213 | 214 | dishName = '' 215 | for dish in dishList: 216 | dishName = os.path.basename(dish).split('.zip')[0] 217 | btn = mc.button(l=dishName,h=28,ann='test') 218 | mc.button(btn,e=True,c=partial( self.switch_module, dishName ,dish )) 219 | def switch_module(self,dishName,dishFile,*args): 220 | archive = zipfile.ZipFile(dishFile, 'r') 221 | jsonFile = archive.read('dish.ini') 222 | jsondata = json.loads(jsonFile) 223 | archive.close() 224 | 225 | #Clear chld 226 | chldrn = mc.layout( self.InfosTab, query=True, childArray=True ) 227 | for chld in chldrn: 228 | mc.deleteUI(chld) 229 | #------------------------------------------------------------------- 230 | mc.columnLayout( adjustableColumn=True ,p=self.InfosTab ,rs=5) 231 | header = """ 232 | 233 |

%s

234 | 235 | """%(dishName ) 236 | 237 | self.dishType = dishName 238 | mc.text( self.module,e=True,l=header,font='boldLabelFont') 239 | mc.scrollField( editable=False, wordWrap=True, text=jsondata['moduleInfos'] ,h=140) 240 | mc.separator() 241 | mc.text( l='name bank') 242 | mc.columnLayout( adjustableColumn=True) 243 | LimbMenu = mc.optionMenu( label='',w=224 ) 244 | mc.menuItem( label='NONE') 245 | mc.setParent('..') 246 | mc.button(l='Open name composer',h=28) 247 | mc.optionMenu( LimbMenu ,e=True,changeCommand=partial(self.composePrfX,LimbMenu)) 248 | 249 | self.dishPrfx = mc.textField() 250 | mc.button(l='Import', h=42,c=self.validate_dish_before_merge ) 251 | def validate_dish_before_merge(self,*args): 252 | prx = mc.textField( self.dishPrfx ,q=True,tx=True) 253 | if len(prx)>1: 254 | path = mc.textField( self.pathTxFld, q=True,tx=True) 255 | dishFile = os.path.join( path,self.dishType+'.zip') 256 | self.IO.merge( dishFile,'XX_',prx+'_') 257 | def composePrfX (self,menuOpt ,*args): 258 | prx = mc.textField( self.dishPrfx ,q=True,tx=True) 259 | module = mc.optionMenu(menuOpt,q=True,value=True).strip() 260 | if module == 'NONE': 261 | return 262 | if len(prx)<1: 263 | if '*' in module: 264 | module = module.split('*')[1] 265 | mc.textField( self.dishPrfx ,e=True,tx=module) 266 | else: 267 | if '*' in module: 268 | module = module.split('*')[1] 269 | mc.textField( self.dishPrfx ,e=True,tx=prx+'_'+module ) 270 | def bentosFactory_UI(self,anchor): 271 | self.dishTabTool = mc.columnLayout( adjustableColumn=True,p=anchor ) 272 | self.module= mc.text( 'CCW_TOOLS_DISHNAME_txFld', l='', h=36 ) 273 | self.InfosTab = mc.frameLayout( mw=5,labelVisible=False,mh=5,p=self.dishTabTool ) 274 | mc.text(l='') 275 | dishList = self.IO.exposeZipTemplate() 276 | if dishList is not None and len(dishList)>0: 277 | self.switch_module( os.path.basename(dishList[0]).split('.zip')[0],dishList[0] ) 278 | def createGourmetTab( self ): 279 | self.gourmetTab = mc.frameLayout( mw=5,labelVisible=False,mh=5,p=self.FindTab) 280 | mc.columnLayout( adjustableColumn=True ) 281 | self.bentoElements = mc.textScrollList( 'CCW_TOOLS_bentoElements',numberOfRows=22, selectCommand=self.select_installedDish ) 282 | def select_installedDish(self,*args): 283 | dish = mc.textScrollList( 'CCW_TOOLS_bentoElements',q=True,selectItem=True) 284 | mc.select(dish,r=True) 285 | def refresh_dishTabs_contents(self,*args): 286 | currentTab = mc.tabLayout(self.swtTab ,q=True,selectTabIndex=True) 287 | 288 | if currentTab == 3: 289 | mc.textScrollList( self.bentoElements ,e=True,ra=True) 290 | globalDishList = self.IO.exposeZipTemplate() 291 | dishes = [] 292 | for dish in globalDishList: 293 | dishName = os.path.basename(dish).split('.zip')[0] 294 | dishes.append(dishName) 295 | 296 | for dishModule in dishes: 297 | dishList = self.factory.collect_similar_dish(dishModule)#self.dishType 298 | if len(dishList)>0: 299 | for dish in dishList: 300 | mc.textScrollList( self.bentoElements ,e=True,a=dish) 301 | -------------------------------------------------------------------------------- /maya/rig/dish/core.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | import maya.cmds as mc 3 | import maya.OpenMaya as OpenMaya 4 | import inspect 5 | import zipfile 6 | from functools import partial 7 | import json 8 | import uuid 9 | import datetime 10 | 11 | if 'dish.data' not in sys.modules.keys(): 12 | frme = inspect.currentframe() 13 | frameData = inspect.getframeinfo(frme) 14 | modulePath = os.path.dirname(frameData[0]) 15 | modulePath = os.path.dirname(modulePath) 16 | sys.path.append(modulePath) 17 | 18 | import dish.dishData as attrToFilter 19 | reload(attrToFilter) 20 | 21 | 22 | author = 'cedric bazillou 2013' 23 | version = 0.05 24 | 25 | class IO: 26 | def compile_bundle(self,*args): 27 | templateList = self.exposeBundles() 28 | 29 | if templateList is not None and len(templateList) > 0: 30 | mc.progressBar( 'CCW_TOOLS_bundle_prgrss', 31 | edit=True, 32 | beginProgress=True, 33 | isInterruptable=True, 34 | status='Please wait ...' , 35 | maxValue=len(templateList) ) 36 | 37 | for idx in range(len(templateList)): 38 | tmpleName = os.path.basename(os.path.dirname(templateList[idx])) 39 | tmpleDir = str(os.path.dirname(templateList[idx])) 40 | tmpleRoot = os.path.dirname(inspect.getfile(self.merge)) 41 | tmpleRoot = r''.join(tmpleRoot) 42 | 43 | tmpleRoot = os.path.join(tmpleRoot,'lunchBox') 44 | 45 | zipPath = os.path.join(tmpleRoot,tmpleName+'.zip') 46 | self.createBundle(tmpleDir,zipPath,tmpleRoot) 47 | mc.progressBar('CCW_TOOLS_bundle_prgrss', edit=True, step=1) 48 | mc.progressBar('CCW_TOOLS_bundle_prgrss', edit=True, endProgress=True) 49 | def createBundle(self,sourcePath,outputZip,root): 50 | myzip = zipfile.ZipFile(outputZip, 'w') 51 | myzip.write( os.path.join( sourcePath ,'dish.ini') , r'\dish.ini' ) 52 | myzip.write( os.path.join( sourcePath ,'widget.py') , r'\widget.py' ) 53 | myzip.write( os.path.join( sourcePath ,'data.ma') , r'\data.ma') 54 | myzip.close() 55 | def exposeZipTemplate(self): 56 | modulePath = os.path.dirname(inspect.getfile(self.merge)) 57 | modulePath = os.path.join(modulePath,'lunchBox') 58 | filelist= os.listdir(modulePath) 59 | modulelist = [ f for f in filelist if f.endswith('.zip') ] 60 | for k in range(len(modulelist)): 61 | modulelist[k] = os.path.join(modulePath,modulelist[k]) 62 | return modulelist 63 | def exposeBundles(self): 64 | modulePath = os.path.dirname(inspect.getfile(self.merge)) 65 | modulePath = os.path.join(modulePath,'src') 66 | 67 | dirlist= os.listdir(modulePath) 68 | if dirlist is not None and len(dirlist)> 0: 69 | filteredDirlist = [] 70 | 71 | for dir in dirlist: 72 | if os.path.isdir(os.path.join(modulePath,dir)) == True: 73 | filteredDirlist.append(os.path.join(modulePath,dir,'data.ma')) 74 | 75 | return filteredDirlist 76 | else: 77 | return None 78 | def merge(self,sourcePath,prfxToReplace,newModuleName): 79 | ## ------------------------------- first create temp module 80 | ## ------------------------------- then name elements properly 81 | scrpDir = mc.internalVar(userScriptDir=True) 82 | localModuleToMerge = os.path.join(scrpDir,newModuleName+'.01.ma') 83 | archive = zipfile.ZipFile(sourcePath, 'r') 84 | jsonFile = archive.open('data.ma') 85 | 86 | outputFile = open(localModuleToMerge, "w") 87 | 88 | for line in jsonFile: 89 | if prfxToReplace in line: 90 | nwLn = line.replace(prfxToReplace,newModuleName) 91 | outputFile.writelines( nwLn) 92 | else: 93 | outputFile.writelines(line) 94 | archive.close() 95 | outputFile.close() 96 | ## ------------------------------- inject it in your scene 97 | mc.file(localModuleToMerge,i=True) 98 | mc.sysFile(localModuleToMerge,delete=True) 99 | 100 | #now list new imported module 101 | content = mc.ls(type='transform') 102 | attributeList = ['foodType','uuID'] 103 | nwNode = [] 104 | for obj in content: 105 | idx = 0 106 | for index, attr in enumerate(attributeList): 107 | if mc.attributeQuery(attributeList[index],node=obj,ex=True) == True: 108 | idx += 1 109 | if idx > 1: 110 | nwNode.append(obj) 111 | mc.setAttr(nwNode[0] +'.uuID',l=False) 112 | mc.deleteAttr(nwNode[0] +'.uuID') 113 | 114 | foodTpe = mc.getAttr(nwNode[0] +'.foodType') 115 | OpenMaya.MGlobal.displayInfo( '**The %s dish %s was successfully merge in your scene'% (foodTpe, newModuleName) ) 116 | return nwNode[0] 117 | def clean_asset_file(): 118 | pass 119 | class factory: 120 | def expose_members(self , 121 | root, 122 | assetListing ): 123 | if mc.objExists(root)==True: 124 | attributeList = [ 'element'] 125 | 126 | for index, attr in enumerate(attributeList): 127 | if mc.attributeQuery(attributeList[index],node=root,ex=True) == False: 128 | mc.addAttr(root,ln=attributeList[index] ,m=True,h=True,k=False) 129 | 130 | for index, elemObj in enumerate(assetListing): 131 | try: 132 | mc.connectAttr(elemObj+'.nodeState','%s.%s[%s]'%( root ,attributeList[0], index), f=True) 133 | except: 134 | pass 135 | OpenMaya.MGlobal.displayInfo( '** Module elements were added to %s '% root ) 136 | def process_root(self, root, 137 | foodType, 138 | moduleInfos ): 139 | if mc.objExists(root)==True: 140 | flagKey = str(uuid.uuid4().hex) 141 | attributeList = ['foodType','moduleInfos']#,'uuID' 142 | dataList = [foodType,moduleInfos,flagKey] 143 | for index, attr in enumerate(attributeList): 144 | if mc.attributeQuery(attributeList[index],node=root,ex=True) == False: 145 | mc.addAttr(root,ln=attributeList[index],dt='string') 146 | mc.setAttr('%s.%s'%(root ,attributeList[index] ),l=False) 147 | mc.setAttr('%s.%s'%(root ,attributeList[index] ) ,dataList[index],type='string') 148 | mc.setAttr('%s.%s'%(root ,attributeList[index] ),l=True) 149 | OpenMaya.MGlobal.displayInfo( '** %s was successfully Flagged'% root ) 150 | def publish_driver(self,root): 151 | modulePath = os.path.dirname(inspect.getfile(self.expose_members)) 152 | attributeList = ['foodType','moduleInfos','element'] 153 | 154 | foodType = mc.getAttr('%s.%s'%(root,attributeList[0])) 155 | directory = os.path.join(os.path.join(modulePath,'src'),foodType) 156 | 157 | if not os.path.isdir(directory): 158 | os.makedirs(directory) 159 | targetFile = os.path.join(directory,'data.ma') 160 | filename = os.path.join(directory,'dish.ini') 161 | widgetname = os.path.join(directory,'widget.py') 162 | 163 | fo = open(widgetname, "w") 164 | fo.close() 165 | 166 | attributeList = ['foodType','moduleInfos' ] 167 | bakedData = {} 168 | 169 | for attr in attributeList: 170 | dat = mc.getAttr('%s.%s'%(root,attr)) 171 | if dat is None or len(dat)< 1 : 172 | dat = [] 173 | bakedData[attr]= dat 174 | 175 | mc.select (root,r=True) 176 | mc.file(targetFile,force=True,typ="mayaAscii",pr=True, es=True) 177 | 178 | try: 179 | jsondata = json.dumps(bakedData ,sort_keys=True, indent=4) 180 | fd = open(filename, 'w') 181 | fd.write(jsondata) 182 | fd.close() 183 | except: 184 | print 'ERROR writing', filename 185 | pass 186 | def collect_similar_dish(self,expextedFood): 187 | content = mc.ls(type='transform') 188 | attributeList = ['foodType' ] 189 | nwNode = [] 190 | for obj in content: 191 | idx = 0 192 | for index, attr in enumerate(attributeList): 193 | if mc.attributeQuery(attributeList[index],node=obj,ex=True) == True: 194 | if mc.getAttr(obj+'.'+attributeList[index]) == expextedFood : 195 | idx = 2 196 | if idx > 1: 197 | nwNode.append(obj) 198 | return nwNode 199 | def read_dish_data(self , root): 200 | attributeList = ['foodType','moduleInfos' ] 201 | dataList = {} 202 | for attr in attributeList : 203 | dataList[attr] = '' 204 | if mc.attributeQuery(attr,node=root,ex=True) == True: 205 | dataList[attr] = mc.getAttr('%s.%s'%(root,attr)) 206 | 207 | dataList['element'] = '' 208 | if mc.attributeQuery('element',node=root,ex=True) == True: 209 | cntList = mc.listConnections('%s.%s'%(root,'element'),sh=True) 210 | if cntList is not None and len(cntList)>0: 211 | dataList['element'] = [] 212 | dataList['element'].extend(cntList) 213 | return dataList 214 | def retrieve_IO_Connections(self,root, IO_Index ): 215 | plugList = ['recipe.py'] 216 | for plugin in plugList: 217 | if not mc.pluginInfo(plugin,q=True,l=True): 218 | mc.loadPlugin(plugin) 219 | attributeList = ['foodType','moduleInfos']#,'uuID' 220 | chkErrr = 0 221 | for index, attr in enumerate(attributeList): 222 | if mc.attributeQuery(attributeList[index],node=root,ex=True) == False: 223 | chkErrr += 1 224 | 225 | if chkErrr > 0: 226 | return None 227 | 228 | attributeList = ['recipe'] 229 | cnList = ['input', 'output'] 230 | linkList = ['inlink', 'outLink'] 231 | labelList = ['inLabel', 'outLabel'] 232 | widgetID_List = ['inWidgetID', 'outWidgetID'] 233 | hub_List = ['input_useParentHub', 'output_useParentHub'] 234 | for attr in attributeList : 235 | if mc.attributeQuery(attr,node=root,ex=True) == False: 236 | storage = mc.createNode('recipe',n=''.join((root,'_',attr,'1'))) 237 | mc.addAttr(root,ln=attr,k=False,h=True) 238 | mc.connectAttr(storage+'.nodeState' ,root+'.'+attr ,f=True) 239 | 240 | mc.setAttr(storage+'.author',attrToFilter.recipeData['author'],type='string') 241 | mc.setAttr(storage+'.gitSource',attrToFilter.recipeData['gitSource'],type='string') 242 | 243 | releaseDate = str( datetime.date.today()) 244 | mc.setAttr(storage+'.releaseDate',releaseDate,type='string') 245 | dataList = {} 246 | storage = mc.listConnections(root+'.'+attributeList[0]) 247 | if storage is None: 248 | attributeList = ['recipe'] 249 | storage = mc.createNode('recipe',n=''.join((root,'_',attributeList[0],'1'))) 250 | mc.connectAttr(storage+'.nodeState' ,root+'.'+attributeList[0] ,f=True) 251 | 252 | mc.setAttr(storage+'.author',attrToFilter.recipeData['author'],type='string') 253 | mc.setAttr(storage+'.gitSource',attrToFilter.recipeData['gitSource'],type='string') 254 | 255 | else: 256 | storage = storage[0] 257 | 258 | idxList = mc.getAttr(storage+'.'+cnList[IO_Index],mi=True) 259 | if idxList is None: 260 | return None 261 | 262 | for index, value in enumerate(idxList): 263 | driverAttr = mc.connectionInfo(storage+'.'+cnList[IO_Index]+'[%s].'%value+linkList[IO_Index],sfd=True) 264 | label = mc.getAttr(storage+'.'+cnList[IO_Index]+'[%s].'%value+ labelList[IO_Index]) 265 | widgetID = mc.getAttr(storage+'.'+cnList[IO_Index]+'[%s].'%value+ widgetID_List[IO_Index] ) 266 | hubState = mc.getAttr(storage+'.'+cnList[IO_Index]+'[%s].'%value+ hub_List[IO_Index] ) 267 | 268 | if hubState == True: 269 | driverAttr = driverAttr.split('[')[0] 270 | 271 | labelLINK = (storage+'.'+cnList[IO_Index]+'[%s].'%value+ labelList[IO_Index]) 272 | widgetIDLINK = (storage+'.'+cnList[IO_Index]+'[%s].'%value+ widgetID_List[IO_Index] ) 273 | dataList[index] = [driverAttr,label,widgetID,labelLINK,widgetIDLINK,hubState] 274 | 275 | 276 | return dataList 277 | def publish_IO_Connections(self,root,targetAttribute,IO_Index ): 278 | if mc.objExists(targetAttribute) == False : 279 | return 280 | 281 | attributeList = ['recipe'] 282 | cnList = ['input', 'output'] 283 | linkList = ['inlink', 'outLink'] 284 | hub_List = ['input_useParentHub', 'output_useParentHub'] 285 | storage = mc.listConnections(root+'.'+attributeList[0]) 286 | 287 | print storage,root 288 | if storage is None: 289 | attributeList = ['recipe'] 290 | storage = mc.createNode('recipe',n=''.join((root,'_',attributeList[0],'1'))) 291 | mc.connectAttr(storage+'.nodeState' ,root+'.'+attributeList[0] ,f=True) 292 | else: 293 | storage = storage[0] 294 | 295 | idxList = mc.getAttr(storage+'.'+cnList[IO_Index] ,mi=True) 296 | idx = 0 297 | 298 | trgRoot = targetAttribute.split('.') 299 | multichk = False 300 | if mc.attributeQuery(trgRoot[1],node=trgRoot[0],multi=True) == True: 301 | targetAttribute = targetAttribute+'[0]' 302 | multichk = True 303 | if idxList is not None: 304 | idx = idxList[-1]+1 305 | mc.connectAttr( targetAttribute, storage + '.%s[%s].%s'%(cnList[IO_Index],idx,linkList[IO_Index]),f=True) 306 | 307 | if multichk == True: 308 | mc.setAttr(storage + '.%s[%s].%s'%(cnList[IO_Index],idx,hub_List[IO_Index]),1) 309 | mc.setAttr(storage + '.%s[%s].%s'%(cnList[IO_Index],idx,hub_List[IO_Index]),l=True) 310 | def delete_Connections_at_targetIndex(self,root,targetIndex,IO_Index ): 311 | attributeList = ['recipe'] 312 | cnList = ['input', 'output'] 313 | storage = mc.listConnections(root+'.'+attributeList[0]) 314 | if storage is None: 315 | attributeList = ['recipe'] 316 | storage = mc.createNode('recipe',n=''.join((root,'_',attributeList[0],'1'))) 317 | mc.connectAttr(storage+'.nodeState' ,root+'.'+attributeList[0] ,f=True) 318 | else: 319 | storage = storage[0] 320 | 321 | 322 | idxList = mc.getAttr(storage+'.'+cnList[IO_Index],mi=True) 323 | idx = 0 324 | if idxList is None: 325 | return 326 | else: 327 | targetIndex = idxList[targetIndex] 328 | if targetIndex in idxList : 329 | mc.removeMultiInstance(storage+'.'+cnList[IO_Index]+'[%s]'%targetIndex,b=True) 330 | -------------------------------------------------------------------------------- /maya/plug-ins/tortilla.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################## 3 | # # 4 | # tortilla.py # 5 | # # 6 | # Email: cedricbazillou@gmail.com # 7 | # blog: http://circecharacterworks.wordpress.com/ # 8 | ######################################################################## 9 | L I C E N S E: 10 | Copyright (c) 2013 Cedric BAZILLOU All rights reserved. 11 | 12 | Permission is hereby granted 13 | -to modify the file 14 | -distribute 15 | -share 16 | -do derivative work 17 | 18 | P U R P O S E: 19 | Compute twist on a per segment level --> we expect normalize u values.... 20 | I N S T A L L A T I O N: 21 | Copy the "tortilla.py" to your Maya plugins directory 22 | Windows: Program Files\Autodesk\MayaXXXX\bin\plug-ins\ 23 | 24 | or better in your maya user directory: 25 | %MAYA_APP_DIR%\%mayaNumber%\scripts\plug-ins\( create one if it does not exists ) 26 | ''' 27 | 28 | __plug_in__Version = "0.742" 29 | __author = "Bazillou2013" 30 | 31 | import math 32 | import maya.OpenMaya as OpenMaya 33 | import maya.OpenMayaMPx as OpenMayaMPx 34 | 35 | kPluginNodeName = "tortilla" 36 | kPluginNodeId = OpenMaya.MTypeId(0xBCB7141) 37 | 38 | 39 | 40 | 41 | class tortilla(OpenMayaMPx.MPxNode): 42 | def __init__(self): 43 | OpenMayaMPx.MPxNode.__init__(self) 44 | def update_output_storage(self,uCount,bldChck,cBuilder): 45 | #how many entry do we need add to the current output list? 46 | growVal = uCount-bldChck 47 | if growVal>0: 48 | cBuilder.growArray ( growVal ) 49 | def getValAtPos(self,pos,myRamp): 50 | valAt_util = OpenMaya.MScriptUtil() 51 | valAt_util.createFromDouble(0.0) 52 | valAtPtr = valAt_util.asFloatPtr() 53 | 54 | myRamp.getValueAtPosition(pos, valAtPtr) 55 | myMainValue = valAt_util.getFloat(valAtPtr) 56 | 57 | return myMainValue 58 | def compute(self,Plug,Data): 59 | if Plug.parent() == self.output : 60 | uParameters_obj = Data.inputValue(self.uParameters).data() 61 | 62 | if uParameters_obj.isNull() == False: 63 | DoubleArrayFn = OpenMaya.MFnDoubleArrayData(uParameters_obj) 64 | 65 | u_params = DoubleArrayFn.array() 66 | u_len = u_params.length() 67 | if u_len > 0 : 68 | output_handle = Data.outputArrayValue(self.output) 69 | startTwist_val = Data.inputValue(self.startTwist).asDouble() 70 | endTwist_val = Data.inputValue(self.endTwist).asDouble() 71 | 72 | startScale_val = Data.inputValue(self.startScale).asDouble3() 73 | endScale_val = Data.inputValue(self.endScale).asDouble3() 74 | 75 | startScale_valX = startScale_val[0] - 1.0 76 | startScale_valY = startScale_val[1] - 1.0 77 | startScale_valZ = startScale_val[2] - 1.0 78 | 79 | endScale_valX = endScale_val[0] - 1.0 80 | endScale_valY = endScale_val[1] - 1.0 81 | endScale_valZ = endScale_val[2] - 1.0 82 | 83 | twistTweak_val = Data.inputValue(self.twistTweak).asDouble() 84 | scaleTweak_val = Data.inputValue(self.scaleTweak).asDouble()-1.0 85 | 86 | cBuilder = output_handle.builder() 87 | 88 | nodeObj = self.thisMObject() 89 | rampWeightData = OpenMaya.MRampAttribute (nodeObj, self.twist_rampWeight ) 90 | numEnt = rampWeightData.getNumEntries() 91 | 92 | rampWeightDataB = OpenMaya.MRampAttribute (nodeObj, self.twistTweak_rampWeight ) 93 | numEntB = rampWeightDataB.getNumEntries() 94 | 95 | 96 | rampWeightDataC = OpenMaya.MRampAttribute (nodeObj, self.scaleTweak_rampWeight ) 97 | numEntC = rampWeightDataC.getNumEntries() 98 | 99 | 100 | rampWeightDataD = OpenMaya.MRampAttribute (nodeObj, self.endScale_rampWeight ) 101 | numEntD = rampWeightDataD.getNumEntries() 102 | 103 | 104 | 105 | for k in range(u_len): 106 | currentDH = cBuilder.addElement(k) 107 | outRotate_DH = currentDH.child(self.outRotate) 108 | outScale_DH = currentDH.child(self.outScale) 109 | 110 | uVal = u_params[k] 111 | uValB = u_params[k] 112 | 113 | if numEnt > 1 : 114 | uVal = self.getValAtPos( u_params[k] ,rampWeightData) 115 | 116 | 117 | strtVal = 1.0-uVal 118 | endVal = 0.0+uVal 119 | 120 | tweakwist_offset = 0.0 121 | tweakwist_offsetB = endVal 122 | 123 | scaleTwist_offset = 0.0 124 | if twistTweak_val != 0.0: 125 | if numEntB > 1 : 126 | tweakwist_offset = self.getValAtPos( u_params[k] ,rampWeightDataB) 127 | 128 | else: 129 | if u_params[k] < 0.5: 130 | tweakwist_offset = 1.0- ((0.5-u_params[k])/0.5) 131 | 132 | else: 133 | tweakwist_offset = 1.0- ((u_params[k]-0.5)/0.5) 134 | 135 | ############################################################################### 136 | 137 | if scaleTweak_val != 0.0: 138 | if numEntC > 1 : 139 | scaleTwist_offset = self.getValAtPos( u_params[k] ,rampWeightDataC) 140 | 141 | else: 142 | if u_params[k] < 0.5: 143 | scaleTwist_offset = 1.0- ((0.5-u_params[k])/0.5) 144 | 145 | else: 146 | scaleTwist_offset = 1.0- ((u_params[k]-0.5)/0.5) 147 | 148 | outTwist = math.radians(startTwist_val*strtVal +endTwist_val*endVal + twistTweak_val*tweakwist_offset ) 149 | 150 | 151 | if numEntD > 1 : 152 | endVal = self.getValAtPos( u_params[k] ,rampWeightDataD) 153 | 154 | scaleX = 1.0 + (startScale_valX*strtVal) + (endScale_valX*endVal) + (scaleTweak_val*scaleTwist_offset) 155 | scaleY = 1.0 + (startScale_valY*strtVal) + (endScale_valY*endVal) + (scaleTweak_val*scaleTwist_offset ) 156 | scaleZ = 1.0 + (startScale_valZ*strtVal) + (endScale_valZ*endVal) + (scaleTweak_val*scaleTwist_offset ) 157 | 158 | 159 | #write values 160 | outRotate_DH.set3Double(outTwist,0.0,0.0) 161 | outScale_DH.set3Double(scaleX,scaleY,scaleZ) 162 | 163 | 164 | output_handle.set(cBuilder) 165 | output_handle.setAllClean() 166 | if Plug == self.twistArray : 167 | uParameters_obj = Data.inputValue(self.uParameters).data() 168 | 169 | if uParameters_obj.isNull() == False: 170 | DoubleArrayFn = OpenMaya.MFnDoubleArrayData(uParameters_obj) 171 | 172 | u_params = DoubleArrayFn.array() 173 | u_len = u_params.length() 174 | if u_len > 0 : 175 | output_handle = Data.outputValue(self.twistArray) 176 | 177 | startTwist_val = Data.inputValue(self.startTwist).asDouble() 178 | endTwist_val = Data.inputValue(self.endTwist).asDouble() 179 | twistTweak_val = Data.inputValue(self.twistTweak).asDouble() 180 | 181 | nodeObj = self.thisMObject() 182 | rampWeightData = OpenMaya.MRampAttribute (nodeObj, self.twist_rampWeight ) 183 | numEnt = rampWeightData.getNumEntries() 184 | 185 | rampWeightDataB = OpenMaya.MRampAttribute (nodeObj, self.twistTweak_rampWeight ) 186 | numEntB = rampWeightDataB.getNumEntries() 187 | 188 | out_TwistList = OpenMaya.MDoubleArray(u_len,0.0) 189 | for n in range(u_len/2): 190 | k = n*2 191 | uVal = u_params[k] 192 | 193 | if numEnt > 1 : 194 | uVal = self.getValAtPos( u_params[k] ,rampWeightData) 195 | 196 | 197 | strtVal = 1.0-uVal 198 | endVal = 0.0+uVal 199 | 200 | tweakwist_offset = 0.0 201 | tweakwist_offsetB = endVal 202 | 203 | if twistTweak_val != 0.0: 204 | if numEntB > 1 : 205 | tweakwist_offset = self.getValAtPos( u_params[k] ,rampWeightDataB) 206 | 207 | else: 208 | if u_params[k] < 0.5: 209 | tweakwist_offset = 1.0- ((0.5-u_params[k])/0.5) 210 | 211 | else: 212 | tweakwist_offset = 1.0- ((u_params[k]-0.5)/0.5) 213 | 214 | 215 | outTwist = math.radians(startTwist_val*strtVal +endTwist_val*endVal + twistTweak_val*tweakwist_offset ) 216 | out_TwistList.set(outTwist,k) 217 | out_TwistList.set(u_params[k+1],k+1) 218 | out_DoubleArrayFn = OpenMaya.MFnDoubleArrayData() 219 | outOBJ = out_DoubleArrayFn.create(out_TwistList) 220 | 221 | output_handle.setMObject(outOBJ) 222 | output_handle.setClean() 223 | 224 | def nodeCreator(): 225 | return OpenMayaMPx.asMPxPtr(tortilla()) 226 | def nodeInitializer(): 227 | typed_Attr = OpenMaya.MFnTypedAttribute() 228 | nAttr = OpenMaya.MFnNumericAttribute() 229 | unitAttr = OpenMaya.MFnUnitAttribute() 230 | matAttr = OpenMaya.MFnMatrixAttribute() 231 | cAttr = OpenMaya.MFnCompoundAttribute() 232 | 233 | 234 | tortilla.uParameters = typed_Attr.create( "uParameters", "uuPrm", OpenMaya.MFnData.kDoubleArray) 235 | typed_Attr.setStorable(1) 236 | typed_Attr.setHidden(1) 237 | tortilla.addAttribute(tortilla.uParameters) 238 | 239 | 240 | tortilla.startTwist = nAttr.create( "startTwist", "sTw", OpenMaya.MFnNumericData.kDouble, 0.0 ) 241 | nAttr.setStorable(1) 242 | nAttr.setKeyable(1) 243 | nAttr.setHidden(0) 244 | tortilla.addAttribute( tortilla.startTwist) 245 | 246 | 247 | tortilla.endTwist = nAttr.create( "endTwist", "eTw", OpenMaya.MFnNumericData.kDouble, 0.0 ) 248 | nAttr.setStorable(1) 249 | nAttr.setKeyable(1) 250 | nAttr.setHidden(0) 251 | tortilla.addAttribute( tortilla.endTwist) 252 | 253 | tortilla.startScale = nAttr.create( "startScale", "sSc", OpenMaya.MFnNumericData.k3Double, 1.0 ) 254 | nAttr.setStorable(1) 255 | nAttr.setKeyable(1) 256 | nAttr.setHidden(0) 257 | tortilla.addAttribute( tortilla.startScale) 258 | 259 | tortilla.endScale = nAttr.create( "endScale", "eSc", OpenMaya.MFnNumericData.k3Double, 1.0 ) 260 | nAttr.setStorable(1) 261 | nAttr.setKeyable(1) 262 | nAttr.setHidden(0) 263 | tortilla.addAttribute( tortilla.endScale) 264 | 265 | tortilla.twistTweak = nAttr.create( "twistTweak", "sWk", OpenMaya.MFnNumericData.kDouble, 0.0 ) 266 | nAttr.setStorable(1) 267 | nAttr.setKeyable(1) 268 | nAttr.setHidden(0) 269 | tortilla.addAttribute( tortilla.twistTweak) 270 | 271 | tortilla.scaleTweak = nAttr.create( "scaleTweak", "scWk", OpenMaya.MFnNumericData.kDouble, 1.0 ) 272 | nAttr.setStorable(1) 273 | nAttr.setKeyable(1) 274 | nAttr.setHidden(0) 275 | tortilla.addAttribute( tortilla.scaleTweak) 276 | 277 | rmp_Attr = OpenMaya.MRampAttribute() 278 | tortilla.twist_rampWeight = rmp_Attr.createCurveRamp ("twist_rampWeight", "tw_rWg") 279 | tortilla.addAttribute( tortilla.twist_rampWeight) 280 | 281 | tortilla.endScale_rampWeight = rmp_Attr.createCurveRamp ("endScale_rampWeight", "enS_rWg") 282 | tortilla.addAttribute( tortilla.endScale_rampWeight) 283 | 284 | tortilla.twistTweak_rampWeight = rmp_Attr.createCurveRamp ("twistTweak_rampWeight", "ttw_rWg") 285 | tortilla.addAttribute( tortilla.twistTweak_rampWeight) 286 | 287 | tortilla.scaleTweak_rampWeight = rmp_Attr.createCurveRamp ("scaleTweak_rampWeight", "stw_rWg") 288 | tortilla.addAttribute( tortilla.scaleTweak_rampWeight) 289 | 290 | 291 | #---------------------------------------------------------------------------- Output Attributes 292 | defaultAngle = OpenMaya.MAngle ( 0.0, OpenMaya.MAngle.kDegrees ) 293 | defaultDist = OpenMaya.MDistance ( 0.0, OpenMaya.MDistance.kCentimeters ) 294 | 295 | tortilla.outRotateX = unitAttr.create( "outRotateX", "orx", defaultAngle) 296 | tortilla.outRotateY = unitAttr.create( "outRotateY", "ory", defaultAngle) 297 | tortilla.outRotateZ = unitAttr.create( "outRotateZ", "orz", defaultAngle) 298 | tortilla.outRotate = nAttr.create( "outRotate", "oRot",tortilla.outRotateX,tortilla.outRotateY,tortilla.outRotateZ) 299 | 300 | tortilla.outTranslateX = unitAttr.create( "outTranslateX", "otx", defaultDist) 301 | tortilla.outTranslateY = unitAttr.create( "outTranslateY", "oty", defaultDist) 302 | tortilla.outTranslateZ = unitAttr.create( "outTranslateZ", "otz", defaultDist) 303 | tortilla.outTranslate = nAttr.create( "outTranslate", "oTrn",tortilla.outTranslateX,tortilla.outTranslateY,tortilla.outTranslateZ) 304 | 305 | tortilla.outScale = nAttr.create( "outScale", "outS", OpenMaya.MFnNumericData.k3Double,1.0 ) 306 | 307 | tortilla.output = cAttr.create( "output", "out" ) 308 | cAttr.addChild(tortilla.outRotate) 309 | cAttr.addChild( tortilla.outScale) 310 | 311 | cAttr.setArray(1) 312 | cAttr.setStorable(1) 313 | cAttr.setKeyable(0) 314 | cAttr.setHidden(True) 315 | cAttr.setUsesArrayDataBuilder(1) 316 | tortilla.addAttribute(tortilla.output) 317 | 318 | tortilla.attributeAffects( tortilla.startTwist , tortilla.output) 319 | tortilla.attributeAffects( tortilla.endTwist , tortilla.output) 320 | tortilla.attributeAffects( tortilla.uParameters , tortilla.output) 321 | tortilla.attributeAffects( tortilla.startScale , tortilla.output) 322 | tortilla.attributeAffects( tortilla.endScale , tortilla.output) 323 | 324 | tortilla.attributeAffects( tortilla.twist_rampWeight , tortilla.output) 325 | tortilla.attributeAffects( tortilla.scaleTweak , tortilla.output) 326 | tortilla.attributeAffects( tortilla.twistTweak , tortilla.output) 327 | tortilla.attributeAffects( tortilla.twistTweak_rampWeight, tortilla.output) 328 | tortilla.attributeAffects( tortilla.scaleTweak_rampWeight, tortilla.output) 329 | tortilla.attributeAffects( tortilla.endScale_rampWeight, tortilla.output) 330 | 331 | # TWIST array for spline deformer 332 | tortilla.twistArray = typed_Attr.create( "twistArray", "twL", OpenMaya.MFnData.kDoubleArray) 333 | typed_Attr.setStorable(1) 334 | typed_Attr.setHidden(1) 335 | tortilla.addAttribute(tortilla.twistArray) 336 | 337 | tortilla.attributeAffects( tortilla.startTwist , tortilla.twistArray) 338 | tortilla.attributeAffects( tortilla.endTwist , tortilla.twistArray) 339 | tortilla.attributeAffects( tortilla.uParameters , tortilla.twistArray) 340 | 341 | tortilla.attributeAffects( tortilla.twist_rampWeight , tortilla.twistArray) 342 | tortilla.attributeAffects( tortilla.twistTweak , tortilla.twistArray) 343 | tortilla.attributeAffects( tortilla.twistTweak_rampWeight, tortilla.twistArray) 344 | 345 | def initializePlugin(mobject): 346 | mplugin = OpenMayaMPx.MFnPlugin(mobject, __author, __plug_in__Version, "Any") 347 | try: 348 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 349 | except: 350 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 351 | def uninitializePlugin(mobject): 352 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 353 | try: 354 | mplugin.deregisterNode( kPluginNodeId ) 355 | except: 356 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise -------------------------------------------------------------------------------- /maya/plug-ins/brownie.py: -------------------------------------------------------------------------------- 1 | import math, sys 2 | import maya.OpenMaya as OpenMaya 3 | import maya.OpenMayaMPx as OpenMayaMPx 4 | import maya.OpenMayaAnim as OpenMayaAnim 5 | 6 | kPluginNodeName = "brownie" 7 | kPluginNodeId = OpenMaya.MTypeId(0x531AB36) 8 | kPluginAuthor = "Bazillou2011" 9 | kPluginVersion = "0.37" 10 | nurbIntersect = OpenMaya.MNurbsIntersector() 11 | 12 | surfMFn = OpenMaya.MFnNurbsSurface() 13 | curveFn = OpenMaya.MFnNurbsCurve() 14 | pointList = OpenMaya.MPointArray() 15 | tempPnt = OpenMaya.MPoint() 16 | 17 | 18 | outMeshFn = OpenMaya.MFnMesh() 19 | meshDataFn = OpenMaya.MFnMeshData() 20 | 21 | 22 | class brownie(OpenMayaMPx.MPxNode): 23 | def __init__(self): 24 | OpenMayaMPx.MPxNode.__init__(self) 25 | def check_curve_surface_plugs(self,argList): 26 | actionData = argList[0] 27 | inputNurbsConnected = False 28 | 29 | if actionData.isNull() == False : 30 | inputNurbsConnected = True 31 | return inputNurbsConnected 32 | def getPatchInfos(self,surfMFn): 33 | uCv = surfMFn.numCVsInU() 34 | vCv = surfMFn.numCVsInV() 35 | 36 | formInU_val = surfMFn.formInU() 37 | formInV_val = surfMFn.formInV() 38 | 39 | degreeU_val = surfMFn.degreeU() 40 | degreeV_val = surfMFn.degreeV() 41 | 42 | path_knotsU = OpenMaya.MDoubleArray() 43 | path_knotsV = OpenMaya.MDoubleArray() 44 | 45 | 46 | surfMFn.getKnotsInU( path_knotsU ) 47 | surfMFn.getKnotsInV( path_knotsV ) 48 | 49 | startUParam = OpenMaya.MScriptUtil() 50 | startUParam.createFromDouble(0.0) 51 | startUPtr = startUParam.asDoublePtr() 52 | 53 | endUParam = OpenMaya.MScriptUtil() 54 | endUParam.createFromDouble(0.0) 55 | endUPtr = endUParam.asDoublePtr() 56 | 57 | startVParam = OpenMaya.MScriptUtil() 58 | startVParam.createFromDouble(0.0) 59 | startVPtr = startVParam.asDoublePtr() 60 | 61 | endVParam = OpenMaya.MScriptUtil() 62 | endVParam.createFromDouble(0.0) 63 | endVPtr = endVParam.asDoublePtr() 64 | 65 | 66 | surfMFn.getKnotDomain( startUPtr, endUPtr, startVPtr, endVPtr ) 67 | 68 | startU = OpenMaya.MScriptUtil(startUPtr).asDouble() 69 | endU = OpenMaya.MScriptUtil(endUPtr).asDouble() 70 | startV = OpenMaya.MScriptUtil(startVPtr).asDouble() 71 | endV = OpenMaya.MScriptUtil(endVPtr).asDouble() 72 | 73 | return [ uCv ,vCv ,degreeU_val ,degreeV_val,formInU_val ,formInV_val,path_knotsU ,path_knotsV,startU,endU , startV, endV ] 74 | def compute(self,Plug,Data): 75 | if Plug == self.outLattice : 76 | InputData = Data.inputValue(self.input ).asNurbsSurface() 77 | InputShapeConnected = self.check_curve_surface_plugs([InputData]) 78 | 79 | if InputShapeConnected == False: 80 | return 81 | else: 82 | self.compute_outLattice( Data,InputData) 83 | if Plug == self.outCage : 84 | self.compute_outCage( Data ) 85 | if Plug == self.outMesh : 86 | self.compute_outMesh( Data) 87 | if Plug == self.outTube : 88 | self.compute_outTube( Data) 89 | def compute_outTube(self,Data): 90 | splineMatrixData = self.composeSplineMatrix( Data) 91 | radius_Val = Data.inputValue( self.radius).asDouble() 92 | 93 | if splineMatrixData == None: 94 | return 95 | else: 96 | radius_Val = Data.inputValue( self.radius).asDouble() 97 | knotCount = 8 98 | 99 | offsetPoint = OpenMaya.MPoint(0,radius_Val,0,1) 100 | offsetArray = OpenMaya.MPointArray(knotCount+1) 101 | u_len = splineMatrixData.length() 102 | 103 | indexTable = [[5,4,3], 104 | [6,8,2], 105 | [7,0,1]] 106 | 107 | 108 | shiftVal = OpenMaya.MEulerRotation(0,0,0, 0) 109 | shftRatio = 360.0/(knotCount*1.0) 110 | 111 | locSpace = OpenMaya.MSpace.kObject 112 | 113 | 114 | for j in range(knotCount): 115 | shiftVal.x = math.radians(j*shftRatio) 116 | offsetArray.set(offsetPoint*shiftVal.asMatrix(),j) 117 | 118 | 119 | newMeshObj = meshDataFn.create() 120 | resultPoint = OpenMaya.MPoint() 121 | 122 | VtxPos = OpenMaya.MPointArray(knotCount*u_len ) 123 | 124 | polygonCounts = OpenMaya.MIntArray(knotCount*(u_len-1) ,4) 125 | polygonConnects = OpenMaya.MIntArray() 126 | 127 | indexTableB = [1,2,3,4,5,6,7,0 ] 128 | for i in range(u_len-1): 129 | for j in range(knotCount): 130 | vertID_A = j+(i*knotCount) 131 | vertID_B = j+((i+1)*knotCount) 132 | vertID_C = indexTableB[j]+((i+1)*knotCount) 133 | vertID_D = indexTableB[j] +(i*knotCount) 134 | 135 | polygonConnects.append(vertID_A) 136 | polygonConnects.append(vertID_D) 137 | polygonConnects.append(vertID_C) 138 | polygonConnects.append(vertID_B) 139 | 140 | 141 | knotOffset_obj = Data.inputValue( self.knotOffset).data() 142 | knotChk = False 143 | knotOffsetList = None 144 | 145 | if knotOffset_obj.isNull() == False: 146 | knotOffsetFn = OpenMaya.MFnVectorArrayData(knotOffset_obj) 147 | knotOffsetList = knotOffsetFn.array() 148 | 149 | if knotOffsetList.length() > 0 : 150 | knotChk = True 151 | 152 | if knotChk == False: 153 | for i in range(u_len): 154 | for j in range(knotCount): 155 | VtxPos.set(offsetArray[j] * splineMatrixData[i] ,j+(i*knotCount)) 156 | else: 157 | tmpPnt = OpenMaya.MPoint() 158 | for i in range(u_len): 159 | for j in range(knotCount): 160 | VtxPos.set((tmpPnt +knotOffsetList[j+(i*knotCount)] ) * splineMatrixData[i] ,j+(i*knotCount)) 161 | 162 | 163 | outMeshFn.create (VtxPos.length(), polygonCounts.length(), VtxPos, polygonCounts, polygonConnects, newMeshObj) 164 | outHandle = Data.outputValue( self.outTube) 165 | outHandle.setMObject(newMeshObj) 166 | outHandle.setClean() 167 | def composeSplineMatrix(self,Data): 168 | splineMatrix_obj = Data.inputValue( self.splineMatrix).data() 169 | if splineMatrix_obj.isNull() == True: 170 | return None 171 | else: 172 | splineMatrixFn = OpenMaya.MFnVectorArrayData(splineMatrix_obj) 173 | vecList = splineMatrixFn.array() 174 | 175 | vec_len = vecList.length()/4 176 | 177 | 178 | if vec_len < 1 : 179 | return None 180 | else: 181 | targLen = int(vecList[0].x) 182 | sliceMatList = OpenMaya.MMatrixArray(targLen) 183 | 184 | for i in range(targLen): 185 | matrixValueList = [ vecList[1+i*4+0].x, vecList[1+i*4+0].y, vecList[1+i*4+0].z, 0.0, 186 | vecList[1+i*4+1].x, vecList[1+i*4+1].y, vecList[1+i*4+1].z, 0.0, 187 | vecList[1+i*4+2].x, vecList[1+i*4+2].y, vecList[1+i*4+2].z, 0.0, 188 | vecList[1+i*4+3].x, vecList[1+i*4+3].y, vecList[1+i*4+3].z,1.0] 189 | 190 | rotMatrix = OpenMaya.MMatrix() 191 | utilB = OpenMaya.MScriptUtil() 192 | utilB.createMatrixFromList( matrixValueList, rotMatrix ) 193 | 194 | sliceMatList.set(rotMatrix,i) 195 | return sliceMatList 196 | def compute_outMesh(self,Data): 197 | splineMatrixData = self.composeSplineMatrix( Data) 198 | radius_Val = Data.inputValue( self.radius).asDouble() 199 | 200 | if splineMatrixData == None: 201 | return 202 | else: 203 | radius_Val = Data.inputValue( self.radius).asDouble() 204 | knotCount = 8 205 | 206 | offsetPoint = OpenMaya.MPoint(0,radius_Val,0,1) 207 | offsetArray = OpenMaya.MPointArray(knotCount+1) 208 | u_len = splineMatrixData.length() 209 | 210 | indexTable = [[5,4,3], 211 | [6,8,2], 212 | [7,0,1]] 213 | 214 | 215 | shiftVal = OpenMaya.MEulerRotation(0,0,0, 0) 216 | shftRatio = 360.0/(knotCount*1.0) 217 | sidenum = int(math.sqrt(knotCount+1)) 218 | locSpace = OpenMaya.MSpace.kObject 219 | 220 | 221 | for j in range(knotCount): 222 | shiftVal.x = math.radians(j*shftRatio) 223 | offsetArray.set(offsetPoint*shiftVal.asMatrix(),j) 224 | 225 | newMeshObj = meshDataFn.create() 226 | resultPoint = OpenMaya.MPoint() 227 | 228 | VtxPos = OpenMaya.MPointArray(knotCount*u_len+2) 229 | 230 | polygonCounts = OpenMaya.MIntArray(knotCount*(u_len-1)+8,4) 231 | polygonConnects = OpenMaya.MIntArray() 232 | 233 | indexTableB = [1,2,3,4,5,6,7,0 ] 234 | for i in range(u_len-1): 235 | for j in range(knotCount): 236 | vertID_A = j+(i*knotCount) 237 | vertID_B = j+((i+1)*knotCount) 238 | vertID_C = indexTableB[j]+((i+1)*knotCount) 239 | vertID_D = indexTableB[j] +(i*knotCount) 240 | 241 | polygonConnects.append(vertID_A) 242 | polygonConnects.append(vertID_D) 243 | polygonConnects.append(vertID_C) 244 | polygonConnects.append(vertID_B) 245 | 246 | 247 | capA = knotCount*u_len 248 | VtxPos.set(resultPoint*splineMatrixData[0] ,capA) 249 | 250 | capB = knotCount*u_len+1 251 | VtxPos.set(resultPoint*splineMatrixData[u_len-1] ,capB) 252 | 253 | for i in range(u_len): 254 | for j in range(knotCount): 255 | VtxPos.set(offsetArray[j] * splineMatrixData[i] ,j+(i*knotCount)) 256 | 257 | 258 | capList = [0,capA,2,1,7,6,capA,0,6,5,4,capA,capA,4,3,2 ] 259 | for j in range(len(capList)): 260 | polygonConnects.append(capList[j]) 261 | 262 | lastRow = [] 263 | for j in range(knotCount): 264 | lastRow.append(j+((u_len-1)*knotCount)) 265 | 266 | capListB = [lastRow[0],lastRow[1],lastRow[2],capB, 267 | lastRow[7],lastRow[0],capB,lastRow[6], 268 | lastRow[6],capB,lastRow[4],lastRow[5], 269 | capB,lastRow[2],lastRow[3],lastRow[4] ] 270 | 271 | for j in range(len(capListB)): 272 | polygonConnects.append(capListB[j] ) 273 | 274 | 275 | outMeshFn.create (VtxPos.length(), polygonCounts.length(), VtxPos, polygonCounts, polygonConnects, newMeshObj) 276 | outHandle = Data.outputValue( self.outMesh) 277 | outHandle.setMObject(newMeshObj) 278 | outHandle.setClean() 279 | def compute_outCage(self,Data): 280 | splineMatrixData = self.composeSplineMatrix( Data) 281 | radius_Val = Data.inputValue( self.radius).asDouble() 282 | 283 | if splineMatrixData == None: 284 | return 285 | else: 286 | knotCount = 8 287 | 288 | offsetPoint = OpenMaya.MPoint(0,radius_Val,0,1) 289 | offsetArray = OpenMaya.MPointArray(knotCount+1) 290 | 291 | indexTable = [[5,4,3], 292 | [6,8,2], 293 | [7,0,1]] 294 | 295 | shiftVal = OpenMaya.MEulerRotation(0,0,0, 0) 296 | shftRatio = 360.0/(knotCount*1.0) 297 | sidenum = int(math.sqrt(knotCount+1)) 298 | 299 | 300 | for j in range(knotCount): 301 | shiftVal.x = math.radians(j*shftRatio) 302 | offsetArray.set(offsetPoint*shiftVal.asMatrix(),j) 303 | 304 | outCage_Hndle = Data.outputValue(self.outCage ) 305 | latDat = OpenMaya.MFnLatticeData () 306 | latObj = latDat.create() 307 | lafFn = OpenMayaAnim.MFnLattice() 308 | 309 | 310 | divX = splineMatrixData.length() 311 | divY = sidenum 312 | divZ = sidenum 313 | 314 | 315 | lafFn.create( divX,divY,divZ,latObj) 316 | 317 | knotOffset_obj = Data.inputValue( self.knotOffset).data() 318 | knotChk = False 319 | knotOffsetList = None 320 | 321 | if knotOffset_obj.isNull() == False: 322 | knotOffsetFn = OpenMaya.MFnVectorArrayData(knotOffset_obj) 323 | knotOffsetList = knotOffsetFn.array() 324 | 325 | if knotOffsetList.length() > 0 : 326 | knotChk = True 327 | 328 | if knotChk == False: 329 | for i in range(divX): 330 | for j in range(divY): 331 | for k in range(divZ): 332 | outPoint = lafFn.point( i, j, k ) 333 | outPointB = offsetArray[ indexTable[j][k] ] * splineMatrixData[i] 334 | 335 | outPoint.x = outPointB.x 336 | outPoint.y = outPointB.y 337 | outPoint.z = outPointB.z 338 | else: 339 | idx = 0 340 | outPointB = OpenMaya.MPoint() 341 | tmpPnt = OpenMaya.MPoint() 342 | for i in range(divX): 343 | for j in range(divY): 344 | for k in range(divZ): 345 | outPoint = lafFn.point( i, j, k ) 346 | idx = indexTable[j][k] 347 | if idx != 8 : 348 | outPointB = (tmpPnt +knotOffsetList[idx+(i*knotCount)]) * splineMatrixData[i] 349 | else : 350 | outPointB = offsetArray[ 8 ] * splineMatrixData[i] 351 | outPoint.x = outPointB.x 352 | outPoint.y = outPointB.y 353 | outPoint.z = outPointB.z 354 | outCage_Hndle.setMObject(latObj) 355 | outCage_Hndle.setClean() 356 | def compute_matrix_from_2_vectors_and_u_Point(self,trX_Mat,trY_Mat,u_Point): 357 | trZ_Mat = (trX_Mat^trY_Mat).normal(); 358 | 359 | matrixValueList = [ trX_Mat.x, trX_Mat.y, trX_Mat.z, 0.0, 360 | trY_Mat.x, trY_Mat.y, trY_Mat.z, 0.0, 361 | trZ_Mat.x, trZ_Mat.y, trZ_Mat.z, 0.0, 362 | u_Point.x,u_Point.y,u_Point.z,u_Point.w ] 363 | 364 | rotMatrix = OpenMaya.MMatrix() 365 | utilB = OpenMaya.MScriptUtil() 366 | utilB.createMatrixFromList( matrixValueList, rotMatrix ) 367 | 368 | return rotMatrix.homogenize() 369 | def compute_outLattice(self,Data,InputData): 370 | widthA_Val = Data.inputValue( self.widthA).asDouble() 371 | widthB_Val = Data.inputValue( self.widthB).asDouble() 372 | uDensity_Val = Data.inputValue( self.uDensity).asShort() 373 | vDensity_Val = Data.inputValue( self.vDensity).asShort() 374 | 375 | surfMFn.setObject(InputData ) 376 | surfData = self.getPatchInfos(surfMFn) 377 | surfMFn.getCVs (pointList,OpenMaya.MSpace.kObject) 378 | uCv = surfData[0] 379 | vCv = surfData[1] 380 | path_knotsU = surfData[6] 381 | path_knotsV = surfData[7] 382 | startU = surfData[8] 383 | endU = surfData[9] 384 | startV = surfData[10] 385 | endV = surfData[11] 386 | 387 | uRatio = (endU-startU)/(uCv*uDensity_Val*1.0) 388 | vRatio = (endV-startV)/(vCv*vDensity_Val*1.0) 389 | uRange = [] 390 | vRange = [] 391 | for k in xrange(uCv*uDensity_Val+1): 392 | uRange.append(k*uRatio) 393 | for k in xrange(vCv*vDensity_Val+1): 394 | vRange.append(k*vRatio) 395 | 396 | widthData = [widthA_Val,widthB_Val] 397 | 398 | mat = OpenMaya.MMatrix() 399 | nurbIntersect.create(InputData, mat) 400 | ptON = OpenMaya.MPointOnNurbs() 401 | 402 | outLattice_Hndle = Data.outputValue(self.outLattice ) 403 | latDat = OpenMaya.MFnLatticeData () 404 | latObj = latDat.create() 405 | lafFn = OpenMayaAnim.MFnLattice() 406 | 407 | 408 | divX = len(uRange) 409 | divY = len(vRange) 410 | divZ = 2 411 | 412 | lafFn.create( divX,divY,divZ,latObj) 413 | resultPoint = OpenMaya.MPoint() 414 | vecList = [widthData[0]*-0.01,widthData[1]*0.01] 415 | 416 | for i in range(divX): 417 | for j in range(divY): 418 | surfMFn.getPointAtParam (uRange[i],vRange[j],resultPoint,OpenMaya.MSpace.kObject ) 419 | outV = surfMFn.normal(uRange[i],vRange[j],OpenMaya.MSpace.kObject).normal() 420 | 421 | for k in range(divZ): 422 | outPoint = lafFn.point( i, j, k ) 423 | outPointB = resultPoint+(outV*vecList[k]) 424 | 425 | outPoint.x = outPointB.x 426 | outPoint.y = outPointB.y 427 | outPoint.z = outPointB.z 428 | 429 | outLattice_Hndle.setMObject(latObj) 430 | outLattice_Hndle.setClean() 431 | def nodeCreator(): 432 | return OpenMayaMPx.asMPxPtr(brownie()) 433 | def nodeInitializer(): 434 | typed_Attr = OpenMaya.MFnTypedAttribute() 435 | mAttr = OpenMaya.MFnNumericAttribute() 436 | nAttr = OpenMaya.MFnNumericAttribute() 437 | 438 | 439 | 440 | brownie.input = typed_Attr.create( "input", "in", OpenMaya.MFnNurbsCurveData.kNurbsSurface ) 441 | typed_Attr.setStorable(0) 442 | typed_Attr.setKeyable(0) 443 | typed_Attr.setHidden(True) 444 | brownie.addAttribute( brownie.input ) 445 | 446 | brownie.widthA = mAttr.create("widthA","wA", OpenMaya.MFnNumericData.kDouble,1.0) 447 | mAttr.setStorable(1) 448 | mAttr.setKeyable(1) 449 | mAttr.setHidden(0) 450 | brownie.addAttribute( brownie.widthA) 451 | 452 | brownie.widthB = mAttr.create("widthB","wB", OpenMaya.MFnNumericData.kDouble,1.0) 453 | mAttr.setStorable(1) 454 | mAttr.setKeyable(1) 455 | mAttr.setHidden(0) 456 | brownie.addAttribute( brownie.widthB) 457 | 458 | brownie.uDensity = mAttr.create("uDensity","uD", OpenMaya.MFnNumericData.kShort,1) 459 | mAttr.setStorable(1) 460 | mAttr.setKeyable(1) 461 | mAttr.setHidden(0) 462 | mAttr.setMin(1) 463 | mAttr.setSoftMax(5) 464 | brownie.addAttribute( brownie.uDensity) 465 | 466 | brownie.vDensity = mAttr.create("vDensity","vD", OpenMaya.MFnNumericData.kShort,1) 467 | mAttr.setStorable(1) 468 | mAttr.setKeyable(1) 469 | mAttr.setHidden(0) 470 | mAttr.setMin(1) 471 | mAttr.setSoftMax(5) 472 | brownie.addAttribute( brownie.vDensity) 473 | 474 | brownie.outLattice = typed_Attr.create("outLattice", "upLat", OpenMaya.MFnData.kLattice) 475 | typed_Attr.setHidden(1) 476 | brownie.addAttribute(brownie.outLattice) 477 | 478 | 479 | brownie.attributeAffects( brownie.input , brownie.outLattice ) 480 | brownie.attributeAffects( brownie.widthA , brownie.outLattice ) 481 | brownie.attributeAffects( brownie.widthB , brownie.outLattice ) 482 | brownie.attributeAffects( brownie.uDensity , brownie.outLattice ) 483 | brownie.attributeAffects( brownie.vDensity , brownie.outLattice ) 484 | 485 | brownie.splineMatrix = typed_Attr.create( "splineMatrix", "sMat", OpenMaya.MFnData.kVectorArray) #1 matrix is decompose into 4 vector.... 486 | typed_Attr.setStorable(0) 487 | typed_Attr.setKeyable(0) 488 | typed_Attr.setHidden(1) 489 | brownie.addAttribute(brownie.splineMatrix) 490 | 491 | 492 | brownie.radius = mAttr.create("radius","rds", OpenMaya.MFnNumericData.kDouble,1.0) 493 | mAttr.setStorable(1) 494 | mAttr.setKeyable(1) 495 | mAttr.setHidden(0) 496 | brownie.addAttribute( brownie.radius) 497 | 498 | brownie.outCage = typed_Attr.create("outCage", "oCg", OpenMaya.MFnData.kLattice) 499 | typed_Attr.setHidden(1) 500 | brownie.addAttribute(brownie.outCage) 501 | 502 | 503 | 504 | brownie.attributeAffects( brownie.splineMatrix , brownie.outCage ) 505 | brownie.attributeAffects( brownie.radius , brownie.outCage ) 506 | 507 | 508 | brownie.outMesh = typed_Attr.create( "outMesh", "oMsh", OpenMaya.MFnMeshData.kMesh) 509 | typed_Attr.setHidden(1) 510 | brownie.addAttribute( brownie.outMesh ) 511 | 512 | 513 | brownie.attributeAffects( brownie.splineMatrix , brownie.outMesh ) 514 | brownie.attributeAffects( brownie.radius , brownie.outMesh ) 515 | 516 | 517 | brownie.knotOffset = typed_Attr.create( "knotOffset", "kOff", OpenMaya.MFnData.kVectorArray) 518 | typed_Attr.setHidden(1) 519 | brownie.addAttribute( brownie.knotOffset ) 520 | 521 | brownie.outTube = typed_Attr.create( "outTube", "oTbe", OpenMaya.MFnMeshData.kMesh) 522 | typed_Attr.setHidden(1) 523 | brownie.addAttribute( brownie.outTube ) 524 | 525 | 526 | brownie.attributeAffects( brownie.splineMatrix , brownie.outTube ) 527 | brownie.attributeAffects( brownie.radius , brownie.outTube ) 528 | brownie.attributeAffects( brownie.knotOffset , brownie.outTube ) 529 | 530 | 531 | 532 | return 533 | def initializePlugin(mobject): 534 | mplugin = OpenMayaMPx.MFnPlugin(mobject, kPluginAuthor, kPluginVersion, "Any") 535 | try: 536 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode) 537 | except: 538 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ); raise 539 | def uninitializePlugin(mobject): 540 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 541 | try: 542 | mplugin.deregisterNode( kPluginNodeId ) 543 | except: 544 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ); raise 545 | -------------------------------------------------------------------------------- /maya/rig/dish/builder.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | import maya.cmds as mc 3 | import maya.OpenMaya as OpenMaya 4 | import inspect 5 | import zipfile 6 | from functools import partial 7 | import json 8 | import uuid 9 | import datetime 10 | 11 | if 'dish.data' not in sys.modules.keys(): 12 | frme = inspect.currentframe() 13 | frameData = inspect.getframeinfo(frme) 14 | modulePath = os.path.dirname(frameData[0]) 15 | modulePath = os.path.dirname(modulePath) 16 | sys.path.append(modulePath) 17 | 18 | if 'attrToFilter' not in sys.modules.keys(): 19 | import dish.data as attrToFilter 20 | reload(attrToFilter) 21 | 22 | if 'dishCore' not in sys.modules.keys(): 23 | import dish.core as dishCore 24 | reload(dishCore) 25 | 26 | 27 | author = 'cedric bazillou 2013' 28 | version = 0.01 29 | 30 | 31 | 32 | class UI: 33 | def __init__(self): 34 | self.outputScroll = '' 35 | self.outputAttributes = '' 36 | self.outputFld = '' 37 | self.scrollInfo = '' 38 | self.assetListing = '' 39 | self.bentoRoot = '' 40 | self.tabCtrl_A = '' 41 | self.tabCtrl_B = '' 42 | self.driverFld = '' 43 | self.driverScroll = '' 44 | self.DriverAttributes = '' 45 | self.canvasSize =[430,400] 46 | self.bundle_prgrss = '' 47 | self.bentoElements = 'CCW_TOOLS_bentoElem' 48 | self.foodField = '' 49 | self.IO = dishCore.IO() 50 | self.factory = dishCore.factory() 51 | self.defaultNodes = attrToFilter.defaultNodes 52 | excludeAttr = attrToFilter.excludeAttr 53 | 54 | filter = attrToFilter.unExposeAttr 55 | excludeAttr.extend(filter) 56 | excludeAttr.extend(attrToFilter.crveExclude) 57 | excludeAttr.extend(attrToFilter.meshExclude) 58 | excludeAttr.extend(attrToFilter.latExclude) 59 | excludeAttr.extend(attrToFilter.surfceExclude) 60 | 61 | self.exludedAttributes = excludeAttr 62 | 63 | #---------------------------------------------------------------------------------------- widget Helpers 64 | def resizeBuildTabs(self): 65 | tabIndex = mc.tabLayout(self.tabCtrl_A ,q=True,sti=True ) 66 | if tabIndex == 1 : 67 | mc.tabLayout(self.tabCtrl_A,e=True, h=620 ) 68 | if tabIndex == 2 : 69 | mc.tabLayout(self.tabCtrl_A,e=True, h=80 ) 70 | #---------------------------------------------------------------------------------------- MAIN UI 71 | def widget(self,widgetParent ): 72 | wd = mc.columnLayout(widgetParent,q=True,w=True) 73 | mc.columnLayout( adjustableColumn=True,p=widgetParent,w=wd ) 74 | mc.separator() 75 | 76 | mc.rowLayout( numberOfColumns=3, 77 | columnWidth2=(80,(self.canvasSize[0]-80-20)), 78 | adjustableColumn=2,cl2=('left','both' ) ) 79 | mc.text(l=' Current Path :') 80 | pathTxFld = mc.textField( 'buildDish_UI_data_dir_txFld',ed=False ) 81 | self.tabCtrl_A = mc.tabLayout( innerMarginWidth=5, innerMarginHeight=5,p=widgetParent ) 82 | 83 | #--------------------------------------------------------------------------------- 84 | self.cookTab() 85 | #--------------------------------------------------------------------------------- 86 | self.deliverTab() 87 | 88 | modulePath = ''.join(os.path.dirname(inspect.getfile(self.resizeBuildTabs))+'\src') 89 | mc.textField( pathTxFld,e=True,tx=modulePath) 90 | mc.tabLayout(self.tabCtrl_A ,e=True,tabLabelIndex=[1,'Cook']) 91 | mc.tabLayout(self.tabCtrl_A ,e=True,tabLabelIndex=[2,'Deliver']) 92 | mc.tabLayout(self.tabCtrl_A ,e=True,cc=self.resizeBuildTabs ) 93 | #---------------------------------------------------------------------------------------- cookTab UI sub Elements 94 | def flagRoot_UI(self): 95 | mc.rowLayout( numberOfColumns=3, columnWidth3=(80,(self.canvasSize[0]-80-20),20 ), adjustableColumn=2,cl3=('left','both','right')) 96 | mc.text(l='1. Bento root :') 97 | self.bentoRoot = mc.textField( 'CCW_TOOLS_ROOT_data_dir_txFld' ) 98 | psdFileRootBtn = mc.button(l='<' ,c=partial(self.collect_root, self.bentoRoot ) ) 99 | mc.setParent('..') 100 | 101 | mc.text(l='2. FoodType') 102 | self.foodField = mc.textField( 'CCW_TOOLS_FoodType_txFld',alwaysInvokeEnterCommandOnReturn=True ) 103 | mc.textField( self.foodField,e=True, enterCommand=partial(self.validateModule, self.foodField ) ) 104 | mc.separator() 105 | mc.text(l='3. Description') 106 | self.scrollInfo = mc.scrollField( editable=True, wordWrap=True, text='#Any relevant informations can be placed here' ) 107 | mc.button(l='Flag bento root',c=self.validateRootData) 108 | mc.separator() 109 | def injectElement_UI(self ): 110 | slot = mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='etchedIn',mw=5,mh=5 ,p=self.tabCtrl_B) 111 | anchorDock = mc.rowLayout( numberOfColumns=2, 112 | columnWidth2=(self.canvasSize[0]/5*2-30, self.canvasSize[0]/5*2-20 ), 113 | adjustableColumn=1, 114 | columnAlign=(1, 'right'), 115 | columnAttach=[(1,'both',0), (2,'both',0)] ,w=self.canvasSize[0]-40) 116 | mc.columnLayout( adjustableColumn=True ) 117 | mc.button(l='4-a. Scan current scene content',c=self.scanSceneGraph) 118 | 119 | mc.columnLayout( adjustableColumn=True,p=anchorDock ) 120 | mc.button(l='4-b. Remove selected' ,c=self.removeNodeFromElementList) 121 | 122 | mc.setParent(slot) 123 | self.assetListing = mc.textScrollList( 'CCW_TOOLS_bentoElem',numberOfRows=10, allowMultiSelection=True ) 124 | mc.button(l='4-c. Inject Elements',h=36 ,c=self.validateDishData) 125 | #------------------------------------------------------------------------------------- 126 | def defineDriver_UI(self ): 127 | mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='etchedIn',mw=5,mh=5 ,p=self.tabCtrl_B) 128 | defineDriver_form = mc.formLayout(numberOfDivisions=2) 129 | 130 | #--------------------------------------------------------------------------------------- 131 | rowA = self.editDriverTab( defineDriver_form ) 132 | rowB = self.manageDriverTab( defineDriver_form ) 133 | 134 | mc.formLayout(defineDriver_form,e=True,attachForm=[ 135 | (rowA, 'top', 1),(rowA, 'bottom', 1),(rowA, 'left', 1), 136 | (rowB, 'top', 1),(rowB, 'bottom', 1),(rowB, 'right', 1) ], 137 | attachControl=[(rowB, 'left', 5, rowA)]) 138 | def editDriverTab(self,anchor ): 139 | driverRow = mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='etchedIn', 140 | mh=5,mw=5 ,w=self.canvasSize[0]/2-30,p=anchor ) 141 | mc.text(l=' 5-a. Driver Node :') 142 | mc.rowLayout( numberOfColumns=2, adjustableColumn=1,cl2=('left','both' ) ) 143 | self.driverFld = mc.textField( 'CCW_TOOLS_DRVER_txFld' ) 144 | psdFileRootBtn = mc.button(l='<' ,w=20,h=20,c=self.collect_driver_data ) 145 | mc.setParent('..') 146 | 147 | self.DriverAttributes = mc.textScrollList( 'CCW_TOOLS_DriverAttributes',numberOfRows=8, allowMultiSelection=True) 148 | 149 | mc.setParent( driverRow ) 150 | mc.separator() 151 | mc.button(l='5-b. Expose selection' , h=32,c=self.validate_driverData) 152 | 153 | return driverRow 154 | #------------------------------------------------------------------------------------- 155 | def defineOutput_UI(self ): 156 | mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='etchedIn',mw=5,mh=5 ,p=self.tabCtrl_B) 157 | defineDriver_form = mc.formLayout(numberOfDivisions=2) 158 | 159 | #--------------------------------------------------------------------------------------- 160 | rowA = self.editOutput_UI( defineDriver_form ) 161 | rowB = self.manageOutputTab( defineDriver_form ) 162 | 163 | mc.formLayout(defineDriver_form,e=True,attachForm=[ 164 | (rowA, 'top', 1),(rowA, 'bottom', 1),(rowA, 'left', 1), 165 | (rowB, 'top', 1),(rowB, 'bottom', 1),(rowB, 'right', 1) ], 166 | attachControl=[(rowB, 'left', 5, rowA)]) 167 | def editOutput_UI(self,anchor ): 168 | driverRow = mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='etchedIn', 169 | mh=5,mw=5 ,w=self.canvasSize[0]/2-30,p=anchor ) 170 | mc.text(l=' 6-a. Output Node :') 171 | mc.rowLayout( numberOfColumns=2, adjustableColumn=1,cl2=('left','both' ) ) 172 | self.outputFld = mc.textField( 'CCW_TOOLS_output_txFld' ) 173 | psdFileRootBtn = mc.button(l='<' ,w=20,h=20 ,c=self.collect_output_data ) 174 | mc.setParent('..') 175 | 176 | self.outputAttributes = mc.textScrollList( 'CCW_TOOLS_outputAttributes',numberOfRows=8, allowMultiSelection=True) 177 | 178 | mc.setParent( driverRow ) 179 | mc.separator() 180 | mc.button(l='6-b. Expose selection' , h=32,c=self.validate_outputData ) 181 | 182 | return driverRow 183 | def manageOutputTab(self,anchor ): 184 | driverRow = mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='in', mh=3,mw=5 ,p=anchor ) 185 | mc.text(l='Published Output' ) 186 | self.outputScroll = mc.scrollLayout( horizontalScrollBarThickness=0,verticalScrollBarThickness=8,childResizable=True ) 187 | 188 | return driverRow 189 | #------------------------------------------------------------------------------------- 190 | def defineMisc_UI(self ): 191 | mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='etchedIn',mw=5,mh=5 ,p=self.tabCtrl_B) 192 | mc.button(l='Flag output' ,w=40) 193 | #---------------------------------------------------------------------------------------- editOutputTab UI Helpers 194 | def collect_output_data(self,*args): 195 | sel = mc.ls(sl=True,fl=True) 196 | root = mc.textField( self.outputFld ,q=True,tx=True) 197 | mc.textField( self.outputFld ,e=True,tx='') 198 | if sel is None or len(sel)<1 : 199 | return 200 | else: 201 | bentoRoot = mc.textField( self.bentoRoot,q=True,tx=True) 202 | erroChk = 0 203 | chkList = [bentoRoot ] 204 | feedBackList = ['Please pick a root object'] 205 | for index, checkObj in enumerate(chkList): 206 | if checkObj is None or len(checkObj)== 0: 207 | erroChk += 1 208 | mc.warning(feedBackList[index]) 209 | if erroChk > 0: 210 | return 211 | mc.textField( self.outputFld ,e=True,tx=sel[0]) 212 | 213 | attributeList = list( set(mc.listAttr(sel[0] ))-set(self.exludedAttributes)) 214 | print attributeList 215 | # 216 | 217 | mc.textScrollList( self.outputAttributes ,e=True,ra=True) 218 | if attributeList is not None: 219 | attributeList = sorted(attributeList) 220 | for attr in attributeList: 221 | mc.textScrollList( self.outputAttributes ,e=True,a=attr) 222 | def validate_outputData(self,*args): 223 | attr = mc.textScrollList( self.outputAttributes ,q=True,si=True) 224 | root = mc.textField( self.outputFld ,q=True,tx=True) 225 | 226 | bentoRoot = mc.textField( self.bentoRoot,q=True,tx=True) 227 | erroChk = 0 228 | chkList = [bentoRoot ] 229 | feedBackList = ['Please pick a root object'] 230 | for index, checkObj in enumerate(chkList): 231 | if checkObj is None or len(checkObj)== 0: 232 | erroChk += 1 233 | mc.warning(feedBackList[index]) 234 | if erroChk > 0: 235 | return 236 | if attr is not None and len(root)>0: 237 | self.factory.publish_IO_Connections( bentoRoot,root+'.'+attr[0],1 ) 238 | self.reset_outputUI() 239 | self.fill_outputUI( bentoRoot ) 240 | def fill_outputUI(self,root ): 241 | inputData = self.factory.retrieve_IO_Connections(root, 1) 242 | 243 | if inputData is not None: 244 | lenData = len(inputData.keys()) 245 | keyList = sorted(inputData.keys()) 246 | 247 | for k in range(lenData): 248 | writeData = inputData[keyList[k]] 249 | self.expose_output_unit(self.outputScroll,writeData,keyList[k],root) 250 | def expose_output_unit(self, anchor, writeData,index,root ): 251 | mc.frameLayout( collapsable=True,labelVisible=True, borderStyle='out' ,l='driver%s'%index ,mw=2,mh=2 ,p=anchor ) 252 | 253 | if writeData[5] == True: 254 | mc.textField(tx=writeData[0],ed=False ,font='boldLabelFont') 255 | else: 256 | mc.textField(tx=writeData[0],ed=False ) 257 | mc.separator() 258 | mc.text(l='label') 259 | lblFld = mc.textField( ed=True ) 260 | mc.connectControl( lblFld, writeData[3]) 261 | 262 | mc.text(l='widgetID') 263 | wdgFld = mc.textField( ed=True ) 264 | mc.connectControl( wdgFld, writeData[4] ) 265 | mc.separator() 266 | rmBtn = mc.button(l='remove',c=partial(self.validate_output_deletion,root , index)) 267 | def validate_output_deletion(self ,root , index, *args): 268 | self.factory.delete_Connections_at_targetIndex( root , index,1 ) 269 | self.reset_outputUI() 270 | self.fill_outputUI( root) 271 | def reset_outputUI(self): 272 | childArray = mc.scrollLayout( self.outputScroll ,q=True,childArray=True) 273 | if childArray is not None: 274 | for obj in childArray: 275 | mc.deleteUI(obj) 276 | #---------------------------------------------------------------------------------------- editDriverTab UI Helpers 277 | def collect_driver_data(self,*args): 278 | sel = mc.ls(sl=True,fl=True) 279 | root = mc.textField( self.driverFld ,q=True,tx=True) 280 | mc.textField( self.driverFld ,e=True,tx='') 281 | if sel is None or len(sel)<1 : 282 | return 283 | else: 284 | bentoRoot = mc.textField( self.bentoRoot,q=True,tx=True) 285 | erroChk = 0 286 | chkList = [bentoRoot ] 287 | feedBackList = ['Please pick a root object'] 288 | for index, checkObj in enumerate(chkList): 289 | if checkObj is None or len(checkObj)== 0: 290 | erroChk += 1 291 | mc.warning(feedBackList[index]) 292 | if erroChk > 0: 293 | return 294 | mc.textField( self.driverFld ,e=True,tx=sel[0]) 295 | 296 | attributeList = list( set(mc.listAttr(sel[0] ))-set(self.exludedAttributes)) 297 | print attributeList 298 | # 299 | 300 | mc.textScrollList( self.DriverAttributes ,e=True,ra=True) 301 | if attributeList is not None: 302 | attributeList = sorted(attributeList) 303 | for attr in attributeList: 304 | mc.textScrollList( self.DriverAttributes ,e=True,a=attr) 305 | def validate_driverData(self,*args): 306 | attr = mc.textScrollList( self.DriverAttributes ,q=True,si=True) 307 | root = mc.textField( self.driverFld ,q=True,tx=True) 308 | 309 | bentoRoot = mc.textField( self.bentoRoot,q=True,tx=True) 310 | erroChk = 0 311 | chkList = [bentoRoot ] 312 | feedBackList = ['Please pick a root object'] 313 | for index, checkObj in enumerate(chkList): 314 | if checkObj is None or len(checkObj)== 0: 315 | erroChk += 1 316 | mc.warning(feedBackList[index]) 317 | if erroChk > 0: 318 | return 319 | if attr is not None and len(root)>0: 320 | self.factory.publish_IO_Connections( bentoRoot,root+'.'+attr[0],0 ) 321 | self.reset_driverUI() 322 | self.fill_driverUI( bentoRoot ) 323 | def manageDriverTab(self,anchor ): 324 | driverRow = mc.frameLayout( collapsable=False,labelVisible=False, borderStyle='in', mh=3,mw=5 ,p=anchor ) 325 | mc.text(l='Published Drivers' ) 326 | self.driverScroll = mc.scrollLayout( horizontalScrollBarThickness=0,verticalScrollBarThickness=8,childResizable=True ) 327 | 328 | return driverRow 329 | def expose_driver_unit(self, anchor, writeData,index,root ): 330 | mc.frameLayout( collapsable=True,labelVisible=True, borderStyle='out' ,l='driver%s'%index ,mw=2,mh=2 ,p=anchor ) 331 | 332 | if writeData[5] == True: 333 | mc.textField(tx=writeData[0],ed=False ,font='boldLabelFont') 334 | else: 335 | mc.textField(tx=writeData[0],ed=False ) 336 | mc.separator() 337 | mc.text(l='label') 338 | lblFld = mc.textField( ed=True ) 339 | mc.connectControl( lblFld, writeData[3]) 340 | 341 | mc.text(l='widgetID') 342 | wdgFld = mc.textField( ed=True ) 343 | mc.connectControl( wdgFld, writeData[4] ) 344 | mc.separator() 345 | rmBtn = mc.button(l='remove',c=partial(self.validate_driver_deletion,root , index)) 346 | def reset_driverUI(self): 347 | childArray = mc.scrollLayout( self.driverScroll ,q=True,childArray=True) 348 | if childArray is not None: 349 | for obj in childArray: 350 | mc.deleteUI(obj) 351 | def fill_driverUI(self,root ): 352 | inputData = self.factory.retrieve_IO_Connections(root, 0) 353 | 354 | if inputData is not None: 355 | lenData = len(inputData.keys()) 356 | keyList = sorted(inputData.keys()) 357 | 358 | for k in range(lenData): 359 | writeData = inputData[keyList[k]] 360 | 361 | self.expose_driver_unit(self.driverScroll,writeData,keyList[k],root) 362 | def validate_driver_deletion(self ,root , index, *args): 363 | self.factory.delete_Connections_at_targetIndex( root , index,0 ) 364 | self.reset_driverUI() 365 | self.fill_driverUI( root) 366 | #---------------------------------------------------------------------------------------- cookTab UI Helpers 367 | def validateDishBeforePublish(self,*args): 368 | root = mc.textField( self.bentoRoot,q=True,tx=True) 369 | erroChk = 0 370 | if len(root)== 0: 371 | print 'Please pick a root object' 372 | else: 373 | attributeList = ['foodType','moduleInfos','element'] 374 | feedBackList = ['found no foodType data in this dish','found no moduleInfos data in this dish','found no element data in this dish'] 375 | for index, checkObj in enumerate(attributeList): 376 | if mc.attributeQuery(checkObj,node=root,ex=True) == False: 377 | erroChk += 1 378 | mc.warning(feedBackList[index]) 379 | if erroChk == 0: 380 | self.factory.publish_driver(root) 381 | def validateRootData(self,*args): 382 | root = mc.textField( self.bentoRoot,q=True,tx=True) 383 | foodType = mc.textField( self.foodField,q=True,tx=True) 384 | erroChk = 0 385 | chkList = [root,foodType] 386 | feedBackList = ['Please pick a root object','Please define a unique foodType'] 387 | for index, checkObj in enumerate(chkList): 388 | if checkObj is None or len(checkObj)== 0: 389 | erroChk += 1 390 | mc.warning(feedBackList[index]) 391 | if erroChk == 0: 392 | infoData = mc.scrollField( self.scrollInfo ,q=True,tx=True) 393 | self.factory.process_root( root, 394 | foodType, 395 | infoData ) 396 | def validateDishData(self,*args): 397 | root = mc.textField( self.bentoRoot,q=True,tx=True) 398 | assetListing = mc.textScrollList( self.assetListing ,q=True,ai=True) 399 | erroChk = 0 400 | chkList = [root,assetListing] 401 | feedBackList = ['Please pick a root object','Please Fill the Element List'] 402 | for index, checkObj in enumerate(chkList): 403 | if checkObj is None or len(checkObj)== 0: 404 | erroChk += 1 405 | mc.warning(feedBackList[index]) 406 | if erroChk == 0: 407 | self.factory.expose_members(root,assetListing) 408 | def validateModule(self ,fieldRef,*args): 409 | foodTx = mc.textField( self.foodField,q=True,tx=True) 410 | if foodTx is not None: 411 | modulePath = ''.join(os.path.dirname(inspect.getfile(self.resizeBuildTabs))+'\src') 412 | filelist= os.listdir(modulePath) 413 | if foodTx in filelist: 414 | prt = mc.promptDialog( title='foodType Alert', 415 | message='Please choose another foodType name:', 416 | button=['OK'], 417 | defaultButton='OK') 418 | mc.textField( self.foodField,e=True,tx='') 419 | else: 420 | OpenMaya.MGlobal.displayInfo( '** %s is valid foodType, Please fill the other UI part to proceed'% foodTx ) 421 | def collect_root(self,fieldRef,*args): 422 | sel = mc.ls(sl=True,fl=True) 423 | mc.textField(fieldRef,e=True,tx='') 424 | mc.textField( self.foodField,e=True,tx='') 425 | mc.scrollField(self.scrollInfo ,e=True,tx='') 426 | 427 | mc.textScrollList( self.DriverAttributes ,e=True,ra=True) 428 | mc.textField( self.driverFld,e=True,tx='') 429 | 430 | mc.textScrollList( self.outputAttributes ,e=True,ra=True) 431 | mc.textField( self.outputFld,e=True,tx='') 432 | 433 | mc.textScrollList( self.assetListing,e=True,ra=True) 434 | self.reset_driverUI() 435 | self.reset_outputUI() 436 | 437 | if sel is None or len(sel)<1 : 438 | return 439 | else: 440 | self.fill_driverUI(sel[0]) 441 | self.fill_outputUI(sel[0]) 442 | 443 | UI_Dict = {} 444 | UI_Dict['moduleInfos'] = [ self.scrollInfo, 1] 445 | UI_Dict['foodType'] = [ self.foodField, 0] 446 | UI_Dict['element'] = [ self.assetListing, 2] 447 | 448 | dataList = self.factory.read_dish_data(sel[0]) 449 | 450 | for key in dataList.keys(): 451 | if dataList[key] is not '': 452 | if UI_Dict[key][1] == 0: 453 | mc.textField( UI_Dict[key][0],e=True,tx=dataList[key]) 454 | if UI_Dict[key][1] == 1: 455 | mc.scrollField( UI_Dict[key][0] ,e=True,tx=dataList[key]) 456 | if UI_Dict[key][1] == 2: 457 | for elem in dataList[key]: 458 | mc.textScrollList( UI_Dict[key][0] ,e=True,a=elem) 459 | mc.textField(fieldRef,e=True,tx=sel[0]) 460 | def scanSceneGraph(self ,*args): 461 | sceneGraph = mc.ls() 462 | mc.textScrollList(self.bentoElements,e=True,ra=True) 463 | 464 | filterList = [ item for item in sceneGraph if item not in self.defaultNodes] 465 | 466 | for obj in filterList: 467 | mc.textScrollList(self.bentoElements,e=True,a=obj) 468 | def removeNodeFromElementList(self ,*args): 469 | selectedItems = mc.textScrollList(self.bentoElements,q=True,selectItem=True) 470 | if selectedItems is not None: 471 | selectedItems.reverse() 472 | for obj in selectedItems : 473 | mc.textScrollList(self.bentoElements,e=True,removeItem=obj) 474 | #---------------------------------------------------------------------------------------- cook TAB 475 | def cookTab(self): 476 | mc.columnLayout( adjustableColumn=True, rs=5,w=self.canvasSize[0],p=self.tabCtrl_A) 477 | buildDish_UI_Anchor = mc.frameLayout( collapsable=False,labelVisible=False, mw=5,mh=5,borderStyle='out' ) 478 | 479 | self.flagRoot_UI() 480 | self.tabCtrl_B = mc.tabLayout( innerMarginWidth=5, innerMarginHeight=5 ) 481 | self.injectElement_UI() 482 | self.defineDriver_UI() 483 | self.defineOutput_UI() 484 | self.defineMisc_UI() 485 | 486 | # publish Elements 487 | mc.setParent(buildDish_UI_Anchor) 488 | mc.separator() 489 | mc.button(l='Release bento',h=45,c=self.validateDishBeforePublish) 490 | 491 | mc.tabLayout(self.tabCtrl_B ,e=True,tabLabelIndex=[1,'4. Flag Elements']) 492 | mc.tabLayout(self.tabCtrl_B ,e=True,tabLabelIndex=[2,'5. Expose Drivers']) 493 | mc.tabLayout(self.tabCtrl_B ,e=True,tabLabelIndex=[3,'6. Expose Outputs']) 494 | mc.tabLayout(self.tabCtrl_B ,e=True,tabLabelIndex=[4,'7. Misc.']) 495 | #---------------------------------------------------------------------------------------- deliverTab UI Helpers 496 | def validate_compile(self ,*args): 497 | self.IO.compile_bundle() 498 | # Tool().show() 499 | #---------------------------------------------------------------------------------------- deliver TAB 500 | def deliverTab(self): 501 | mc.columnLayout( adjustableColumn=True, rs=5,w=self.canvasSize[0],p=self.tabCtrl_A) 502 | mc.button(l='Compile bundle',c=self.validate_compile) 503 | self.bundle_prgrss = mc.progressBar('CCW_TOOLS_bundle_prgrss') 504 | --------------------------------------------------------------------------------