Update
This commit is contained in:
577
docs/CUSTOM_PLUGIN_GUIDE.md
Normal file
577
docs/CUSTOM_PLUGIN_GUIDE.md
Normal file
@@ -0,0 +1,577 @@
|
||||
# Maya 自定义插件添加指南
|
||||
|
||||
本指南将帮助你在 NexusLauncher 的 Maya 插件系统中添加自己的工具和插件。
|
||||
|
||||
---
|
||||
|
||||
## 📁 目录结构说明
|
||||
|
||||
```
|
||||
template/plugins/maya/2023/
|
||||
├── shelves/ # 工具架文件(.mel 格式)
|
||||
├── scripts/ # Python/MEL 脚本
|
||||
├── plug-ins/ # Maya 插件文件(.py 或 .mll)
|
||||
├── icons/ # 工具图标
|
||||
└── README.md # 基础说明文档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 添加方式概览
|
||||
|
||||
根据你的需求,有三种主要的添加方式:
|
||||
|
||||
| 方式 | 适用场景 | 难度 |
|
||||
|------|---------|------|
|
||||
| **1. 添加工具架按钮** | 快速添加 Python 脚本工具 | ⭐ 简单 |
|
||||
| **2. 添加 Maya 插件** | 创建 Maya 命令或节点 | ⭐⭐ 中等 |
|
||||
| **3. 添加启动脚本** | 自动执行初始化代码 | ⭐ 简单 |
|
||||
|
||||
---
|
||||
|
||||
## 方式 1: 添加工具架按钮
|
||||
|
||||
### 适用场景
|
||||
- 你有一个 Python 脚本工具想要快速访问
|
||||
- 需要在工具架上添加按钮
|
||||
- 不需要注册 Maya 命令
|
||||
|
||||
### 步骤
|
||||
|
||||
#### 1.1 准备你的 Python 脚本
|
||||
|
||||
将你的 Python 脚本放到 `scripts/` 目录:
|
||||
|
||||
```
|
||||
scripts/
|
||||
├── userSetup.py # 启动脚本(已存在)
|
||||
├── nexus_test.py # 示例脚本(已存在)
|
||||
└── my_custom_tool.py # 👈 你的新脚本
|
||||
```
|
||||
|
||||
**示例脚本** (`my_custom_tool.py`):
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
我的自定义工具
|
||||
"""
|
||||
import maya.cmds as cmds
|
||||
|
||||
def run_my_tool():
|
||||
"""执行我的工具"""
|
||||
# 你的工具逻辑
|
||||
cmds.confirmDialog(
|
||||
title='My Tool',
|
||||
message='Hello from my custom tool!',
|
||||
button=['OK']
|
||||
)
|
||||
print("[MyTool] Tool executed successfully")
|
||||
|
||||
def show_ui():
|
||||
"""显示工具界面"""
|
||||
# 如果有 UI,在这里创建
|
||||
pass
|
||||
```
|
||||
|
||||
#### 1.2 准备图标(可选)
|
||||
|
||||
将图标文件放到 `icons/` 目录:
|
||||
|
||||
```
|
||||
icons/
|
||||
├── nexus_test.png # 示例图标(已存在)
|
||||
└── my_tool_icon.png # 👈 你的图标(32x32 或 64x64 PNG)
|
||||
```
|
||||
|
||||
> **提示**: 如果没有图标,可以使用文字标签代替
|
||||
|
||||
#### 1.3 编辑工具架文件
|
||||
|
||||
编辑 `shelves/shelf_NexusLauncher.mel`,在文件末尾的 `}` 之前添加新按钮:
|
||||
|
||||
```mel
|
||||
shelfButton
|
||||
-enableCommandRepeat 1
|
||||
-flexibleWidthType 3
|
||||
-flexibleWidthValue 32
|
||||
-enable 1
|
||||
-width 35
|
||||
-height 34
|
||||
-manage 1
|
||||
-visible 1
|
||||
-preventOverride 0
|
||||
-annotation "我的自定义工具 - 点击运行"
|
||||
-enableBackground 0
|
||||
-backgroundColor 0 0 0
|
||||
-highlightColor 0.321569 0.521569 0.65098
|
||||
-align "center"
|
||||
-label "MT"
|
||||
-labelOffset 0
|
||||
-rotation 0
|
||||
-flipX 0
|
||||
-flipY 0
|
||||
-useAlpha 1
|
||||
-font "boldLabelFont"
|
||||
-imageOverlayLabel "MT"
|
||||
-overlayLabelColor 1 1 1
|
||||
-overlayLabelBackColor 0.2 0.8 0.5 0.9
|
||||
-image "my_tool_icon.png"
|
||||
-image1 "my_tool_icon.png"
|
||||
-style "iconOnly"
|
||||
-marginWidth 0
|
||||
-marginHeight 1
|
||||
-command "import my_custom_tool\nmy_custom_tool.run_my_tool()"
|
||||
-sourceType "python"
|
||||
-commandRepeatable 1
|
||||
-flat 1
|
||||
;
|
||||
```
|
||||
|
||||
**关键参数说明**:
|
||||
- `-annotation`: 鼠标悬停时的提示文字
|
||||
- `-label`: 按钮文字标签(如果没有图标会显示)
|
||||
- `-imageOverlayLabel`: 图标上的文字叠加层
|
||||
- `-overlayLabelBackColor`: 文字背景颜色 (R G B Alpha)
|
||||
- `-image`: 图标文件名(在 icons/ 目录中)
|
||||
- `-command`: 点击按钮时执行的 Python 代码
|
||||
|
||||
#### 1.4 测试
|
||||
|
||||
1. 通过 NexusLauncher 启动 Maya 2023
|
||||
2. 检查 NexusLauncher 工具架是否出现新按钮
|
||||
3. 点击按钮测试功能
|
||||
|
||||
---
|
||||
|
||||
## 方式 2: 添加 Maya 插件
|
||||
|
||||
### 适用场景
|
||||
- 需要注册自定义 Maya 命令
|
||||
- 需要创建自定义节点
|
||||
- 需要更深度的 Maya API 集成
|
||||
|
||||
### 步骤
|
||||
|
||||
#### 2.1 创建插件文件
|
||||
|
||||
在 `plug-ins/` 目录创建你的插件文件:
|
||||
|
||||
```
|
||||
plug-ins/
|
||||
├── nexus_example_plugin.py # 示例插件(已存在)
|
||||
└── my_custom_plugin.py # 👈 你的新插件
|
||||
```
|
||||
|
||||
**插件模板** (`my_custom_plugin.py`):
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
我的自定义 Maya 插件
|
||||
"""
|
||||
import sys
|
||||
import maya.api.OpenMaya as om
|
||||
|
||||
|
||||
def maya_useNewAPI():
|
||||
"""告诉 Maya 使用 Python API 2.0"""
|
||||
pass
|
||||
|
||||
|
||||
class MyCustomCommand(om.MPxCommand):
|
||||
"""自定义命令类"""
|
||||
|
||||
kPluginCmdName = 'myCustomCmd' # 命令名称
|
||||
|
||||
def __init__(self):
|
||||
om.MPxCommand.__init__(self)
|
||||
|
||||
@staticmethod
|
||||
def cmdCreator():
|
||||
return MyCustomCommand()
|
||||
|
||||
def doIt(self, args):
|
||||
"""执行命令"""
|
||||
print(f'[MyPlugin] Custom command executed!')
|
||||
om.MGlobal.displayInfo('My custom plugin is working!')
|
||||
|
||||
# 在这里添加你的命令逻辑
|
||||
# 例如:创建对象、修改场景等
|
||||
|
||||
|
||||
def initializePlugin(plugin):
|
||||
"""初始化插件"""
|
||||
pluginFn = om.MFnPlugin(plugin, 'YourName', '1.0', 'Any')
|
||||
try:
|
||||
pluginFn.registerCommand(
|
||||
MyCustomCommand.kPluginCmdName,
|
||||
MyCustomCommand.cmdCreator
|
||||
)
|
||||
print(f'[MyPlugin] Plugin loaded: {MyCustomCommand.kPluginCmdName}')
|
||||
except:
|
||||
sys.stderr.write(f'Failed to register command: {MyCustomCommand.kPluginCmdName}')
|
||||
raise
|
||||
|
||||
|
||||
def uninitializePlugin(plugin):
|
||||
"""卸载插件"""
|
||||
pluginFn = om.MFnPlugin(plugin)
|
||||
try:
|
||||
pluginFn.deregisterCommand(MyCustomCommand.kPluginCmdName)
|
||||
print(f'[MyPlugin] Plugin unloaded: {MyCustomCommand.kPluginCmdName}')
|
||||
except:
|
||||
sys.stderr.write(f'Failed to deregister command: {MyCustomCommand.kPluginCmdName}')
|
||||
raise
|
||||
```
|
||||
|
||||
#### 2.2 配置自动加载
|
||||
|
||||
编辑 `scripts/userSetup.py`,在 `load_nexus_plugins()` 函数中添加你的插件:
|
||||
|
||||
```python
|
||||
def load_nexus_plugins():
|
||||
"""Load NexusLauncher plugins"""
|
||||
try:
|
||||
plugin_path = os.environ.get('MAYA_PLUG_IN_PATH', '')
|
||||
|
||||
if not plugin_path:
|
||||
print("[NexusLauncher] MAYA_PLUG_IN_PATH not set, skipping plugin load")
|
||||
return
|
||||
|
||||
print(f"[NexusLauncher] MAYA_PLUG_IN_PATH: {plugin_path}")
|
||||
|
||||
# 要加载的插件列表
|
||||
plugins_to_load = [
|
||||
"nexus_example_plugin.py",
|
||||
"my_custom_plugin.py", # 👈 添加你的插件
|
||||
]
|
||||
|
||||
for plugin_file in plugins_to_load:
|
||||
if cmds.pluginInfo(plugin_file, query=True, loaded=True):
|
||||
print(f"[NexusLauncher] Plugin already loaded: {plugin_file}")
|
||||
else:
|
||||
try:
|
||||
cmds.loadPlugin(plugin_file)
|
||||
print(f"[NexusLauncher] ✓ Loaded plugin: {plugin_file}")
|
||||
|
||||
# 设置为自动加载
|
||||
cmds.pluginInfo(plugin_file, edit=True, autoload=True)
|
||||
print(f"[NexusLauncher] ✓ Set plugin to auto-load")
|
||||
except Exception as e:
|
||||
print(f"[NexusLauncher] Failed to load plugin {plugin_file}: {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[NexusLauncher] Error loading plugins: {e}")
|
||||
```
|
||||
|
||||
#### 2.3 测试插件
|
||||
|
||||
1. 通过 NexusLauncher 启动 Maya 2023
|
||||
2. 检查脚本编辑器输出,确认插件已加载
|
||||
3. 在 Maya 命令行或脚本编辑器中测试命令:
|
||||
|
||||
```python
|
||||
import maya.cmds as cmds
|
||||
cmds.myCustomCmd() # 执行你的自定义命令
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 方式 3: 添加启动脚本
|
||||
|
||||
### 适用场景
|
||||
- 需要在 Maya 启动时自动执行某些操作
|
||||
- 设置环境变量或全局配置
|
||||
- 加载第三方库
|
||||
|
||||
### 步骤
|
||||
|
||||
#### 3.1 编辑 userSetup.py
|
||||
|
||||
在 `scripts/userSetup.py` 文件末尾添加你的初始化代码:
|
||||
|
||||
```python
|
||||
def my_custom_startup():
|
||||
"""我的自定义启动函数"""
|
||||
try:
|
||||
print("[MyStartup] Running custom startup code...")
|
||||
|
||||
# 在这里添加你的启动逻辑
|
||||
# 例如:
|
||||
# - 设置默认渲染器
|
||||
# - 加载常用插件
|
||||
# - 配置工作区
|
||||
# - 连接到资产管理系统
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
# 示例:设置默认单位为厘米
|
||||
cmds.currentUnit(linear='cm')
|
||||
print("[MyStartup] ✓ Set default unit to cm")
|
||||
|
||||
# 示例:设置默认时间单位为 24fps
|
||||
cmds.currentUnit(time='film')
|
||||
print("[MyStartup] ✓ Set default time unit to 24fps")
|
||||
|
||||
print("[MyStartup] ✓ Custom startup completed")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[MyStartup] Error during startup: {e}")
|
||||
|
||||
|
||||
# 在 Maya 启动完成后执行
|
||||
cmds.evalDeferred(my_custom_startup)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 高级技巧
|
||||
|
||||
### 1. 动态重载工具架
|
||||
|
||||
如果你在开发过程中频繁修改工具架,可以使用 `RELOAD_SHELF.py` 快速重载:
|
||||
|
||||
```python
|
||||
# 在 Maya 脚本编辑器中执行
|
||||
import sys
|
||||
sys.path.append(r'E:\Zoroot\Dev\NexusLauncher\template\plugins\maya\2023')
|
||||
import RELOAD_SHELF
|
||||
RELOAD_SHELF.reload_shelf()
|
||||
```
|
||||
|
||||
### 2. 使用相对导入
|
||||
|
||||
如果你的工具有多个模块,可以创建包结构:
|
||||
|
||||
```
|
||||
scripts/
|
||||
├── my_tool/
|
||||
│ ├── __init__.py
|
||||
│ ├── core.py
|
||||
│ ├── ui.py
|
||||
│ └── utils.py
|
||||
└── userSetup.py
|
||||
```
|
||||
|
||||
在工具架按钮中使用:
|
||||
|
||||
```mel
|
||||
-command "from my_tool import ui\nui.show_window()"
|
||||
```
|
||||
|
||||
### 3. 添加菜单项
|
||||
|
||||
除了工具架按钮,你还可以在 `userSetup.py` 中添加自定义菜单:
|
||||
|
||||
```python
|
||||
def create_custom_menu():
|
||||
"""创建自定义菜单"""
|
||||
try:
|
||||
import maya.cmds as cmds
|
||||
|
||||
# 检查菜单是否已存在
|
||||
if cmds.menu('NexusMenu', exists=True):
|
||||
cmds.deleteUI('NexusMenu')
|
||||
|
||||
# 创建菜单
|
||||
main_window = mel.eval('$tmpVar=$gMainWindow')
|
||||
custom_menu = cmds.menu(
|
||||
'NexusMenu',
|
||||
label='NexusTools',
|
||||
parent=main_window,
|
||||
tearOff=True
|
||||
)
|
||||
|
||||
# 添加菜单项
|
||||
cmds.menuItem(
|
||||
label='My Tool',
|
||||
command='import my_custom_tool; my_custom_tool.run_my_tool()',
|
||||
parent=custom_menu
|
||||
)
|
||||
|
||||
cmds.menuItem(divider=True, parent=custom_menu)
|
||||
|
||||
cmds.menuItem(
|
||||
label='About',
|
||||
command='cmds.confirmDialog(title="About", message="NexusTools v1.0")',
|
||||
parent=custom_menu
|
||||
)
|
||||
|
||||
print("[NexusLauncher] ✓ Created custom menu")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[NexusLauncher] Error creating menu: {e}")
|
||||
|
||||
# 在启动时执行
|
||||
cmds.evalDeferred(create_custom_menu)
|
||||
```
|
||||
|
||||
### 4. 调试技巧
|
||||
|
||||
**查看环境变量**:
|
||||
```python
|
||||
import os
|
||||
print(os.environ.get('MAYA_SHELF_PATH'))
|
||||
print(os.environ.get('MAYA_PLUG_IN_PATH'))
|
||||
```
|
||||
|
||||
**检查插件加载状态**:
|
||||
```python
|
||||
import maya.cmds as cmds
|
||||
print(cmds.pluginInfo(query=True, listPlugins=True))
|
||||
```
|
||||
|
||||
**查看工具架列表**:
|
||||
```python
|
||||
import maya.cmds as cmds
|
||||
print(cmds.lsUI(type='shelfLayout'))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 常见问题
|
||||
|
||||
### Q1: 工具架按钮不显示图标?
|
||||
|
||||
**A**: 检查以下几点:
|
||||
1. 图标文件是否在 `icons/` 目录中
|
||||
2. 文件名是否正确(区分大小写)
|
||||
3. 图标格式是否为 PNG
|
||||
4. `XBMLANGPATH` 环境变量是否正确设置
|
||||
|
||||
### Q2: Python 脚本找不到模块?
|
||||
|
||||
**A**: 确保:
|
||||
1. 脚本在 `scripts/` 目录中
|
||||
2. `PYTHONPATH` 和 `MAYA_SCRIPT_PATH` 已正确设置
|
||||
3. 使用 `import` 时不需要包含 `.py` 后缀
|
||||
|
||||
### Q3: 插件加载失败?
|
||||
|
||||
**A**: 检查:
|
||||
1. 插件文件语法是否正确
|
||||
2. 是否包含 `maya_useNewAPI()` 函数(API 2.0)
|
||||
3. `initializePlugin()` 和 `uninitializePlugin()` 是否正确实现
|
||||
4. 查看脚本编辑器的错误信息
|
||||
|
||||
### Q4: 修改后没有生效?
|
||||
|
||||
**A**: 尝试:
|
||||
1. 完全关闭 Maya 重新启动
|
||||
2. 使用 `RELOAD_SHELF.py` 重载工具架
|
||||
3. 检查是否修改了正确版本的文件(2023/2025)
|
||||
|
||||
### Q5: 工具架在非 NexusLauncher 启动时也出现?
|
||||
|
||||
**A**: 这是正常的,因为 Maya 会保存工具架配置。解决方法:
|
||||
- 系统已配置为临时工具架,不会保存到配置文件
|
||||
- 如果仍然出现,删除 `Documents\maya\2023\prefs\shelves\shelf_NexusLauncher.mel`
|
||||
|
||||
---
|
||||
|
||||
## 🎓 学习资源
|
||||
|
||||
### Maya Python API
|
||||
- [Maya Python API 2.0 文档](https://help.autodesk.com/view/MAYAUL/2023/ENU/?guid=Maya_SDK_py_ref_index_html)
|
||||
- [Maya Commands 参考](https://help.autodesk.com/cloudhelp/2023/ENU/Maya-Tech-Docs/Commands/index.html)
|
||||
|
||||
### MEL 脚本
|
||||
- [MEL 命令参考](https://help.autodesk.com/cloudhelp/2023/ENU/Maya-Tech-Docs/Commands/index.html)
|
||||
- [工具架按钮参数说明](https://help.autodesk.com/cloudhelp/2023/ENU/Maya-Tech-Docs/Commands/shelfButton.html)
|
||||
|
||||
---
|
||||
|
||||
## 📝 最佳实践
|
||||
|
||||
1. **命名规范**
|
||||
- 使用有意义的名称
|
||||
- 避免与 Maya 内置命令冲突
|
||||
- 使用前缀区分自己的工具(如 `nexus_`, `my_`)
|
||||
|
||||
2. **错误处理**
|
||||
- 始终使用 try-except 包裹关键代码
|
||||
- 提供清晰的错误信息
|
||||
- 使用 `print()` 输出调试信息
|
||||
|
||||
3. **代码组织**
|
||||
- 将复杂工具拆分为多个模块
|
||||
- 使用函数和类组织代码
|
||||
- 添加文档字符串说明
|
||||
|
||||
4. **性能优化**
|
||||
- 避免在启动时执行耗时操作
|
||||
- 使用 `cmds.evalDeferred()` 延迟执行
|
||||
- 只加载必要的插件
|
||||
|
||||
5. **版本兼容**
|
||||
- 如果支持多个 Maya 版本,注意 API 差异
|
||||
- 在 `2023/` 和 `2025/` 目录分别维护
|
||||
- 测试不同版本的兼容性
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始示例
|
||||
|
||||
### 完整示例:添加一个"创建立方体"工具
|
||||
|
||||
**1. 创建脚本** (`scripts/create_cube_tool.py`):
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
创建立方体工具
|
||||
"""
|
||||
import maya.cmds as cmds
|
||||
|
||||
def create_custom_cube():
|
||||
"""创建一个自定义立方体"""
|
||||
# 创建立方体
|
||||
cube = cmds.polyCube(name='CustomCube', width=2, height=2, depth=2)[0]
|
||||
|
||||
# 设置颜色
|
||||
cmds.polyColorPerVertex(cube, rgb=(1, 0.5, 0), colorDisplayOption=True)
|
||||
|
||||
# 移动到原点上方
|
||||
cmds.move(0, 1, 0, cube)
|
||||
|
||||
print(f"[CreateCube] Created cube: {cube}")
|
||||
cmds.select(cube)
|
||||
|
||||
return cube
|
||||
```
|
||||
|
||||
**2. 添加工具架按钮** (编辑 `shelves/shelf_NexusLauncher.mel`):
|
||||
|
||||
```mel
|
||||
shelfButton
|
||||
-annotation "Create Custom Cube"
|
||||
-label "Cube"
|
||||
-imageOverlayLabel "CB"
|
||||
-overlayLabelBackColor 0.8 0.5 0.2 0.9
|
||||
-command "import create_cube_tool\ncreate_cube_tool.create_custom_cube()"
|
||||
-sourceType "python"
|
||||
;
|
||||
```
|
||||
|
||||
**3. 测试**
|
||||
- 启动 Maya
|
||||
- 点击工具架上的 "CB" 按钮
|
||||
- 应该会创建一个橙色的立方体
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
如果遇到问题:
|
||||
1. 检查 Maya 脚本编辑器的错误信息
|
||||
2. 查看本指南的"常见问题"部分
|
||||
3. 参考示例插件代码
|
||||
4. 查阅 Maya 官方文档
|
||||
|
||||
---
|
||||
|
||||
**祝你开发愉快!** 🎉
|
||||
Reference in New Issue
Block a user