简介:MXSPyCOM 是一套面向 3ds Max 脚本开发者的开源工具源码包,重点解决内置编辑器功能有限、MaxScript 与 Python 脚本编辑调试效率不高的问题。它通过 COM 机制把 3ds Max 与 VS Code、Sublime Text、PyCharm、Notepad++ 等外部编辑器连接起来,支持脚本实时同步执行、语法高亮、代码补全与调试,适合希望提升自动化流程和脚本开发体验的中级用户。压缩包共 35 个文件,约 396KB,包含 C# 工程与核心通信实现、ms 与 py 示例脚本、初始化 COM 服务脚本、json 工作区配置、ps1 发布脚本、说明文档与许可文件,以及大量各编辑器配置界面截图,涵盖 VS Code、Sublime、PyCharm、Notepad++、Wing、Visual Studio 与 Unreal Engine 等配置示意,便于对照完成环境搭建和参数设置。目前已有 403 人学习下载。读者可从中了解插件与外部编辑器通信的完整实现,借鉴 COM 服务初始化、示例脚本与多编辑器配置方式,并基于源码进行二次开发、兼容性调试或排错。
1. 从一次批量导出卡壳说起:MXSPyCOM 把 MaxScript 和 Python 接在哪
MXSPyCOM 这个源码包,解决的是 3ds Max 里 MaxScript 与外部 Python 之间的“最后一公里”:MaxScript 能直接操作场景,Python 擅长批处理、日志和文件校验,但两者默认不在一个进程里。MXSPyCOM 的做法是在 3ds Max 内启动一个 COM 服务,Python 侧用 pywin32 连上去发 MaxScript 命令,适合做资产批处理、渲染前检查、场景规范化的人。它不适合只想点界面的人,也不负责替你写业务脚本。第一次拿到源码,别急着批量跑,先把最小闭环打通,否则后面每个坑都会看起来像玄学。
2. 拆开源码看通信链路:MaxScript 端、COM 层和 Python 端怎么对上
源码包拿到手,最容易犯的错是直接双击.ms文件,或者在 Python 里随手Dispatch一个自己猜的 ProgID。MXSPyCOM 这类工具的核心不是某个魔法函数,而是一条固定的通信链路:3ds Max 进程里跑着 MaxScript 服务,服务注册成 COM 对象,外部 Python 通过 COM 把字符串发进去,3ds Max 在主线程执行完再把结果吐回来。链路里任何一环对不上,报错都很像“玄学”。
2.1 三个角色的最小闭环
先把角色拆清楚。3ds Max 是宿主进程,MaxScript 是宿主里的执行语言,COM 是 Windows 上的进程间通信机制,Python 是外部调度器。MXSPyCOM 的源码里通常有两端:MaxScript 端负责注册服务、暴露执行入口,Python 端负责连接、发命令、收结果。你不需要把 COM 的底层协议背下来,但要知道每个报错该看哪一端。
为什么不用纯 MaxScript 跑完整流程?因为批处理真正麻烦的地方不在“选中物体导出”这一句,而在读 CSV、比对文件哈希、写结构化日志、失败重试、跨软件调度。这些事 Python 的生态更顺手。那为什么不用 3ds Max 内置 Python 全包了?外部 Python 更适合长时间调度,也方便把 3ds Max 当成一个执行节点,而不是把整个管线塞进宿主进程。常见做法是:MaxScript 只做场景操作,Python 做任务编排和结果校验,两边用最小协议通信。
| 角色 | 运行位置 | 主要职责 | 排查时看什么 |
|---|---|---|---|
| MaxScript 入口 | 3ds Max 进程内 | 注册 COM 服务、暴露执行方法 | createOLEObject、ProgID、Listener 输出 |
| COM 层 | Windows 进程间 | 把 Python 调用转给 3ds Max | Invalid class string、权限、会话 |
| Python 客户端 | 外部解释器 | 发命令、收结果、写日志 | pywin32、方法名、返回值类型 |
还有一个容易被忽略的点:3ds Max 的场景操作最终要回到主线程。Python 发一条命令过去,MaxScript 执行期间 UI 会阻塞,脚本里如果弹了messageBox,整条链路就卡在那里,Python 侧看起来像“调用超时”。所以批量脚本里尽量不弹窗,错误写日志文件,让 Python 去读。
2.2 从源码包定位两个入口
解压源码后,别急着运行。先在目录里搜 COM 注册点和 Python 客户端入口,确认 ProgID 和方法名。Windows 上没有grep就用findstr,或者用编辑器全局搜索。下面这组命令只是定位思路,路径换成你解压后的目录。
# 在源码目录中找 MaxScript 端的 COM 注册点 grep -RIn --include="*.ms" --include="*.mcr" -E "createOLEObject|ProgID|COM" . # 找 Python 端是否已经封装好客户端 grep -RIn --include="*.py" -E "Dispatch|win32com|ProgID|Eval|Execute" .-R是递归,-n打行号,--include限定扩展名。第一条命令的重点不是把所有结果都看一遍,而是找到 MaxScript 里创建 COM 对象的那几行,记下 ProgID;第二条命令看 Python 端有没有现成封装。如果源码里已经有 Python 客户端类,优先用它,少写重复的 COM 样板。如果只有 MaxScript 端,Python 端就自己用win32com.client.Dispatch连。
| 搜到什么 | 说明 | 下一步 |
|---|---|---|
createOLEObject "XXX" | MaxScript 注册的服务名 | 把XXX记下来,Python 端必须一致 |
Python 里的Dispatch("XXX") | 已封装客户端 | 直接看类方法和参数 |
只有Execute没有Eval | 可能只执行不返回 | 需要返回值就让 MaxScript 写文件 |
| 示例脚本 | 作者留的调用样例 | 先跑样例,再改业务 |
提示:源码包里的示例脚本比文档更可信,先跑通示例,再动自己的场景。
2.3 跑通第一条命令
第一步,在 3ds Max 的 MAXScript Listener 里运行 MaxScript 入口。路径换成源码包中实际文件的位置,不要双击.ms文件,Listener 里能看到注册输出。
-- 在 3ds Max 的 MAXScript Listener 里执行 -- 把路径换成源码包中 MaxScript 入口的实际位置 fileIn @"C:/work/MXSPyCOM/startup.ms"fileIn的作用是执行脚本文件,@"..."是 verbatim 字符串,路径里的反斜杠不用层层转义,用正斜杠更稳。执行后看 Listener 有没有打印服务启动、ProgID 或端口之类的信息。如果没有输出,就在脚本里搜createOLEObject,确认它到底注册了什么名字。
第二步,Python 侧连接并自动探测方法名。不同源码包的封装不一样,有的叫Eval,有的叫Execute,有的叫Run,先探测再调用,比写死一个方法更稳。
import win32com.client PROGID = "MXSPyCOM.Application" # 以 MaxScript 端实际注册的 ProgID 为准 mx = win32com.client.Dispatch(PROGID) def get_sender(mx): for name in ("Eval", "Execute", "Run"): fn = getattr(mx, name, None) if callable(fn): print("使用 COM 方法:", name) return fn raise RuntimeError("没有找到 Eval/Execute/Run,检查源码里的 Python 客户端封装") send = get_sender(mx) # 先确认能执行一条无副作用的查询 print(send("$Box001.pos.z"))PROGID必须和 MaxScript 端注册的一致,不一致就会报Invalid class string。getattr动态取方法,避免源码换方法名后脚本直接崩。$Box001.pos.z是一条 MaxScript 表达式,如果场景里没有Box001,先创建一个 Box 再查。返回值是None时,可能你调用的是Execute这种只执行不返回的方法,换Eval,或者让 MaxScript 把结果写到文件里再由 Python 读。
第三步,做一条有副作用的验证:让 3ds Max 创建一个 Box,再查它的高度。这样能确认“命令确实进了 3ds Max”,而不是只连上了一个空壳。
send("b = Box pos:[0,0,10]") print(send("b.pos.z"))如果第二条返回10.0左右,链路就通了。参数说明:Box pos:[0,0,10]是 MaxScript 创建盒子的写法,b.pos.z取 Z 轴位置。注意不要在批量脚本里用messageBox做提示,弹窗会把主线程卡住,Python 侧只能干等。
3. 把批处理落到场景文件:参数传递、返回值与目录约定
链路通了以后,下一步是把“单条命令”变成“可重复的任务”。这一步最容易翻车的地方不是 COM 本身,而是字符串拼接、路径编码和返回值类型。我的习惯是:短命令直接走 COM,长参数落成临时.ms文件,复杂返回值落成 JSON 文件。这样 Python 和 MaxScript 之间只传路径和短字符串,排查时打开文件就能看见现场。
3.1 参数传递:短命令走 COM,长参数落临时 .ms
直接在 Python 里拼一长串 MaxScript,遇到中文路径、空格、引号、反斜杠,很容易少一个转义就语法错误。更稳的做法是 Python 生成一个临时.ms文件,把参数写进去,COM 只发一句fileIn @"..."。MaxScript 文件本身是 UTF-8,路径用正斜杠,减少转义层级。
from pathlib import Path import tempfile import win32com <p> <a href="https://download.csdn.net/download/mufenglaoshi/87529927" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>