- _refresh_messages: widget pool reuse to avoid layout cascade → QWebEngineView crash - viewer.html: QWebChannel bridge, texture resize, burst render, gl.finish - live2d_view.py: debug checkpoints, playMotion/setExpression render-on-demand - main.py: Chromium flags --no-sandbox --in-process-gpu --disable-gpu-rasterization --ignore-gpu-blocklist - scheduler.py: test_reminder re-enabled - docs: complete root cause analysis
164 lines
5.3 KiB
Markdown
164 lines
5.3 KiB
Markdown
# Live2D 问题分析与修复报告 v6
|
||
|
||
**日期:** 2026-05-21
|
||
**状态:** 已定位根因,修复中
|
||
|
||
---
|
||
|
||
## 一、问题排查过程
|
||
|
||
### 1. 初始问题:Live2D 内容无法展示
|
||
|
||
通过 HTTP 服务器内置方案解决了 WebEngine `file://` fetch 限制问题。
|
||
|
||
### 2. 第二问题:PIXI.js 渲染无法找到合适的 renderer
|
||
|
||
在 Firefox 中测试发现 "Unable to auto-detect a suitable renderer",因此放弃 PIXI.js,改用原生 WebGL。
|
||
|
||
### 3. 第三问题:模型显示为空白
|
||
|
||
用 PIXI 时只显示 texture,不显示人物。换用原生 WebGL 后仍然只显示空白 canvas。
|
||
|
||
---
|
||
|
||
## 二、根因分析
|
||
|
||
### 发现:纹理文件只有 1/3 有内容
|
||
|
||
```
|
||
texture_00.png: 4096x4096
|
||
Center pixel RGBA: 0 0 0 0 (透明)
|
||
Non-transparent pixels: 5,370,078 / 16,777,216 (约32%)
|
||
```
|
||
|
||
`texture_00.png` 只有约 32% 的像素是不透明的,中心区域是透明的。这意味着 **texture_00.png 是分图层存储的,不是一张完整立绘**。
|
||
|
||
### 发现:drawables API 结构
|
||
|
||
```
|
||
model.drawables.count = 307
|
||
model.drawables.vertexCounts[i] = 每 drawable 的顶点数
|
||
model.drawables.vertexPositions = Float32Array, 所有 drawable 的顶点坐标 (2 * sum(vertexCounts))
|
||
model.drawables.vertexUvs = Float32Array, 所有 drawable 的 UV 坐标
|
||
model.drawables.indexCounts[i] = 每 drawable 的索引数
|
||
model.drawables.indices = Uint16Array, 所有 drawable 的索引
|
||
model.drawables.drawOrders[i] = 渲染顺序
|
||
model.drawables.textureIndices[i] = 纹理索引 (0 或 1)
|
||
model.drawables.opacities[i] = 透明度 (0~1)
|
||
```
|
||
|
||
**关键数据**:
|
||
- drawables.count = 307
|
||
- vc[0] = 15(第一个 drawable 有 15 个顶点)
|
||
- op[0] = 1(完全透明?不,应该是完全不透明)
|
||
|
||
### 渲染逻辑问题
|
||
|
||
代码中 `model.textures` 是 undefined(返回 undefined),所以当前用 `window._loadedTextures[texIdx]` 代替。这个能工作。
|
||
|
||
问题在于 **drawables.vertexPositions 的索引计算**:
|
||
|
||
```javascript
|
||
var vertexOffset = 0;
|
||
for(var j = 0; j < i; j++) {
|
||
vertexOffset += drawables.vertexCounts[j];
|
||
}
|
||
```
|
||
|
||
这里的 `vertexOffset` 是顶点数偏移,但 `vertexPositions` 是 Float32Array,每个顶点 2 个 float(x, y)。
|
||
|
||
当前代码:
|
||
```javascript
|
||
var px = posArr[(vertexOffset + v) * 2];
|
||
var py = posArr[(vertexOffset + v) * 2 + 1];
|
||
```
|
||
|
||
这是对的,`vertexOffset` 是顶点偏移,乘以 2 后才是 Float32Array 中的位置。
|
||
|
||
但问题是 `vertexCounts` 和 `opacities` 的访问方式。日志显示:
|
||
- `drawables.vertexCount exists: undefined`
|
||
- `drawables.opacities exists: object`
|
||
|
||
这说明 `drawables.vertexCount` 不是直接属性(可能是方法或计算属性),而 `drawables.opacities` 是对象。
|
||
|
||
所以 `drawables.vertexCounts[0]` 应该能工作(前面调试输出 vc0 = 15)。
|
||
|
||
---
|
||
|
||
## 三、当前状态
|
||
|
||
### 已修改的文件
|
||
|
||
1. **`ui/live2d_view.py`**
|
||
- 内置 HTTP 服务器(CORS 支持)解决 file:// fetch 问题
|
||
- 模型数据通过 HTTP JSON 文件注入
|
||
- `window._assetsDir` 设为 HTTP 地址
|
||
|
||
2. **`assets/live2d/march7/viewer.html`**
|
||
- 移除 PIXI.js,改用原生 WebGL
|
||
- 自定义 vertex/fragment shader
|
||
- 按 drawOrders 排序渲染所有 307 个 drawable
|
||
- 模型更新用 `model.update()`(Model.prototype.update)
|
||
|
||
### 待确认问题
|
||
|
||
1. **纹理是否正确**:texture_00.png 的 32% 不透明像素是否是角色内容?需要对比 texture_01.png 的数据
|
||
2. **drawables 数据访问**:`drawables.vertexCounts[i]` 确实能返回 15,但渲染仍然空白
|
||
|
||
---
|
||
|
||
## 四、下一步修复计划
|
||
|
||
### 方案 A:简化测试
|
||
|
||
先用一个固定四边形测试 WebGL 是否正常工作,不经过 Live2D Core:
|
||
|
||
```javascript
|
||
// 测试代码:画一个简单的红色三角形
|
||
var vbuf = gl.createBuffer();
|
||
gl.bindBuffer(gl.ARRAY_BUFFER, vbuf);
|
||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0, 1,0, 0.5,1]), gl.STATIC_DRAW);
|
||
// 用 program 画...
|
||
```
|
||
|
||
如果红色三角形能显示,说明 WebGL 本身没问题,问题在 Live2D 数据访问。
|
||
|
||
### 方案 B:直接读取纹理测试
|
||
|
||
用 Canvas 2D 把 texture_00.png + texture_01.png 合成为一张图,看是否能显示角色:
|
||
|
||
```javascript
|
||
// 两个纹理叠加显示
|
||
ctx.drawImage(texture00, 0, 0);
|
||
ctx.drawImage(texture01, 0, 0);
|
||
```
|
||
|
||
如果 Canvas 2D 能显示说明纹理本身没问题,问题在 WebGL 渲染路径。
|
||
|
||
---
|
||
|
||
## 五、关键文件清单
|
||
|
||
| 文件 | 用途 |
|
||
|------|------|
|
||
| `ui/live2d_view.py` | Python 端:HTTP 服务器、模型注入 |
|
||
| `assets/live2d/march7/viewer.html` | JS 端:WebGL 渲染 |
|
||
| `assets/live2d/march7/live2dcubismcore.min.js` | Live2D Core SDK |
|
||
| `assets/live2d/march7/March 7th.moc3` | 模型二进制(3.7MB) |
|
||
| `assets/live2d/march7/march 7th.model3.json` | 模型描述 |
|
||
| `assets/live2d/march7/March 7th.4096/texture_00.png` | 纹理 0(4096x4096,约32%内容) |
|
||
| `assets/live2d/march7/March 7th.4096/texture_01.png` | 纹理 1(未测试) |
|
||
|
||
---
|
||
|
||
## 六、已验证可行
|
||
|
||
- [x] 内置 HTTP 服务器解决 file:// 协议限制
|
||
- [x] 模型数据成功加载(307 drawables)
|
||
- [x] 纹理加载成功(2个 4096x4096)
|
||
- [x] WebGL 初始化成功
|
||
- [x] Shader program 创建成功
|
||
- [x] Live2D Core SDK 加载成功(v6.0.1)
|
||
- [x] `model.drawables.vertexCounts[0]` = 15
|
||
- [x] `model.drawables.opacities[0]` = 1
|
||
- [ ] 实际渲染显示角色(待解决) |