Maya Python游戏与影视编程指南阅读笔记——第七章

maya命令创建基本工具
1、构建窗口基类,并继承创建窗口,实现基本物体创建
optwin.py文件

import maya.cmds as cmds

class AR_OptionsWindow(object):
    """选项窗口的基类"""
    @classmethod
    def showUI(cls):
        """用于实例化选项窗口的函数"""
        win = cls()
        win.create()
        return win
    def __init__(self):
        """初始化公共数据属性"""
        ## 唯一的窗口句柄
        self.window = 'ar_optionsWindow'
        ## 窗口标题
        self.title = 'Options Window'
        ## 窗口大小
        self.size = (546, 350)
        ## 指定是否支持工具/操作切换
        self.supportsToolAction = False
        ## 要在操作按钮上显示的名称
        self.actionName = 'Apply and Close'
    def create(self):
        """绘制窗口"""
        # 如果窗口存在句柄,则删除该窗口
        if cmds.window(self.window, exists=True):
            cmds.deleteUI(self.window, window=True)
        # 初始化窗口
        self.window = cmds.window(
            self.window,
            title=self.title,
            widthHeight=self.size,
            menuBar=True
        )
        # 窗口的主窗体
        self.mainForm = cmds.formLayout(nd=100)
        # 创建常用菜单项和按钮
        self.commonMenu()
        self.commonButtons()
        # 请参见getOptionBox.mel,了解我们为什么要实现此布局模式以模拟maya的选项框
        self.optionsBorder = cmds.tabLayout(
            scrollable=True,
            tabsVisible=False,
            height=1,
            childResizable=True
        )
        cmds.formLayout(
            self.mainForm, e=True,
            attachForm=(
                [self.optionsBorder,'top',0],
                [self.optionsBorder,'left',2],
                [self.optionsBorder,'right',2]
            ),
            attachControl=(
                [self.optionsBorder,'bottom',5,self.applyBtn]
            )
        )
        # 在displayOptions()中附加控件的窗体
        self.optionsForm = cmds.formLayout(nd=100)
        self.displayOptions()
        # 显示窗口
        cmds.showWindow()
    def commonMenu(self):
        """为所有选项框创建公用菜单项"""
        self.editMenu = cmds.menu(label='Edit')
        self.editMenuSave = cmds.menuItem(
            label='Save Settings',
            command=self.editMenuSaveCmd
        )
        self.editMenuReset = cmds.menuItem(
            label='Reset Settings',
            command=self.editMenuResetCmd
        )
        self.editMenuDiv = cmds.menuItem(d=True)
        self.editMenuRadio = cmds.radioMenuItemCollection()
        self.editMenuTool = cmds.menuItem(
            label='As Tool',
            radioButton=True,
            enable=self.supportsToolAction,
            command=self.editMenuToolCmd
        )
        self.editMenuAction = cmds.menuItem(
            label='As Action',
            radioButton=True,
            enable=self.supportsToolAction,
            command=self.editMenuActionCmd
        )
        self.helpMenu = cmds.menu(label='Help')
        self.helpMenuItem = cmds.menuItem(
            label='Help on %s'%self.title,
            command=self.helpMenuCmd
        )
    def helpMenuCmd(self, *args):
        """重写此方法以显示自定义帮助"""
        cmds.launch(web='http://maya-python.com')
    def editMenuSaveCmd(self, *args):
        """重写此方法以实现保存设置"""
        pass
    def editMenuResetCmd(self, *args):
        """重写此方法以实现重置设置"""
        pass
    def editMenuToolCmd(self, *args):
        """重写此方法以实现工具模式"""
        pass
    def editMenuActionCmd(self, *args):
        """重写此方法以实现操作模式"""
        pass
    def actionBtnCmd(self, *args):
        """应用操作并关闭窗口"""
        self.applyBtnCmd()
        self.closeBtnCmd()
    def applyBtnCmd(self, *args):
        """重写此方法以应用操作"""
        pass
    def closeBtnCmd(self, *args):
        """关闭窗口"""
        cmds.deleteUI(self.window, window=True)
    def commonButtons(self):
        """为所有选项框创建公用按钮"""
        self.commonBtnSize = ((self.size[0]-18)/3, 26)
        self.actionBtn = cmds.button(
            label=self.actionName,
            height=self.commonBtnSize[1],
            command=self.actionBtnCmd
        )
        self.applyBtn = cmds.button(
            label='Apply',
            height=self.commonBtnSize[1],
            command=self.applyBtnCmd
        )
        self.closeBtn = cmds.button(
            label='Close',
            height=self.commonBtnSize[1],
            command=self.closeBtnCmd
        )
        cmds.formLayout(
            self.mainForm, e=True,
            attachForm=(
                [self.actionBtn,'left',5],
                [self.actionBtn,'bottom',5],
                [self.applyBtn,'bottom',5],
                [self.closeBtn,'bottom',5],
                [self.closeBtn,'right',5]
            ),
            attachPosition=(
                [self.actionBtn,'right',1,33],
                [self.closeBtn,'left',0,67]
            ),
            attachControl=(
                [self.applyBtn,'left',4,self.actionBtn],
                [self.applyBtn,'right',4,self.closeBtn]
            ),
            attachNone=(
                [self.actionBtn,'top'],
                [self.applyBtn,'top'],
                [self.closeBtn,'top']
            )
        )
    def displayOptions(self):
        """重写此方法以显示选项控件"""
        pass

#AR_OptionsWindow.showUI() #创建预览窗口

polywin.py文件

import maya.cmds as cmds
from optwin import AR_OptionsWindow

class AR_PolyOptionsWindow(AR_OptionsWindow):
    """用于创建多边形基本体的简单窗口的类"""
    def __init__(self):
        """初始化基类并重写数据属性"""
        AR_OptionsWindow.__init__(self)
        # 基类属性重写
        self.title = 'Polygon Creation Options'
        # 基类属性重写
        self.actionName = 'Create'
    def displayOptions(self):
        """从基类重写"""
        # 基本类型选择器
        self.objType = cmds.radioButtonGrp(
            label='Object Type: ',
            labelArray4=[
                'Cube',
                'Cone',
                'Cylinder',
                'Sphere'
            ],
            numberOfRadioButtons=4,
            select=1,
        )
        # 一组变换控件
        self.xformGrp = cmds.frameLayout(
            label='Transformations',
            collapsable=True,
        )
        cmds.formLayout(
            self.optionsForm, e=True,
            attachControl=(
                [self.xformGrp,'top',2,self.objType]
            ),
            attachForm=(
                [self.xformGrp,'left',0],
                [self.xformGrp,'right',0]
            )
        )
        self.xformCol = cmds.columnLayout()
        self.position = cmds.floatFieldGrp(
            label='Position: ',
            numberOfFields=3
        )
        self.rotation = cmds.floatFieldGrp(
            label='Rotation (XYZ): ',
            numberOfFields=3
        )
        self.scale = cmds.floatFieldGrp(
            label='Scale: ',
            numberOfFields=3,
            value=[1.0,1.0,1.0,1.0]
        )
        cmds.setParent('..')
        cmds.setParent('..')
        # 顶点颜色选择器
        self.color = cmds.colorSliderGrp(
            label='Vertex Colors: '
        )
        cmds.formLayout(
            self.optionsForm, e=True,
            attachControl=(
                [self.color,'top',0,self.xformGrp]
            ),
            attachForm=(
                [self.color,'left',0],
            )
        )
    def applyBtnCmd(self, *args):
        """从基类重写"""
        # 确定要创建的对象的类型
        self.objIndAsCmd = {
    
    
            1:cmds.polyCube,
            2:cmds.polyCone,
            3:cmds.polyCylinder,
            4:cmds.polySphere
        }
        objIndex = cmds.radioButtonGrp(
            self.objType, q=True,
            select=True
        )
        # 创建新对象
        newObject = self.objIndAsCmd[objIndex]()
        # 转换新对象
        pos = cmds.floatFieldGrp(
            self.position, q=True,
            value=True
        )
        rot = cmds.floatFieldGrp(
            self.rotation, q=True,
            value=True
        )
        scale = cmds.floatFieldGrp(
            self.scale, q=True,
            value=True
        )
        cmds.xform(newObject[0], t=pos, ro=rot, s=scale)
        # 将顶点颜色应用于新对象
        col = cmds.colorSliderGrp(
            self.color, q=True,
            rgbValue=True
        )
        cmds.polyColorPerVertex(
            newObject[0],
            colorRGB=col,
            colorDisplayOption=True
        )
        
        
#实例化窗口        
AR_PolyOptionsWindow.showUI()

输出效果:
在这里插入图片描述

maya命令创建动作姿势管理器

import maya.cmds as cmds
import maya.mel as mel
import os, cPickle, sys, time

kPoseFileExtension = 'pse'

def showUI():
    """实例化姿势管理器窗口的函数"""
    return AR_PoseManagerWindow.showUI()

class AR_PoseManagerWindow(object):
    """基本姿势管理器窗口的类"""
    @classmethod
    def showUI(cls):
        """实例化姿势管理器窗口的函数"""
        win = cls()
        win.create()
        return win
    def __init__(self):
        """初始化数据属性"""
        ## 独特的窗把手
        self.window = 'ar_poseManagerWindow'
        ## 窗口标题
        self.title = 'Pose Manager'
        ## 窗口大小
        self.size = (300, 174)
        if mel.eval('getApplicationVersionAsFloat()') > 2010.0:
            self.size = (300, 150)
        ## 在可写位置存储姿势的临时文件
        self.tempFile = os.path.join(
            os.path.expanduser('~'),
            'temp_pose.%s'%kPoseFileExtension
        )
        ## 当前剪贴板状态消息
        self.clipboardStat = 'No pose currently copied.'
        if (os.path.exists(self.tempFile)):
            self.clipboardStat = 'Old pose currently copied to clipboard.'
        ## 要在文件浏览器中显示的文件筛选器
        self.fileFilter = 'Pose (*.%s)'%kPoseFileExtension
    def create(self):
        """绘制窗口"""
        # 如果窗口存在句柄,则删除该窗口
        if(cmds.window(self.window, exists=True)):
            cmds.deleteUI(self.window, window=True)
        # 初始化窗口
        self.window = cmds.window(self.window, title=self.title, wh=self.size, s=False)
        # 主窗体布局
        self.mainForm = cmds.formLayout()
        # 复制/粘贴框架
        self.copyPasteFrame = cmds.frameLayout(l='Copy and Paste Poses')
        # 框架内的窗体布局
        self.copyPasteForm = cmds.formLayout()
        # 在两列网格中创建按钮
        self.copyPasteGrid = cmds.gridLayout(cw=self.size[0]/2-2, nc=2)
        self.copyBtn = cmds.button(l='Copy Pose', c=self.copyBtnCmd)
        self.pasteBtn = cmds.button(l='Paste Pose', c=self.pasteBtnCmd)
        # 带剪贴板状态标签的滚动视图
        cmds.setParent(self.copyPasteForm)
        self.clipboardLayout = cmds.scrollLayout(h=42, w=self.size[0]-4)
        self.clipboardLbl = cmds.text(l=self.clipboardStat)
        # 在复制粘贴窗体中附加控件
        ac = []; af = []
        ac.append([self.clipboardLayout,'top',0,self.copyPasteGrid])
        af.append([self.copyPasteGrid,'top',0])
        af.append([self.clipboardLayout,'bottom',0])
        cmds.formLayout(
            self.copyPasteForm, e=True,
            attachControl=ac, attachForm=af
        )
        # 保存/加载框架
        cmds.setParent(self.mainForm)
        self.loadSaveFrame = cmds.frameLayout(l='Save and Load Poses')
        # 在两列网格中创建按钮
        self.loadSaveBtnLayout = cmds.gridLayout(cw=self.size[0]/2-2, nc=2)
        self.saveBtn = cmds.button(l='Save Pose', c=self.saveBtnCmd)
        self.loadBtn = cmds.button(l='Load Pose', c=self.loadBtnCmd)
        # 将框架附加到主窗体
        ac = []; af = []
        ac.append([self.loadSaveFrame,'top',0,self.copyPasteFrame])
        af.append([self.copyPasteFrame,'top',0])
        af.append([self.copyPasteFrame,'left',0])
        af.append([self.copyPasteFrame,'right',0])
        af.append([self.loadSaveFrame,'bottom',0])
        af.append([self.loadSaveFrame,'left',0])
        af.append([self.loadSaveFrame,'right',0])
        cmds.formLayout(
            self.mainForm, e=True,
            attachControl=ac, attachForm=af
        )
        # 显示窗口
        cmds.showWindow(self.window)
        # 强制窗口大小
        cmds.window(self.window, e=True, wh=self.size)
    def getSelection(self):
        rootNodes = cmds.ls(sl=True, type='transform')
        if rootNodes is None or len(rootNodes) < 1:
            cmds.confirmDialog(t='Error', b=['OK'],
                m='Please select one or more transform nodes.')
            return None
        else: return rootNodes
    def copyBtnCmd(self, *args):
        """当按下复制姿势按钮时调用"""
        rootNodes = self.getSelection()
        if rootNodes is None: return
        cmds.text(
            self.clipboardLbl, e=True,
            l='Pose copied at %s for %s.'%(
                time.strftime('%I:%M'),
                ''.join('%s, '%t for t in rootNodes)[:-3]
            )
        )
        exportPose(self.tempFile, rootNodes)
    def pasteBtnCmd(self, *args):
        """当按下粘贴姿势按钮时调用"""
        if not os.path.exists(self.tempFile): return
        importPose(self.tempFile)
    def saveBtnCmd(self, *args):
        """当按下保存姿势按钮时调用"""
        rootNodes = self.getSelection()
        if rootNodes is None: return
        filePath = ''
        # 2011及更新版本的使用 fileDialog2
        try:
            filePath = cmds.fileDialog2(
                ff=self.fileFilter, fileMode=0
            )
        # BUG: 在某些版本的OS X上,Maya 2008和更早的版本可能会返回目录名和文件名之间没有分隔符的路径:e.g., /users/adam/Desktopuntitled.pse
        except:
            filePath = cmds.fileDialog(
                dm='*.%s'%kPoseFileExtension, mode=1
            )
        # 提前退出对话被取消
        if filePath is None or len(filePath) < 1: return
        if isinstance(filePath, list): filePath = filePath[0]
        exportPose(filePath, cmds.ls(sl=True, type='transform'))
    def loadBtnCmd(self, *args):
        """按下加载姿势按钮时调用"""
        filePath = ''
        # 玛雅2011及更新版本的使用 fileDialog2
        try:
            filePath = cmds.fileDialog2(
                ff=self.fileFilter, fileMode=1
            )
        except:
            filePath = cmds.fileDialog(
                dm='*.%s'%kPoseFileExtension, mode=0
            )
        # 提前退出对话被取消
        if filePath is None or len(filePath) < 1: return
        if isinstance(filePath, list): filePath = filePath[0]
        importPose(filePath)

def exportPose(filePath, rootNodes):
    """在文件路径处为根节点及其子节点保存姿势文件"""
    # try to open the file
    try: f = open(filePath, 'w')
    except:
        cmds.confirmDialog(
            t='Error', b=['OK'],
            m='Unable to write file: %s'%filePath
        )
        raise
    # 建立层次结构数据列表
    data = saveHiearchy(rootNodes, [])
    # 保存序列化数据
    cPickle.dump(data, f)
    # 关闭文件
    f.close()

def saveHiearchy(rootNodes, data):
    """将所有可设置关键帧属性的属性值附加到数据数组"""
    # 遍历提供的节点
    for node in rootNodes:
        # 跳过非转换节点
        nodeType = cmds.nodeType(node)
        if not (nodeType=='transform' or 
            nodeType=='joint'): continue
        # 获取动画属性
        keyableAttrs = cmds.listAttr(node, keyable=True)
        if keyableAttrs is not None:
            for attr in keyableAttrs:
                data.append(['%s.%s'%(node,attr), 
                    cmds.getAttr('%s.%s'%(node,attr))])
        # 如果有子级,则重复相同的过程并附加其数据
        children = cmds.listRelatives(node, children=True)
        if children is not None: saveHiearchy(children, data)
    return data

def importPose(filePath):
    """导入存储在filePath中的姿势数据"""
    # 尝试打开文件
    try: f = open(filePath, 'r')
    except:
        cmds.confirmDialog(
            t='Error', b=['OK'],
            m='Unable to open file: %s'%filePath
        )
        raise
    # 取消pickle数据
    pose = cPickle.load(f)
    # 关闭文件
    f.close()
    # 将属性设置为存储的姿势
    errAttrs = []
    for attrValue in pose:
        try: cmds.setAttr(attrValue[0], attrValue[1])
        except:
            try: errAttrs.append(attrValue[0])
            except: errAttrs.append(attrValue)
    # 如果需要,显示错误消息
    if len(errAttrs) > 0:
        importErrorWindow(errAttrs)
        sys.stderr.write('Not all attributes could be loaded.')

def importErrorWindow(errAttrs):
    """导入姿势时,如果有未知属性,将显示一个错误窗口"""
    win='ar_errorWindow'
    # 关闭窗口的函数
    def dismiss(*args):
        cmds.deleteUI(win, window=True)
    # 如果存在该窗口,则将其销毁
    if cmds.window(win, exists=True):
        dismiss()
    # 创建窗口
    size = (300, 200)
    cmds.window(
        win, wh=size, s=False,
        t='Unknown Attributes'
    )
    mainForm = cmds.formLayout()
    # 信息标签
    infoLbl = cmds.text(l='The following attributes could not be found.\nThey are being ignored.', al='left')
    # 显示无法加载的属性列表
    scroller = cmds.scrollLayout(w=size[0])
    errStr = ''.join('\t- %s\n'%a for a in errAttrs).rstrip()
    cmds.text(l=errStr, al='left')
    # 关闭按钮
    btn = cmds.button(l='OK', c=dismiss, p=mainForm, h=26)
    # 附加控件
    ac = []; af=[];
    ac.append([scroller,'top',5,infoLbl])
    ac.append([scroller,'bottom',5,btn])
    af.append([infoLbl,'top',5])
    af.append([infoLbl,'left',5])
    af.append([infoLbl,'right',5])
    af.append([scroller,'left',0])
    af.append([scroller,'right',0])
    af.append([btn,'left',5])
    af.append([btn,'right',5])
    af.append([btn,'bottom',5])
    cmds.formLayout(
        mainForm, e=True,
        attachControl=ac, attachForm=af
    )
    # 显示窗口
    cmds.window(win, e=True, wh=size)
    cmds.showWindow(win)
    
    
showUI()

输出结果:
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/peixin_huang/article/details/104143045