Files
EzVibe/docs/live2d_issue_report.md
e2hang 798e5c2f7d checkpoint: segfault root cause analysis + Live2D stability fixes
- _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
2026-05-23 13:33:58 +08:00

5.3 KiB
Raw Permalink Blame History

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 个 floatx, y

当前代码:

var px = posArr[(vertexOffset + v) * 2];
var py = posArr[(vertexOffset + v) * 2 + 1];

这是对的,vertexOffset 是顶点偏移,乘以 2 后才是 Float32Array 中的位置。

但问题是 vertexCountsopacities 的访问方式。日志显示:

  • 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

// 测试代码:画一个简单的红色三角形
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 纹理 04096x4096约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] = 15
  • model.drawables.opacities[0] = 1
  • 实际渲染显示角色(待解决)