- _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
5.3 KiB
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 的索引计算:
var vertexOffset = 0;
for(var j = 0; j < i; j++) {
vertexOffset += drawables.vertexCounts[j];
}
这里的 vertexOffset 是顶点数偏移,但 vertexPositions 是 Float32Array,每个顶点 2 个 float(x, y)。
当前代码:
var px = posArr[(vertexOffset + v) * 2];
var py = posArr[(vertexOffset + v) * 2 + 1];
这是对的,vertexOffset 是顶点偏移,乘以 2 后才是 Float32Array 中的位置。
但问题是 vertexCounts 和 opacities 的访问方式。日志显示:
drawables.vertexCount exists: undefineddrawables.opacities exists: object
这说明 drawables.vertexCount 不是直接属性(可能是方法或计算属性),而 drawables.opacities 是对象。
所以 drawables.vertexCounts[0] 应该能工作(前面调试输出 vc0 = 15)。
三、当前状态
已修改的文件
-
ui/live2d_view.py- 内置 HTTP 服务器(CORS 支持)解决 file:// fetch 问题
- 模型数据通过 HTTP JSON 文件注入
window._assetsDir设为 HTTP 地址
-
assets/live2d/march7/viewer.html- 移除 PIXI.js,改用原生 WebGL
- 自定义 vertex/fragment shader
- 按 drawOrders 排序渲染所有 307 个 drawable
- 模型更新用
model.update()(Model.prototype.update)
待确认问题
- 纹理是否正确:texture_00.png 的 32% 不透明像素是否是角色内容?需要对比 texture_01.png 的数据
- drawables 数据访问:
drawables.vertexCounts[i]确实能返回 15,但渲染仍然空白
四、下一步修复计划
方案 A:简化测试
先用一个固定四边形测试 WebGL 是否正常工作,不经过 Live2D Core:
// 测试代码:画一个简单的红色三角形
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 合成为一张图,看是否能显示角色:
// 两个纹理叠加显示
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(未测试) |
六、已验证可行
- 内置 HTTP 服务器解决 file:// 协议限制
- 模型数据成功加载(307 drawables)
- 纹理加载成功(2个 4096x4096)
- WebGL 初始化成功
- Shader program 创建成功
- Live2D Core SDK 加载成功(v6.0.1)
model.drawables.vertexCounts[0]= 15model.drawables.opacities[0]= 1- 实际渲染显示角色(待解决)