给网页添加一只 Live2D 看板娘
2021-07-24 / 猫村 あおい 🍭

二次元!

简介

Live2D 看板娘是很多 二次元 博客的标配。这只猫猫手上刚好有 なちょ猫 的模型,当然要给网站加上可爱的猫娘!

首先想到的是大家都在用的插件:fghrsh/live2d_demo 或者 stevenjoezhang/live2d-widget

stevenjoezhang/live2d-widget 的效果

但是这两个插件用的 Live2D 是旧版本的,不能加载 moc3 模型。

如何给博客添加一只猫娘

看板娘的结构(?

以 stevenjoezhang/live2d-widget 为例,这玩意本质是 waifu-tips.js 创建 waifu div,div 里面有纸片人本体 canvas 和对话气泡等小部件,waifu-tips.js 负责加载 Live2D 模型和控制小部件。

waifu-tips.js 调用 live2d.min.js 里面的 loadModel 函数加载模型,live2d.min.js 是 Live2D 的控制器,而 Live2D 的核心是个闭源的东西。

这个 live2d.min.js 对应的 Live2D 版本比较低。其实这个项目是个很老的坑,可以看见 Github 上有很多版本,但是好像很少人升级 Live2D Core。

现在要升级的话,就要把整个 live2d.min.js 换掉。

然后看到这样一篇 笔记:live2d4.0 sdk 博客园网页动画

这篇作者给出了一个百度网盘成品链接,当然还有修改过程。 那么就照着做了。

下载 Live2D Demo 并运行

从这里开始喵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3.sdk
官方sdk api:https://docs.live2d.com/cubism-sdk-tutorials/sample-build-web/

3.1运行实例
需要环境:node.js TypeScript Webpack (TypeScript和Webpack安装慢可以使用淘宝镜像)
编辑器打开sdk项目,具体的目录是什么内容可以看项目根目录下的 README.md 文件(windows用户可以使用Typora软件打开.md文件)

打开控制台跳转到Demo文件夹下输入 npm install 命令(安装了淘宝镜像的可以使用cnpm install命令安装的快一些)
install命令会根据package.json 文件中的配置下载安装需要的插件
这里已经安装好了,安装好后在Demo文件夹下回多出一个 node_modules 文件夹
运行 npm run build命令

运行完成后会在Demo文件夹下生成一个 dist 文件夹,该文件夹下有一个bundle.js,这个就是集合打包好的js文件,在index.html文件中有引用
运行 npm run serve命令,启动服务器

4.在浏览器中输入 http://localhost:5000/Samples/TypeScript/Demo/ 就能看到

可以看到,浏览器里面已经有了可爱的 Live2D 纸片人了!我们只要把她放进 waifu div 里面那个 canvas 就好了!

修改 Live2D Demo

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
3.2源码
想把一些配置放到html中,比如画布(canvas)的大小位置,模型保存的路径等等信息
否则每次需要改变模型的时候都要改代码,重新编译,麻烦
lappdefine.ts //定义基本的参数
lappdelegate.ts //初始化,释放资源,事件绑定
lapplive2dmanager.ts //模型的管理类,进行模型生成和废弃、事件的处理、模型切换。
lappmodel.ts //模型类,定义模型的基本属性
lappal.ts //读取文件,抽象文件数据(算是工具类)
lappsprite.ts //动画精灵类,(学python时知道了精灵类和精灵组)
lapptexturemanager.ts//纹理管理类,进行图像读取和管理的类
lappview.ts //视图类,生成模型的图像被lapplive2dmanager管理
main.ts //主程序启动程序
touchmanager.ts //事件的管理类(比如移动鼠标,点击鼠标,触摸屏触碰等)

这里只说重要修改点,如果想理解部分原理的,可以看上面那篇文章,里面有中文注释。当然看 Demo 里面的官方日语注释也可以。

主函数 (main.ts)

1
2
3
4
5
6
7
8
// 浏览器装入后的处理(打开页面)
window.onload = (): void => {
// create the application instance
if (LAppDelegate.getInstance().initialize() == false) {
return;
}
LAppDelegate.getInstance().run();
};

这个 main.ts 覆盖了 window.onload 使得网页载入完成就启动 LAppDelegate,由于我们要与 waifu-tips.js 整合,所以改成导出这个函数,以后再调用。

1
2
3
4
5
6
7
8
9
export const win: any = window

// js 里面调用 l2d_initInstance() 就开始运行 Live2D
win.l2d_initInstance = () => {
if (LAppDelegate.getInstance().initialize() == false) {
return;
}
LAppDelegate.getInstance().run();
};

LAppDelegate.getInstance().initialize()(lappdelegate.ts)

1.使用现有的 canvas

1
2
3
4
5
6
7
8
9
10
11
12
13
// キャンバスの作成
// canvas = document.createElement('canvas');
// if (LAppDefine.CanvasSize === 'auto') {
// this._resizeCanvas();
// } else {
// canvas.width = LAppDefine.CanvasSize.width;
// canvas.height = LAppDefine.CanvasSize.height;
// }

canvas = <HTMLCanvasElement>document.getElementById("live2d"); // index.html中的id=live2d的画布
canvas.width = canvas.width;
canvas.height = canvas.height;
canvas.toDataURL("image/png");

2.不要再添加 canvas

1
2
// キャンバスを DOM に追加
// document.body.appendChild(canvas);

onResize()

1
2
3
4
5
public onResize(): void {
//this._resizeCanvas(); 这个会变形
this._view.initialize();
this._view.initializeSprite();
}

LAppDelegate.getInstance().run()

1
2
// 清除彩色缓冲区和深度缓冲区  (加上这一句会导致有些浏览器背景变成黑色,而不是透明)
// gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

部分设置 (lappdefine.ts)

这里有一些参数,我们要导出到 js 供运行时调整。

1
2
3
4
5
6
7
8
export const win: any = window

win.l2d_setConfig = function (resourcesPath: string, backImageName: string, modelDir: string[]) {
ResourcesPath = resourcesPath;
BackImageName = backImageName;
ModelDir = modelDir;
ModelDirSize = modelDir.length;
}

更换模型 (main.ts)

1
2
3
win.l2d_changeModel = (no) => {
LAppLive2DManager.getInstance().changeScene(no)
}

外部调用

修改好之后 html 引入 bundle.js 做测试,大概这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Live2DCubismCore script -->
<script src="https://cdn.jsdelivr.net/gh/wangstong/mycdn/live2d/js/live2dcubismcore.js"></script>
<!-- Build script -->
<script src="bundle.js"></script>

<!-- 这里可以定义画布的大小位置 -->
<canvas id="live2d" width="500" height="500" class="live2d" style="position: fixed; opacity: 1; right: 0px; bottom: -20px; z-index: 99999; pointer-events: none;"></canvas>

<script type="text/javascript">
var resourcesPath = 'https://cdn.jsdelivr.net/gh/wangstong/mycdn/live2d/model/'; // 指定资源文件(模型)保存的路径
var backImageName = ''; // 指定背景图片
var modelDir = ['Hiyori']; // 指定需要加载的模型
l2d_setConfig(resourcesPath, backImageName, models); // 模型设置
l2d_initInstance(); // 开始显示模型
</script>

然后纸片人就显示在 canvas 里面了!

整合到 waifu-tips.js

这个 waifu-tips.js 可以看出来被 114514 人改过喵,过于混乱所以只说加载纸片人的重点:

增加以下

1
2
3
4
5
6
7
8
9
10
function displayLive2dModel(cdnBase, models, modelId) {
const resourcesPath = `${cdnBase}/model3/`; // 指定资源文件(模型)保存的路径
const backImageName = ''; // 指定背景图片
l2d_setConfig(resourcesPath, backImageName, models); // 初始化模型
if (!l2d_ok) {
l2d_ok = true
l2d_initInstance()
}
l2d_changeModel(modelId)
}

修改以下

1
2
3
4
5
6
7
8
9
10
    async function loadModel(modelId, modelTexturesId, message) {
localStorage.setItem("modelId", modelId);
localStorage.setItem("modelTexturesId", modelTexturesId);
displayLive2dModel(cdnBase, modelList.models, modelId) // 重点
}
async function loadOtherModel() {
let modelId = localStorage.getItem("modelId");
const index = (++modelId >= modelList.models.length) ? 0 : modelId;
loadModel(index, 0, modelList.messages[index]);
}

注意:这里没有实现同一个人物的换装(modelTexturesId)

渲染尺寸

1
<canvas id="live2d" width="500" height="500" class="live2d"></canvas>

这里的 width 和 height 为渲染尺寸,修改 css 里面 canvas 大小时需要一起修改避免出现模糊。

加载

到这里主要工作就完成了。

加载 js 时记得加载 live2d core 和 bundle.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 加载 waifu.css live2d.min.js waifu-tips.js
if (screen.width >= 768) {
Promise.all([
loadExternalResource(live2d_path + "waifu.css", "css"),
loadExternalResource(live2d_path + "live2dcubismcore.js", "js"),
loadExternalResource(live2d_path + "bundle.js", "js")
loadExternalResource(live2d_path + "waifu-tips.js", "js")
]).then(() => {
initWidget({
waifuPath: live2d_path + "waifu-tips.json",
//apiPath: "https://live2d.fghrsh.net/api/",
cdnPath: "https://cdn.jsdelivr.net/gh/fghrsh/live2d_api/"
});
});
}

live2dcubismcore.js + bundle.js 一共 350kB+ 而旧版的 live2d.min.js 只有 100 多 kB

总结

  1. 由于写的太烂,本博客的看板娘并不会完整开源。
  2. nacho 猫猫可爱!!!

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 许可协议。
本文链接:
https://nekoquq.github.io/posts/0008.html