Unity MCP 材质操作指南
最后更新: 2026-05-03
适用环境: Unity 2022.3.22f1 + MCP Server 3.2.4
着色器: lilToon (Hidden/lilToonOutline)
概述
本文档记录通过 MCP 协议远程操作 Unity Editor 材质球的完整工作流,覆盖 lilToon 着色器多层贴图叠加、中文路径编码问题、MCP 认证等核心场景。
MCP 服务器协议
1. 初始化会话
必须先调用 initialize 获取 Session ID:
init_payload = {
"jsonrpc": "2.0",
"id": 0,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "hermes", "version": "1.0.0"}
}
}
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream"
}
response = requests.post(base_url + "/mcp", json=init_payload, headers=headers)
session_id = response.headers.get("Mcp-Session-Id")
⚠️ 关键协议要求:
- Accept 头必须同时包含 application/json 和 text/event-stream
- 服务器返回 406 Not Acceptable 表示 Accept 头不完整
- 后续所有请求必须携带 Mcp-Session-Id 头
2. 执行 C# 代码
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "execute_code",
"arguments": {
"action": "execute",
"code": "/* C# code here */"
}
}
}
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
"Mcp-Session-Id": session_id
}
3. 解析响应
3. 解析响应
```python# Server-Sent Events (SSE) 格式响应 data = json.loads(response.text.split('data: ')[1].split('\r\n')[0]) result = json.loads(data['result']['content'][0]['text'])
result['data']['result'] 包含 C# 代码返回值
---
## 中文路径编码问题
### 问题现象
Unity AssetDatabase 返回中文路径时为 UTF-8 编码乱码:
| 实际路径 | AssetDatabase 返回 |
|---------|-------------------|
| `Assets/!改变` | `Assets/!æ¹å¤` |
| `Assets/!改变/R18カスタムディーテール` | `Assets/!æ¹å¤/R18ãã¯ã¹ãã£ã¼` |
### 解决方案:使用 GUID 加载资产
**不要直接使用中文路径**,改用 GUID 两步加载:
```csharp
// 步骤 1: 扫描获取 GUID
var guids = UnityEditor.AssetDatabase.FindAssets("");
foreach (var guid in guids) {
var path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains("!")) {
// 记录 guid|type|path 映射
}
}
// 步骤 2: 用 GUID 加载资产(完全避开中文路径)
var r18Guid = "afa7bb1e008aaa44d812dc35a3a97afa";
var path = UnityEditor.AssetDatabase.GUIDToAssetPath(r18Guid);
var tex = UnityEditor.AssetDatabase.LoadAssetAtPath<Texture2D>(path);
lilToon 材质球贴图规则
;
var tex = UnityEditor.AssetDatabase.LoadAssetAtPath---
## lilToon 材质球贴图规则### 多层贴图叠加机制
lilToon 支持多层贴图叠加,**额外贴图通常不是替换 `_MainTex`**,而是作为叠加层添加:
| 新贴图类型 | 目标插槽 | 启用开关 | 混合模式参数 | 说明 |
|-----------|---------|---------|-------------|------|
| 第二层身体/服装贴图 | `_Main2ndTex` | `_UseMain2ndTex = 1` | `_Main2ndTexBlendMode` | 叠加在原始贴图上,0=Normal |
| 第三层细节贴图 | `_Main3rdTex` | `_UseMain3rdTex = 1` | `_Main3rdTexBlendMode` | 额外叠加层 |
| AO/阴影遮罩 | `_ShadowStrengthMask` | `_UseShadow = 1` | `_ShadowStrength` | 控制阴影强度分布 |
| MatCap 材质捕获 | `_MatCapTex` | `_UseMatCap = 1` | `_MatCapBlend` | 改变表面光泽/质感 |
| 第二 MatCap | `_MatCap2ndTex` | `_UseMatCap2nd = 1` | `_MatCap2ndBlend` | 额外材质捕获层 |
| 法线贴图 | `_BumpMap` | `_UseBumpMap = 1` | `_BumpScale` | 表面凹凸细节 |
| 自发光贴图 | `_EmissionMap` | `_UseEmission = 1` | `_EmissionBlend` | 发光效果 |
### 贴图推断规则表
| 文件名关键词 | 推断类型 | 目标插槽 | 优先级 |
|-------------|---------|---------|-------|
| `AO`, `Occlusion`, `ShadowMask` | 环境光遮蔽 | `_ShadowStrengthMask` | 高 |
| `Matcap`, `MatCap` | 材质捕获 | `_MatCapTex` | 高 |
| `Normal`, `Bump` | 法线贴图 | `_BumpMap` | 高 |
| `Emission`, `Emissive` | 自发光 | `_EmissionMap` | 高 |
| `Body`, `Cloth`, 日期戳 | 主体贴图 | **先试** `_Main2ndTex`(叠加),不对再试 `_MainTex`(替换) | 中 |
missionMap` | 高 |
| `Body`, `Cloth`, 日期戳 | 主体贴图 | **先试** `_Main2ndTex`(叠加),不对再试 `_MainTex`(替换) | 中 |### 应用步骤(完整代码)
```csharp
// 1. 加载材质球
var bodyMat = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(
"Assets/Cazalis/Material/Cazalis_Body.mat");
// 2. 用 GUID 加载贴图
var r18Guid = "afa7bb1e008aaa44d812dc35a3a97afa";
var r18Path = UnityEditor.AssetDatabase.GUIDToAssetPath(r18Guid);
var r18Tex = UnityEditor.AssetDatabase.LoadAssetAtPath<Texture2D>(r18Path);
// 3. 应用到第二层(叠加)
bodyMat.SetFloat("_UseMain2ndTex", 1);
bodyMat.SetTexture("_Main2ndTex", r18Tex);
bodyMat.SetFloat("_Main2ndTexBlendMode", 0); // 0=Normal
// 4. 保存修改
UnityEditor.EditorUtility.SetDirty(bodyMat);
UnityEditor.AssetDatabase.SaveAssets();
材质球修改最佳实践
✅ 正确做法
// 直接加载并修改材质球文件(永久生效)
var mat = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(path);
mat.SetTexture("_Main2ndTex", newTex);
UnityEditor.EditorUtility.SetDirty(mat);
UnityEditor.AssetDatabase.SaveAssets();
❌ 错误做法
// renderer.material 会在编辑模式创建实例,导致材质泄露
var mat = renderer.material; // 触发 "Instantiating material" 警告
Console 警告信息:
Instantiating material due to calling renderer.material during edit mode. This will leak materials into the scene. You most likely want to use renderer.sharedMaterial instead.
ll leak materials into the scene. You most likely want to use renderer.sharedMaterial instead.`
---## 工具环境区分
| 工具 | 执行环境 | 语言 | 用途 |
|---|---|---|---|
execute_code (Hermes) |
Python 沙箱 | Python | 发送 HTTP 请求调用 MCP 服务器 |
execute_code (Unity MCP) |
Unity Editor | C# | 操作 Unity 资产和场景 |
调用链:
Hermes Python → HTTP Request → Unity MCP Server → C# Code → Unity Editor
完整工作流程
flowchart TD
A[建立 MCP 连接] --> B[Initialize 获取 Session ID]
B --> C[扫描目标资产获取 GUID]
C --> D[读取材质球属性列表]
D --> E{判断贴图类型}
E -->|AO/阴影| F[→ _ShadowStrengthMask]
E -->|MatCap| G[→ _MatCapTex]
E -->|主体贴图| H[先试 _Main2ndTex 叠加]
F --> I[保存材质球]
G --> I
H --> J{效果正确?}
J -->|是| I
J -->|否| K[改用 _MainTex 替换]
K --> I
I --> L[验证材质球状态]
- 建立 MCP 连接 → 调用
initialize获取 Session ID - 扫描目标资产 → 用 GUID 避开中文路径问题
- 读取材质球属性 → 确认着色器类型和可用插槽
- 应用贴图 → 按 lilToon 规则选择正确插槽
- 验证状态 → 读取材质球确认贴图已加载
- 保存 →
SetDirty+SaveAssets
常见问题排查
| 问题 | HTTP 状态码 | 原因 | 解决方案 |
|---|---|---|---|
| 贴图加载返回 NULL | - | 中文路径乱码 | 改用 GUID 加载资产 |
| Not Acceptable | 406 | Accept 头不完整 | 添加 text/event-stream 到 Accept |
| Bad Request | 400 | 缺少 Session ID | 先 initialize 获取 Session ID |
| Console 红色警告 | - | 使用了 renderer.material |
改用 sharedMaterial 或直接修改文件 |
| 贴图显示不对 | - | 插槽选错 | 查看 lilToon 规则表,尝试 _Main2ndTex |
| 代码执行成功但返回空 | - | C# 代码未 return | 确保代码末尾有 return result; |
附录:Cazalis 模型材质结构
in2ndTex|
| 代码执行成功但返回空 | - | C# 代码未 return | 确保代码末尾有return result;` |
附录:Cazalis 模型材质结构### 模型层级
Cazalis
├── Body_Base (SkinnedMeshRenderer)
│ └── Cazalis_Body.mat
│ ├── _MainTex → Cazalis_Body.png (原始身体)
│ ├── _Main2ndTex → R18 叠加层
│ ├── _ShadowStrengthMask → AOmap.png
│ └── _MatCapTex → matcap 1.png
└── Body (SkinnedMeshRenderer)
├── Cazalis_Face.mat → _MainTex → Cazalis_Face.png
└── Cazalis_Face_Alpha.mat → _MainTex → Cazalis_Face.png
原始贴图清单
| 贴图 | 路径 | 用途 |
|---|---|---|
Cazalis_Body.png |
Assets/Cazalis/Texture/ |
原始身体贴图 |
Cazalis_Face.png |
Assets/Cazalis/Texture/ |
脸部贴图 |
Cazalis_Hair.png |
Assets/Cazalis/Texture/ |
头发贴图 |
Cazalis_Cloth.png |
Assets/Cazalis/Texture/ |
服装贴图 |
Cazalis_Butterfly.png |
Assets/Cazalis/Texture/ |
蝴蝶装饰贴图 |
MatCap 贴图清单
| 贴图 | 路径 | 用途 |
|---|---|---|
Cazalis_Matcap_Hair.png |
Assets/Cazalis/Texture/Matcap/ |
头发材质捕获 |
Cazalis_Matcap_Hairpin.png |
Assets/Cazalis/Texture/Matcap/ |
发饰材质捕获 |
Cazalis_Matcap_Pearl.png |
Assets/Cazalis/Texture/Matcap/ |
珍珠材质捕获 |
Cazalis_Matcap_Shoes.jpg |
Assets/Cazalis/Texture/Matcap/ |
鞋子材质捕获 |
Cazalis_Matcap_Whitemetal.png |
Assets/Cazalis/Texture/Matcap/ |
白金属材质捕获 |