之前偶尔就会在别人的博客上看到 Live2D 看板娘效果,就... 有点眼馋了。
于是就想:
# 前言
本来昨天就在想,将 live2D 相关的东西都弄完,然后将本篇文章写完,以及再写个『年中』总结。
结果果然是人算不如情况,预期总是与实际有所差异,昨天整了一天 live2D。
主要是到处找模型,然后挑选看得上眼的,以及写些自定义修改代码花的时间有点长。
另外为了方便本地预览模型,还整了两个 Python 脚本来辅助,一个用于批量重名名,将入口 json 文件重命名为 index.json,另一个用于批量替换预览:点一下控制窗口,然后刷一下页面就切到下一个模型这种。
今天又加了点新功能,修了点昨天没注意到的 Bug,然后修修改改时间又跑了,今天最多把本篇博客写完就差不多了 (或者可能也写不完,得等明天补充了)。
总结呢怎么着也还是得拖到明天去,毕竟除了本篇博客之外,新下载了十几个 G 的 live2D 模型,还等着我弄到看板娘上去看呢。
# 过程
如果按照 Hexo 来讲的话,大概有三种方式:
- 使用 Hexo 插件,直接
npm install --save hexo-helper-live2d
安装 Hexo 插件,Github 地址为 hexo-helper-live2d - 使用第三方做好的 Live2D 代码,然后作自定义修改
- 拉取官方 SDK,自己撸一个
个人采用了第二种方式,使用 live2d-widget,并在此基础上作自定义修改。
将其从 Github 上拉下来,放在自己博客的 source 目录下,然后在 head.ejs 处引用 autoload.js 即可。
<!-- 自定义看板娘 -->
<% if (theme.live2d.enable){ %>
<script src="/live2d-widget/autoload.js"></script>
<% } %>
当然,这是最基础和简单的做法,单纯这样,确实可以弄出看板娘,但是模型之类的全都是示例库的。
此时想要做到更换自定义的看板娘,有三种做法:
- 按照官方文档自己搭建一个服务器
- 直接将模型放在 Hexo source 目录加载
- 按照说明文档 fork 示例库,或者自己建立一个模型库,然后修改 model_list.json 列表
第一种就不考虑了,没服务器,而且弄起来也挺麻烦。
第二种会增加博客项目本身大小,每次 deploy 可都是一份消耗,所以也不考虑。
因此个人开始选择了第一种。
分别 fork 以下两个库:
- live2d-widget
- live2d_api
注:如果觉得这样比较麻烦,也可直接拉取 live2d-widget 库,然后将其文件复制到 Hexo source 目录使用。
fork 之后,发现就算修改了 model_list.json,但是使用 jsdeliver 拉到的 model_list.json 模型配置表还是旧的。
可能是因为 jsdeliver 缓存原因,于是改成支持本地加载配置,然后整理模型。
加载模型列表的代码改在了 autoload.js 初始化的地方,可以直接配置绝对路径,也可以配置相对路径:
initWidget({ | |
waifuPath: live2d_path + "waifu-tips.json", | |
// 模型列表配置路径,如果不配置则默认为 cdnPath 路径下同名文件 | |
modelListPath: live2d_path + "model_list.json", | |
//apiPath: "https://live2d.fghrsh.net/api/", | |
//live2d 模型仓库地址 | |
cdnPath: "https://cdn.jsdelivr.net/gh/CWHISME/live2d_api@master/" | |
}); |
效果如下:
# 关于点击反馈
# 事件
由于网上搜集模型,多数都是提取来的。其配置的 json 有时候默认选项可能无法触发反馈。
辨别方法很简单:当你发现配置中有 flick_head、tap_body 相关 motion 配置,但是点击脑袋或者身体都没反应的话,就说明模型默认不支持。
此时如果想要的话,就需要自己手动设置对应点击区域及其动作了。
如下所示:
"hit_areas_custom":{
"head_x":[-0.3, 0.8],
"head_y":[-0.04, 0.43],
"body_x":[-0.4, 0.29],
"body_y":[0.17, -0.38]
}
该配置代表自定义了两个点击区域 『头』 『身体』,当点击对应区域时,分别会触发 “flick_head”、“tap_body” 的 Motion 事件
其中 hit_areas_custom 字段的 head_x 和 body_x 定义了头部和身体的 HIT_AREA 的左上角的坐标,head_y 和 b ody_y 定义了右下角的坐标。
获取坐标的方式可以通过修改 live2d.min.js 中 DEBUG_LOG:!0 实现。
注:如果想直接通过明文 ID 取区域,也可以在 i.prototype.getDrawDataIndex
处打断点,找明文 ID。
内置支持的 Motion 字段有:
- flick_head:点击脑袋触发
- tap_body:点击身体触发
- sleepy: 50000 毫秒后自动播放,index.json 没配置的话,会报错
另外还有『Tap face』会触发播放表情,不过网上下载的模型,基本上都是没有表情的。因此个人对 live2D.min.js 做了点修改:当没有表情时,点击脑袋触发 “flick_head” motion 事件。
另外修改了播放的判断代码,不会由于 motion 优先级而导致后续点击被忽略。
另外经过对 live2D.min.js 代码的查询,目前这个插件用到的 live2d sdk, 好像就支持这么三个触发 motion 事件了。互动事件就两个,一个点击身体,一个点击脑袋。
# 音效
可以参考 nepnep 模型,在点击触发事件中,添加 sound 字段即可。
# 自定义修改
如果有对修改版更有兴趣的,也可以 fork 我修改后的库。
- live2d-widget
- live2d_api
其中 model_list.json 增加 defaultModelInfo、sizeZoomList 字段 (还有个 backup 字段可以忽略,没有实际作用)
- defaultModelInfo:用于配置默认的模型路径
- sizeZoomList:配置模型可以放大的大小列表
具体还修改了些啥,看了下记录,大概修改有:
- 支持直接配置本地模型表
- 增加模型表初始化模型配置
- 优化随机模型方式,避免反复随机到同一模型,在同一角色没有多个模型时,隐藏换装按钮
- 增加放大 live2d 模型展示区域的功能
- 增加 Python 小工具方便预览
# Python 小工具
- ModifyFileName.py: 用于一键重命名,将网上下载的 .model.json 格式后缀的入口文件重命名为 index.json
- ModifyFileStr.py:用于更换模型,递归执行,将指定目录下所有存在 index.json 文件的入口进行依次替换入预览代码,回车键更换。
注:后续 ModifyFileStr.py 经过修改后,有预览时选择备份则同时修改 model.json 的功能,如果使用 ModifyFileStr 那么 ModifyFileName 就属于可选项了。
使用方法是:
首先反注释 waifu-tips.js 中代码 loadlive2d("live2d", `/@live2D@/`);
,并注释下方正常加载代码,然后修改 ModifyFileStr.py 中的开头路径配置即可。
# 需要修改脚本路径 | |
jsfilePath = r"F:/Hexo/HexoBlog/Hexo/source/live2d-widget/waifu-tips.js" | |
# 模型路径 | |
live2DPath = r"F:/Hexo/live2dModels/Live2d-model/" | |
# 如果更换模型时,输入了 “1”,则会同时将当前模型复制到此目录 | |
live2DBackupPath = r"F:/Hexo/live2dModels/fav/" | |
#模型的网络路径 --- 或者如果是直接拖到 Hexo/Source 目录的话,就是相对路径,如 “/live2D/” | |
rootDir = "/live2D/" | |
# 标记符号 | |
defaultName = "/@live2D@/" |
其中:
- 配置相对路径:需要将模型放 source 目录
- 绝对路径:一个绝对的网络路径,如从 jsdeliver 拉取的
然后执行 py 脚本,按回车会照顺序切换模型。
# 搭建本地文件服务测试
注 1:可以使用 HFS 搭建本地文件服务,这样就不用把模型拖进 Hexo sourse 目录了,不然可想而知,十几个 G 大小的模型,Hexo 铁定处理不过来的。HFS 添加好对应目录后,网页 js 就可以直接访问了,非常方便。
注 2:实际试过 HFS 之后,发现会有报跨域访问调用问题...
因为跨域访问问题,因此文件服务器还是换成 Nginx 了。
在 nginx.conf 配置 server 字段中添加一列新的 location 配置即可:
location /Live2d-model {
# 模型绝对路径
alias F:/Hexo/live2dModels/Live2d-model/;
allow all;
autoindex on;
}
当然,Nginx 如果用只是这样使用默认配置依然还是会有跨域访问问题,因此配置表中还需要加一行:
location /Live2d-model {
# 模型绝对路径
alias F:/Hexo/live2dModels/Live2d-model/;
allow all;
autoindex on;
# 允许跨域访问
add_header 'Access-Control-Allow-Origin' '*';
# 禁止缓存,避免本地有问题,修改之后无法即时刷新
add_header Cache-Control no-store;
add_header Pragma no-cache;
}
配置完成之后,如果之前启动过 Nginx 服务,则需要使用 nginx -s reload 命令重新加载配置。
# 重新加载配置
nginx -s reload
# 正常关闭
nginx -s quit
# 快速关闭服务
nginx -s stop
然后 Python 代码中, rootDir 路径修改为 Nginx 访问路径:
# 需要修改脚本路径 | |
jsfilePath = r"F:/Hexo/HexoBlog/Hexo/source/live2d-widget/waifu-tips.js" | |
# 模型路径 | |
live2DPath = r"F:/Hexo/live2dModels/Live2d-model/" | |
# 如果更换模型时,输入了 “1”,则会同时将当前模型复制到此目录 | |
live2DBackupPath = r"F:/Hexo/live2dModels/fav/" | |
# 模型的网络路径 --- 或者如果是直接拖到 Hexo/Source 目录的话,就是相对路径,如 “/live2D/” | |
rootDir = "http://127.0.0.1/Live2d-model/" | |
# 标记符号 | |
defaultName = "/@live2D@/" |
执行 Python 代码:
刷新页面,就可以看到可以正常访问,模型也加载出来了。
问题解决了之后,还是有点成就感的嘛。不过,等我过两天忘了就想不起来了。
# 其它模型库
因为注意到点击网上找的模型的时候,有时候会报错,如下:
然后就考虑是不是模型的问题,于是想到了昨天导出找模型找到的一个庞大无比的 live2D 模型库,到如今都还在维护。看日期前些天都在更新。
昨天也是为感觉这库太大,暂且放弃了
然后呢,正好因为这仓库里边也有之前找的模型,于是今天想替换下来看看,结果分支不能单独拉,就全拉了...
整个模型库达到了十几个 G!虽然 readme 写着有相关工具可以单独下载的,不过在我试图直接拉取的时候,github 竟然达到了满速,十几 M 每秒?!
虽然凭借 github 都经常连不上这种经验感觉不对劲,不过既然速度这么快,于是放弃思考,就让它继续拉了。
所有可以想见,待会我还要筛模型,找好好康的,应该还需要不短的时间的了。
都有报错,最后还是在 live2d.min.js 对应方法处加了个容错判断。
另外这个模型库还有很多是 moc3 格式的,目前这个插件想要用的话,就得改使用的 live2d 渲染插件和代码了。比如同时支持两者模型,根据不同模型调用不同的渲染?不过 moc 的已经够用了。其他的模型暂时也不想看了,等以后什么时候想搞再说吧。
# 问题
# js 修改 css 样式
在使用 js 修改元素 style 的时候,必须符合元素原本规范,比如:设置元素的长宽。
之前我是这样用的
var panel = document.getElementById("live2d"); | |
panel.style.height = size; | |
panel.style.width = size; |
结果一直不生效,调试又得出结论找到的元素也没问题,就很为难。
后边左思右想,各种赋值方法也试过,都没法改变,网上也搜索不出什么东西。
后边看着 css 代码发呆的时候,偶然注意到 css 代码赋值参数是有『px』后缀,于是抱着试一试的心态,结果成了!
async function zoomModelSize(add = false) { | |
if (!modelList) await loadModelList(); | |
var sizeZoomIndex = sessionStorage.getItem("sizeZoomIndex"); | |
if (add) { | |
sizeZoomIndex++; | |
showMessage("好的啦 ~~~", 2000, 9); | |
} | |
if (sizeZoomIndex >= modelList.sizeZoomList.length||!(typeof(sizeZoomIndex) == 'number' && !isNaN(sizeZoomIndex))) | |
sizeZoomIndex = 0; | |
var outBoundSize = modelList.sizeZoomList[sizeZoomIndex] + 35; | |
if (outBoundSize > window.innerHeight || outBoundSize > window.innerWidth) { | |
sizeZoomIndex = 0; | |
showMessage("你的浏览器界面太小了,再大一点可就装不下啦 ~", 5000, 9); | |
} | |
var size = modelList.sizeZoomList[sizeZoomIndex] | |
var panel = document.querySelector("#waifu #live2d"); | |
panel.style.height = size + "px"; | |
panel.style.width = size + "px"; | |
sessionStorage.setItem("sizeZoomIndex", sizeZoomIndex); | |
} |
这个问题是在我修改这次博客使用到的 live2d 插件代码,准备加一个『循环放大 / 缩小』效果的时候发现的。
毕竟 js 这东西,以及网页这块,也都是个人在整自己博客的时候用到过,有问题就查文档或搜索。
大概因为这个问题是属于『常识』?碰到过的大概知道,js style 会自动筛除不合法格式的代码,但是给个提示也好么,既没有报错,也不给提示,所说说这些弱类型语言有时候就让人喜欢不起来。
# vscode 快捷键
Shift+Alt 可以像 Vs 一样竖行选择。
# 关于 js 获取移动端高宽
直接使用想要获取屏幕长宽使用 screen.width 或者获取浏览器长宽使用 window.innerWidth 貌似都无法获取到正确结果。
其中获取屏幕长宽 screen.width 可以通过在页面开始加上 meta 标志,使其在移动端也可以生效:
<meta name="viewport" content="height=device-height, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"> |
而 window.innerWidth 在移动端好像是不行的。所以可以改用 document.body.clientWidth 获取浏览器长宽。
# 结语
如同前言所说,开始本来只是打算用插件弄好就收工,计划的是端午节的第一天把 live2D 弄好,并且把本文写了,另外再写个『年中』总结。
结果后边为了测试网上找的模型,又写了两个 Python 小工具,大概就是递归查找模型,然后修改 js 读取代码处的加载路径。
最初也是采用将模型放在 source 目录,然后使用相对路径读取。
后面不是下载了一个超大型模型库么,十几个 G,太大了,直接放 Hexo 里边,硬盘哗啦啦响,半天反应不过来。
于是又配置 nginx 文件服务,使得可以本地读取。
以及一些感觉想改的地方也想改改,搞着搞着,就在改改改这块儿一去不复返了。
今天已经是端午节第三天了,明天就又要上班了。端午节三天,花了可不少时间在这上边,本来计划的学习下 .NetCore 的都没能搞!现在想想还有点不可思议。
另外这两天感觉就是:VSCode 真好用!智能提示真爽快,写 Python、js 之类都真是够方便的,就像 Vs Studio 写 C# 似的。
昨天还是没收完... 今天是 6 月 14 日端午节,终于补充完毕了。
参考文章:
Hexo(sakura)添加 live2d 看板动画
给博客添加能动的看板娘 (Live2D)- 将其添加到网页上吧
Live2DViewerEX 文档