Update
This commit is contained in:
@@ -10,6 +10,24 @@ Animation picker for Autodesk Maya 2017 (or higher)
|
||||
> A menus, markmenu and hotbox designer cross DCC.
|
||||
> https://github.com/luckylyk/hotbox_designer
|
||||
|
||||
## 🔧 版本兼容性
|
||||
|
||||
### 支持的 Maya 版本
|
||||
- **Maya 2017-2024** - 使用 PySide2
|
||||
- **Maya 2025+** - 使用 PySide6
|
||||
- **自动适配** - 运行时自动检测 Maya 版本并使用对应的 Qt 绑定
|
||||
|
||||
### Qt 兼容性
|
||||
- **PySide2** - Maya 2017-2024(自动)
|
||||
- **PySide6** - Maya 2025+(自动)
|
||||
- **Python 2/3** - 完全兼容
|
||||
|
||||
### 兼容性特性
|
||||
1. **自动 Qt 检测** - 根据 Maya 版本自动选择 PySide2 或 PySide6
|
||||
2. **API 映射** - PySide6 API 自动映射到 PySide2 兼容接口
|
||||
3. **向后兼容** - 支持旧版本 picker 文件的自动升级
|
||||
4. **跨版本数据** - Picker 文件在不同 Maya 版本间通用
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 简单快速的 picker 创建
|
||||
@@ -57,6 +75,33 @@ animation_tools.dwpicker.show(ignore_scene_pickers=True)
|
||||
5. **代码执行模板**:`import dwpicker` → `import animation_tools.dwpicker as dwpicker`
|
||||
6. 保持所有原始功能不变
|
||||
|
||||
## 💡 技术架构
|
||||
|
||||
### 核心模块
|
||||
- **main.py** - 主窗口和核心逻辑
|
||||
- **picker.py** - Picker 画布和交互
|
||||
- **designer/** - Picker 设计器模块
|
||||
- **pyside.py** - Qt 版本兼容层
|
||||
- **compatibility.py** - 数据格式兼容性处理
|
||||
|
||||
### 兼容性层次
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ DwPicker UI │
|
||||
└──────────┬──────────────────┘
|
||||
│
|
||||
┌──────────▼──────────────────┐
|
||||
│ pyside.py (兼容层) │
|
||||
│ - PySide6 (Maya 2025+) │
|
||||
│ - PySide2 (Maya 2017-2024) │
|
||||
└──────────┬──────────────────┘
|
||||
│
|
||||
┌──────────▼──────────────────┐
|
||||
│ Maya API │
|
||||
│ - maya.cmds │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
## 官方文档
|
||||
|
||||
更多信息请访问 [Official Documentation](https://dreamwall-animation.github.io/dwpicker)
|
||||
|
||||
@@ -1,16 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
PySide Compatibility Module
|
||||
自动检测并导入合适的 Qt 绑定(PySide2 或 PySide6)
|
||||
支持 Maya 2017-2026+ 所有版本
|
||||
"""
|
||||
|
||||
try:
|
||||
ModuleNotFoundError
|
||||
except NameError:
|
||||
class ModuleNotFoundError(ImportError): # Python2 backward compatilibity
|
||||
# Python 2 backward compatibility
|
||||
class ModuleNotFoundError(ImportError):
|
||||
pass
|
||||
|
||||
from maya import cmds
|
||||
|
||||
# 尝试导入 PySide6(Maya 2025+)
|
||||
try:
|
||||
if int(cmds.about(majorVersion=True)) >= 2025:
|
||||
maya_version = int(cmds.about(majorVersion=True))
|
||||
if maya_version >= 2025:
|
||||
print(f"DwPicker: Detected Maya {maya_version}, using PySide6")
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
from PySide6 import __version__
|
||||
import shiboken6 as shiboken2
|
||||
|
||||
# PySide6 兼容性映射
|
||||
QtWidgets.QShortcut = QtGui.QShortcut
|
||||
QtWidgets.QAction = QtGui.QAction
|
||||
|
||||
@@ -21,7 +36,15 @@ try:
|
||||
|
||||
QtCore.Qt.BackgroundColorRole = QtCore.Qt.BackgroundRole
|
||||
else:
|
||||
raise TypeError()
|
||||
except (ModuleNotFoundError, TypeError):
|
||||
# Maya 2017-2024 使用 PySide2
|
||||
raise TypeError("Maya version < 2025, will use PySide2")
|
||||
except (ModuleNotFoundError, TypeError, ImportError) as e:
|
||||
# 降级到 PySide2(Maya 2017-2024)
|
||||
try:
|
||||
maya_version = int(cmds.about(majorVersion=True))
|
||||
print(f"DwPicker: Detected Maya {maya_version}, using PySide2")
|
||||
except:
|
||||
print("DwPicker: Using PySide2")
|
||||
|
||||
from PySide2 import QtCore, QtGui, QtWidgets
|
||||
import shiboken2
|
||||
@@ -39,8 +39,50 @@ python("import animation_tools.mgpicker; animation_tools.mgpicker.start()");
|
||||
## 插件说明
|
||||
|
||||
- 插件文件位于 `MGPicker_Program/Plug-ins/` 目录
|
||||
- Maya 2023 使用 `MGPicker_2023x64.mll`
|
||||
- 插件会在启动时自动加载
|
||||
- 支持 Maya 2017-2026 版本
|
||||
- 插件会在启动时自动检测 Maya 版本并加载对应的插件
|
||||
|
||||
## 🔧 版本兼容性
|
||||
|
||||
### 支持的 Maya 版本
|
||||
- **Maya 2017** - MGPicker_2017x64.mll
|
||||
- **Maya 2018** - MGPicker_2018x64.mll
|
||||
- **Maya 2019** - MGPicker_2019x64.mll
|
||||
- **Maya 2020** - MGPicker_2020x64.mll
|
||||
- **Maya 2022** - MGPicker_2022x64.mll
|
||||
- **Maya 2023** - MGPicker_2023x64.mll
|
||||
- **Maya 2024** - MGPicker_2024x64.mll
|
||||
- **Maya 2025** - MGPicker_2025x64.mll
|
||||
- **Maya 2026** - MGPicker_2026x64.mll
|
||||
|
||||
### 自动版本匹配
|
||||
启动器会自动检测当前 Maya 版本并加载对应的插件:
|
||||
1. **完全匹配** - 优先使用与 Maya 版本完全匹配的插件
|
||||
2. **向下兼容** - 如果没有完全匹配,使用小于等于当前版本的最高版本插件
|
||||
3. **兜底策略** - 如果当前版本比所有可用插件都旧,使用最旧的可用插件
|
||||
|
||||
### 使用示例
|
||||
|
||||
```python
|
||||
# 自动检测版本并启动(动画师模式)
|
||||
import animation_tools.mgpicker
|
||||
animation_tools.mgpicker.start()
|
||||
|
||||
# 启动设计师模式
|
||||
animation_tools.mgpicker.start(mode=0)
|
||||
|
||||
# 仅加载插件
|
||||
animation_tools.mgpicker.load_plugin()
|
||||
```
|
||||
|
||||
## 💡 功能特性
|
||||
|
||||
- **动画选择器** - 快速选择和操作角色控制器
|
||||
- **自定义界面** - 创建自定义的 Picker 界面
|
||||
- **命令按钮** - 绑定 MEL/Python 命令到按钮
|
||||
- **姿势管理** - 保存和加载角色姿势
|
||||
- **镜像功能** - 镜像选择和姿势
|
||||
- **多版本支持** - 自动适配不同 Maya 版本
|
||||
|
||||
## 原始信息
|
||||
|
||||
|
||||
@@ -11,6 +11,78 @@ import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
|
||||
|
||||
def get_maya_version():
|
||||
"""
|
||||
获取当前 Maya 版本号
|
||||
返回格式: '2023', '2024' 等
|
||||
"""
|
||||
try:
|
||||
maya_version = cmds.about(version=True)
|
||||
# Maya 版本格式可能是 "2023" 或 "2023.1" 等,取主版本号
|
||||
return maya_version.split('.')[0]
|
||||
except Exception as e:
|
||||
print(f"Failed to get Maya version: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def find_compatible_plugin(plugin_dir, maya_version):
|
||||
"""
|
||||
查找兼容的 MGPicker 插件
|
||||
优先使用完全匹配的版本,如果没有则向下查找最接近的版本
|
||||
|
||||
Args:
|
||||
plugin_dir: 插件目录路径
|
||||
maya_version: Maya 版本号字符串,如 '2023'
|
||||
|
||||
Returns:
|
||||
插件名称(不含扩展名),如果找不到则返回 None
|
||||
"""
|
||||
if not maya_version:
|
||||
return None
|
||||
|
||||
try:
|
||||
maya_ver_int = int(maya_version)
|
||||
except ValueError:
|
||||
print(f"Invalid Maya version format: {maya_version}")
|
||||
return None
|
||||
|
||||
# 列出所有可用的插件版本
|
||||
available_versions = []
|
||||
if os.path.exists(plugin_dir):
|
||||
for filename in os.listdir(plugin_dir):
|
||||
if filename.startswith("MGPicker_") and filename.endswith(".mll"):
|
||||
# 提取版本号,例如从 "MGPicker_2023x64.mll" 提取 "2023"
|
||||
try:
|
||||
version_str = filename.replace("MGPicker_", "").replace("x64.mll", "")
|
||||
ver_int = int(version_str)
|
||||
available_versions.append((ver_int, filename.replace(".mll", "")))
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if not available_versions:
|
||||
return None
|
||||
|
||||
# 按版本号排序
|
||||
available_versions.sort(reverse=True)
|
||||
|
||||
# 首先尝试完全匹配
|
||||
for ver, plugin_name in available_versions:
|
||||
if ver == maya_ver_int:
|
||||
print(f"Found exact match plugin for Maya {maya_version}: {plugin_name}")
|
||||
return plugin_name
|
||||
|
||||
# 如果没有完全匹配,使用小于等于当前版本的最高版本
|
||||
for ver, plugin_name in available_versions:
|
||||
if ver <= maya_ver_int:
|
||||
print(f"Using compatible plugin for Maya {maya_version}: {plugin_name} (version {ver})")
|
||||
return plugin_name
|
||||
|
||||
# 如果当前版本比所有可用版本都旧,使用最旧的版本
|
||||
oldest_ver, oldest_plugin = available_versions[-1]
|
||||
print(f"Warning: Maya {maya_version} is older than available plugins. Using oldest: {oldest_plugin} (version {oldest_ver})")
|
||||
return oldest_plugin
|
||||
|
||||
|
||||
def get_mgpicker_path():
|
||||
"""Get MG-Picker Studio installation path"""
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
@@ -18,25 +90,52 @@ def get_mgpicker_path():
|
||||
|
||||
|
||||
def load_plugin():
|
||||
"""Load MGPicker plugin"""
|
||||
plugin_name = "MGPicker_2023x64"
|
||||
"""
|
||||
Load MGPicker plugin
|
||||
自动检测 Maya 版本并加载对应的插件
|
||||
"""
|
||||
# 获取当前 Maya 版本
|
||||
maya_version = get_maya_version()
|
||||
if not maya_version:
|
||||
print("Warning: Could not determine Maya version")
|
||||
return False
|
||||
|
||||
print(f"Detected Maya version: {maya_version}")
|
||||
|
||||
# 查找兼容的插件
|
||||
mgpicker_path = get_mgpicker_path()
|
||||
plugin_dir = os.path.join(mgpicker_path, "MGPicker_Program", "Plug-ins")
|
||||
plugin_name = find_compatible_plugin(plugin_dir, maya_version)
|
||||
|
||||
if not plugin_name:
|
||||
print(f"Error: No compatible MGPicker plugin found for Maya {maya_version}")
|
||||
return False
|
||||
|
||||
# Check if plugin is already loaded
|
||||
if cmds.pluginInfo(plugin_name, query=True, loaded=True):
|
||||
print(f"MGPicker plugin already loaded: {plugin_name}")
|
||||
return True
|
||||
try:
|
||||
if cmds.pluginInfo(plugin_name, query=True, loaded=True):
|
||||
print(f"MGPicker plugin already loaded: {plugin_name}")
|
||||
return True
|
||||
except RuntimeError:
|
||||
# Plugin not registered yet, will try to load
|
||||
pass
|
||||
|
||||
# Get the plugin path from mgpicker module
|
||||
mgpicker_path = get_mgpicker_path()
|
||||
plugin_path = os.path.join(mgpicker_path, "MGPicker_Program", "Plug-ins", f"{plugin_name}.mll")
|
||||
# Get the plugin path
|
||||
plugin_path = os.path.join(plugin_dir, f"{plugin_name}.mll")
|
||||
plugin_path = plugin_path.replace("\\", "/")
|
||||
|
||||
if not os.path.exists(plugin_path):
|
||||
print(f"Error: Plugin file not found: {plugin_path}")
|
||||
return False
|
||||
|
||||
try:
|
||||
cmds.loadPlugin(plugin_path)
|
||||
print(f"MGPicker plugin loaded: {plugin_path}")
|
||||
print(f"MGPicker plugin loaded successfully: {plugin_path}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Failed to load MGPicker plugin: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -59,6 +59,64 @@ studiolibrary.main()
|
||||
- 支持 Maya 2017 及更高版本
|
||||
- 需要 PySide2 或 PySide6(Maya 自带)
|
||||
|
||||
## 🔧 版本兼容性
|
||||
|
||||
### 支持的 Maya 版本
|
||||
- **Maya 2017+** - 支持所有现代版本的 Maya
|
||||
- **自动适配** - 运行时自动检测 Maya 环境和 Qt 版本
|
||||
|
||||
### Qt 兼容性
|
||||
Studio Library 使用 `Qt.py` 兼容层,支持多种 Qt 绑定:
|
||||
- **PySide6** - Maya 2025+ (优先)
|
||||
- **PySide2** - Maya 2017-2024 (优先)
|
||||
- **PyQt5** - 备用方案
|
||||
- **PySide** - Maya 2014-2016 (备用)
|
||||
- **PyQt4** - 备用方案
|
||||
|
||||
### 兼容性特性
|
||||
1. **自动 Qt 检测** - 运行时检测可用的 Qt 绑定
|
||||
2. **Maya 环境检测** - 自动识别是否在 Maya 中运行
|
||||
3. **跨版本支持** - 同一代码在不同 Maya 版本中运行
|
||||
4. **Python 2/3 兼容** - 使用 `six` 库实现 Python 2 和 3 的兼容
|
||||
|
||||
### Qt 绑定优先级
|
||||
```
|
||||
PySide6 > PySide2 > PyQt5 > PySide > PyQt4
|
||||
```
|
||||
|
||||
可通过环境变量 `QT_PREFERRED_BINDING` 指定优先使用的绑定:
|
||||
```python
|
||||
import os
|
||||
os.environ['QT_PREFERRED_BINDING'] = 'PySide2'
|
||||
```
|
||||
|
||||
## 💡 技术架构
|
||||
|
||||
### 核心模块
|
||||
- **studiolibrary** - 核心库逻辑,与 DCC 无关
|
||||
- **studiolibrarymaya** - Maya 特定集成
|
||||
- **mutils** - Maya 工具函数(动画、姿势等)
|
||||
- **studioqt** - Qt UI 组件
|
||||
- **studiovendor** - 第三方依赖(Qt.py, six)
|
||||
|
||||
### 兼容性层次
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ Studio Library UI │
|
||||
└──────────┬──────────────────┘
|
||||
│
|
||||
┌──────────▼──────────────────┐
|
||||
│ Qt.py (兼容层) │
|
||||
│ - PySide6/PySide2/PyQt5 │
|
||||
└──────────┬──────────────────┘
|
||||
│
|
||||
┌──────────▼──────────────────┐
|
||||
│ Maya API │
|
||||
│ - maya.cmds │
|
||||
│ - maya.OpenMaya │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
## 许可证
|
||||
|
||||
GNU Lesser General Public License v3.0
|
||||
|
||||
54
2023/scripts/animation_tools/studiolibrary/launcher.py
Normal file
54
2023/scripts/animation_tools/studiolibrary/launcher.py
Normal file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Studio Library Launcher
|
||||
用于从工具架快速启动 Studio Library
|
||||
支持所有 Maya 版本
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def LaunchStudioLibrary():
|
||||
"""
|
||||
启动 Studio Library 主界面
|
||||
自动检测 Maya 版本和 Qt 绑定
|
||||
"""
|
||||
try:
|
||||
# 获取 Studio Library 路径
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# 确保路径在 sys.path 中
|
||||
if current_dir not in sys.path:
|
||||
sys.path.insert(0, current_dir)
|
||||
|
||||
# 导入并启动 Studio Library
|
||||
import studiolibrary
|
||||
|
||||
# 打印版本信息
|
||||
print(f"Studio Library version: {studiolibrary.version()}")
|
||||
|
||||
# 检测 Maya 环境
|
||||
if studiolibrary.isMaya():
|
||||
print("Running in Maya environment")
|
||||
else:
|
||||
print("Running in standalone mode")
|
||||
|
||||
# 启动主窗口
|
||||
window = studiolibrary.main()
|
||||
|
||||
print("Studio Library launched successfully")
|
||||
|
||||
return window
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed to launch Studio Library: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
LaunchStudioLibrary()
|
||||
Reference in New Issue
Block a user