live2d web笔记之一:官方SDK尝试

news/2025/3/17 14:42:54/

最近没太多事情,想要给群里建一个网站。想来不知道放些什么内容进去,建好站之后姑且先放一个live2d的看板娘。因此产生了这个live2d网页开发的尝试。

第一次尝试,从live2d的官方原生的SDK入手。在我之前已经有很多大佬做成了,这里先放我的成果,再放本人从0开始实现的过程。

一、成品

~浼钤茶会~群内共享站~ (meiqianhime.com)http://www.meiqianhime.com/

前端新手,学了没多久,所以做的网页很烂,轻喷orz

二、过程

开发环境:

Live2D Cubism 4.1 #来自官方,live2d模型的编辑器和查看器。

vscode #官方指定的代码编辑器

node.js TypeScript Webpack #必须环境

python+Flask 本人使用的网页应用框架,可以换其他

1.下载SDK,准备模型

登录官网,下载webSDK。官网需要翻墙,不然会比较慢。

Live2D Cubismhttps://www.live2d.com/

选择【各种下载】-【live2D SDK下载与功能介绍】,

在弹出的页面中找【Live2D Cubism SDK for Web】并下载。

接下来是准备模型。官方提供了几种现成的模型可供下载。本人葱厨,所以下载了初音未来的模型。之后会尝试用自己的模型来做,可能会放在以后的笔记中。

2.运行SDK示例项目

安装vscode、nodejs和TypeScript,并做好相关环境配置。

将下载好的SDK压缩包解压并用vscode打开,在README.md文件中可以看到项目结构的说明。

在终端中cd到Samples/TypeScript/Demo,这是官方的示例项目。

运行指令npm install,根据文件package.json中信息安装项目所需插件。

运行指令npm run build进行项目打包,

完成后会在Demo文件夹下生成dist文件夹,

里面有打包好的bundle.js文件,用于之后的移植开发。

运行指令npm run serve运行服务,打开终端给出的本地链接进入示例页面。 

终端中按ctrl-c退出服务。

3.加入自己准备的模型

3.1 模型方面的准备

打开资源文件夹Samples/Recourses,放入准备好的模型。

修改文件夹的名字与里面的cmo3文件相同,双击打开。

 这里想要做一个点击交互,点一下miku就会有动作的那种。

点击【建模】--【图形网格】--【创建触碰检测用途的图形网格】,

把红框框套在想要触发点击交互的地方,

然后把左边检查器中的名称改成Body。(不改也行)

然后点上面的【编辑纹理集 】

弹出的窗口中找到【用于触碰检测的图像】,右键添加到纹理集。

 

完成后ctrl-s保存,然后选择【文件】--【导出运作档】--【导出为moc3文件】,将模型导出。

接下来打开.can3文件进行动画处理。

miku的模型有附带做好的动画,如果是自定义模型,可以看相关教程做一两个简单的动画。

打开后选择【文件】--【导出运作档】--【导出动态文件】,导出所有的动画文件到指定文件夹。

这里创建了新文件夹anime用于存储动画文件。

接下来打开官方的模型查看器CubismViewer4,将模型的moc3文件拖入。

点开左边的【hitAreas】,将定义好的点击框命名为Body(首字母大写) 

然后把刚刚的动画文件拖入,选择想要触发的动画,将组名改为TapBody。

然后ctrl-s保存文件,把生成的model3.json文件覆盖原有文件。

处理完之后,模型文件夹应该有以下结构。

3.2 向Demo中加入自己的模型

vscode打开Samples/TypeScript/Demo/src/lappdefine.ts,找到存放模型名的列表。

在列表最末端添加自己的模型的文件夹名。

如果不想显示其他模型,可以只留自己的模型名字。

// モデル定義---------------------------------------------
// モデルを配置したディレクトリ名の配列
// ディレクトリ名とmodel3.jsonの名前を一致させておくこと
//在这里修改,添加'miku'
export const ModelDir: string[] = ['Haru', 'Hiyori', 'Mark', 'Natori', 'Rice', 'miku'];
export const ModelDirSize: number = ModelDir.length;// 外部定義ファイル(json)と合わせる
export const MotionGroupIdle = 'Idle'; // アイドリング
export const MotionGroupTapBody = 'TapBody'; // 体をタップしたとき

 保存之后,使用指令npm run build重新打包,

然后使用指令npm run serve 运行服务。

点击齿轮更换模型,就可以看到自己的模型显示在网页上了= =

到这里大概完成了三分之一,可以稍微喘口气了= =

4. 源码修改

我们最终想要一个id为live2d的canvas画布,当我们在html中创建它时就会显示live2d的内容。

基于此对demo中的源码进行修改。

这里主要参考这几位大佬的方法进行修改。第一篇的大佬有比较详细的讲代码,这里不多说。

(10条消息) 笔记:live2d4.0 sdk 博客园网页动画_weixin_44128558的博客-CSDN博客_live2d生成https://blog.csdn.net/weixin_44128558/article/details/104792345(10条消息) live2d(Web SDK 4.x)Web看板娘进阶_仰望星空的sun的博客-CSDN博客_live2d sdkhttps://blog.csdn.net/qq_37735413/article/details/119413744

4.1 lappdefine.ts

将变量ResourcesPath、BackImageName、ModelDir、ModelDirSize的变量声明从const改为let。

// 相対パス
// 相对路径 打完包移植的时候要修改它
export let ResourcesPath = '../../Resources/';// モデルの後ろにある背景の画像ファイル
// 背景图片 不是很想要,就把它赋了空值。
export let BackImageName = '';// 歯車
// 画面右上角的齿轮的图片
export let GearImageName = 'icon_gear.png';// 終了ボタン
// 结束按钮 没见过这东西?
export let PowerImageName = 'CloseNormal.png';// モデル定義---------------------------------------------
// モデルを配置したディレクトリ名の配列
// ディレクトリ名とmodel3.jsonの名前を一致させておくこと
// 模型定义
// 配置模型的目录名的列表
// 模型的目录名应该与model3.json的文件名一致
// 这里只想要一个模型,所以只留下了miku的模型。
export let ModelDir: string[] = ['miku'];
export let ModelDirSize: number = ModelDir.length;

 然后在文件末尾添加代码

export const win: any = windowwin.initDefine=function(resourcesPath: string, backImageName: string, modelDir: string[]){ResourcesPath = resourcesPath;BackImageName = backImageName;ModelDir = modelDir;ModelDirSize = modelDir.length;
}

 4.2 main.ts

注释掉window.onresize,否则live2d模型会随着窗口改变大小。

/*** Process when changing screen size.*/
// window.onresize = () => {
//   if (LAppDefine.CanvasSize === 'auto') {
//     LAppDelegate.getInstance().onResize();
//   }
// };

 4.3 lappdelegate.ts

首先找到getInstance.initialize()进行修改。

public initialize(): boolean {// キャンバスの作成// 生成画布// 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");// glコンテキストを初期化// 初始化gl上下文// @ts-ignoregl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');if (!gl) {alert('不能初始化 WebGL. 浏览器不支持.');gl = null;document.body.innerHTML ='浏览器不支持 <code>&lt;canvas&gt;</code> 元素.';// gl初期化失敗return false;}// キャンバスを DOM に追加// 向DOM添加画布// document.body.appendChild(canvas);if (!frameBuffer) {frameBuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);}// 透過設定// 透明度设定gl.enable(gl.BLEND);gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);const supportTouch: boolean = 'ontouchend' in canvas;if (supportTouch) {// タッチ関連コールバック関数登録// 触摸模式下的回调函数canvas.ontouchstart = onTouchBegan;// canvas.ontouchmove = onTouchMoved;window.ontouchmove = onTouchMoved;canvas.ontouchend = onTouchEnded;canvas.ontouchcancel = onTouchCancel;} else {// マウス関連コールバック関数登録// 鼠标点击模式下的回调函数canvas.onmousedown = onClickBegan;// canvas.onmousemove = onMouseMoved;window.onmousemove = onMouseMoved;canvas.onmouseup = onClickEnded;}// AppViewの初期化// 初始化AppViewthis._view.initialize();// Cubism SDKの初期化// 初始化SDKthis.initializeCubism();return true;}

 然后找到onMouseMoved函数进行修改。

/*** マウスポインタが動いたら呼ばれる。* 鼠标移动时触发*/
function onMouseMoved(e: MouseEvent): void {// if (!LAppDelegate.getInstance()._captured) {  //判断鼠标是否单击//   return;// }if (!LAppDelegate.getInstance()._view) {LAppPal.printMessage('view notfound');return;}const rect = (e.target as Element).getBoundingClientRect();// const posX: number = e.clientX - rect.left;// const posY: number = e.clientY - rect.top;//这里是模型身体随着鼠标摆动的数值//使用canvas.getBoundingClientRect()读取画布实时位置,加入身体位置的计算,// 方便移动画布之后模型能依然根据和鼠标的相对位置摆动let posX: number = e.clientX - canvas.getBoundingClientRect().left;let posY: number = e.clientY - window.innerHeight + canvas.height + canvas.getBoundingClientRect().top;// 图像在网页的坐下角,简单处理坐标将超过画布边界坐标就等与边界坐标posX = (posX > canvas.width) ? canvas.width : posX;posY = (posY < 0) ? 0 : posY;LAppDelegate.getInstance()._view.onTouchesMoved(posX, posY);
}

 然后找到run()函数,将gl.clear注释掉。

      // カラーバッファや深度バッファをクリアする// 清除彩色缓冲区和深度缓冲区// gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

4.4 lappview.ts

找到initializeSprite()函数进行修改。

  /*** 画像の初期化を行う。*/public initializeSprite(): void {const width: number = canvas.width;const height: number = canvas.height;const textureManager = LAppDelegate.getInstance().getTextureManager();const resourcesPath = LAppDefine.ResourcesPath;let imageName = '';// 背景画像初期化imageName = LAppDefine.BackImageName;if(imageName != "" && imageName != null){ //如果指定了背景图片,就加载// 非同期なのでコールバック関数を作成const initBackGroundTexture = (textureInfo: TextureInfo): void => {const x: number = width * 0.5;const y: number = height * 0.5;const fwidth = textureInfo.width * 2.0;const fheight = height * 0.95;this._back = new LAppSprite(x, y, fwidth, fheight, textureInfo.id);};textureManager.createTextureFromPngFile(resourcesPath + imageName,false,initBackGroundTexture);}// 歯車画像初期化// imageName = LAppDefine.GearImageName;// const initGearTexture = (textureInfo: TextureInfo): void => {//   const x = width - textureInfo.width * 0.5;//   const y = height - textureInfo.height * 0.5;//   const fwidth = textureInfo.width;//   const fheight = textureInfo.height;//   this._gear = new LAppSprite(x, y, fwidth, fheight, textureInfo.id);// };// textureManager.createTextureFromPngFile(//   resourcesPath + imageName,//   false,//   initGearTexture// );// シェーダーを作成if (this._programId == null) {this._programId = LAppDelegate.getInstance().createShader();}}

 4.5 index.html

在body里插入一个id为live2d的canvas。

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="viewport" content="width=1900"><title>TypeScript HTML App</title><style>html, body {margin: 0;overflow: hidden;}</style><!-- Pollyfill script --><script src="https://unpkg.com/core-js-bundle@3.6.1/minified.js"></script><!-- Live2DCubismCore script --><script src = "../../../Core/live2dcubismcore.js"></script><!-- Build script --><script src = "./dist/bundle.js"></script>
</head>
<body><canvas id="live2d" width="600" height="600" class="live2d"></canvas>
</body>
</html>

全部处理好之后,重新打包并运行。

npm run build

npm run serve

 5.打包完成后的移植

完成上述步骤后,开始尝试在普通的网页中加入live2d。

移植只移动模型文件夹和几个js文档,故对移植环境要求不高。

wamp或者flask什么的应该都可以。

这里使用flask的开发环境来移植live2d到原有项目。

需要的东西有:

1.模型文件夹

2.live2dcubismcore.js和live2dcubismcore.js.map,在core文件夹里。

3.bundle.js,在dist文件夹里。

网页名:浼钤茶会

static                    存放静态资源文件css                     存放css文件meiqiancss1.csssrc                     存放js文件meiqianjs1.jsresource                存放模型和图片文件
templates                 存放网页文件index.html              登入界面
app.py                    用于启动flask网页应用

把模型文件夹扔进resource文件夹,其余三个文件扔进src文件夹。

打开bundle.js,ctrl-f搜索ResourcesPath,找到资源路径并修改为现在的resource。

exports.ResourcesPath = '../static/Resources/';
exports.BackImageName = '';
exports.GearImageName = 'icon_gear.png';
exports.PowerImageName = 'CloseNormal.png';
exports.ModelDir = ['miku'];

然后打开index.html,在head中加入三个js文件的引用。

    <!-- Pollyfill script --><script src="https://unpkg.com/core-js-bundle@3.6.1/minified.js"></script><!-- Live2DCubismCore script --><script src = "../static/src/live2dcubismcore.js"></script><!-- Build script --><script src = "../static/src/bundle.js"></script>

运行app.py,完成。

以下是各种源码。

app.py

from flask import Flask, render_template, request, Response, send_from_directoryapp = Flask(__name__)@app.route('/', methods=['GET', 'POST'])
def main():return render_template('index.html')if __name__ == '__main__':app.run()

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>~浼钤茶会~群内共享站~</title><link rel="icon" href="../static/resources/favicon.ico"><link rel="stylesheet" href="../static/css/meiqiancss1.css">
</head><body><div id="live2d-main"><canvas id="live2d" height=600 class="live2d"></canvas></div><div class="header" style="background-image: url('../static/resources/bg2.JPG')"><h1>浼钤茶会</h1><p>尚在建设中的茶会大厅~</p></div><div class="navbar"><a href="#" onclick="building()">主页</a><a href="#" onclick="building()">花园</a><a href="index.html">大厅</a><a href="#" onclick="building()">图书馆</a><a href="#" onclick="building()">call吧</a><a href="#" onclick="building()">浼钤姬的房间</a><a href="#" onclick="building()">留言板</a><a href="#" class="right" onclick="building()">个人房间</a></div><div class="row"><div class="side"><h1>建设中。。。</h1></div><div class="main"><h1>建设中。。。</h1></div></div><div class="footer"><p>made by 某电饭锅司机</p></div><!-- Pollyfill script --><script src="https://unpkg.com/core-js-bundle@3.6.1/minified.js"></script><!-- Live2DCubismCore script --><script src = "../static/src/live2dcubismcore.js"></script><!-- Build script --><script src = "../static/src/bundle.js"></script><script src="../static/src/meiqianjs1.js"></script>
</body>
</html>

meiqiancss1.css

* {box-sizing: border-box;
}/* body 样式 */
body {font-family: Arial;margin: 0;
}/* 标题 */
.header {padding: 80px;text-align: center;background: #1abc9c;color: white;
}/* 标题字体加大 */
.header h1 {font-size: 40px;
}/* 导航 */
.navbar {overflow: hidden;background-color: #333;
}/* 导航栏样式 */
.navbar a {float: left;display: block;color: white;text-align: center;padding: 14px 20px;text-decoration: none;
}/* 右侧链接*/
.navbar a.right {float: right;
}/* 鼠标移动到链接的颜色 */
.navbar a:hover {background-color: #ddd;color: black;
}/* 列容器 */
.row {display: -ms-flexbox; /* IE10 */display: flex;-ms-flex-wrap: wrap; /* IE10 */flex-wrap: wrap;
}.row div{min-height: 500px;max-height: 2000px;
}/* 创建两个列 */
/* 边栏 */
.side {-ms-flex: 30%; /* IE10 */flex: 30%;background-color: #f1f1f1;padding: 20px;
}/* 主要的内容区域 */
.main {-ms-flex: 70%; /* IE10 */flex: 70%;background-color: white;padding: 20px;
}/* 测试图片 */
.fakeimg {background-color: #aaa;width: 100%;padding: 20px;
}/* 底部 */
.footer {padding: 20px;text-align: center;background: #ddd;
}.footer p{font-family: '黑体', serif;
}#live2d-main {position : absolute;padding: 10px;bottom: 5px;left:5px;
}#live2d {/* position : absolute; */}/* 响应式布局 - 在屏幕设备宽度尺寸小于 700px 时, 让两栏上下堆叠显示 */
@media screen and (max-width: 700px) {.row {flex-direction: column;}
}/* 响应式布局 - 在屏幕设备宽度尺寸小于 400px 时, 让导航栏目上下堆叠显示 */
@media screen and (max-width: 400px) {.navbar a {float: none;width: 100%;}
}

meiqianjs1.js

function building() {alert("正在建设中。。");
}//Make the DIV element draggagle:
dragElement(document.getElementById("live2d-main"));function dragElement(elmnt) {var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;if (document.getElementById(elmnt.id )) {/* if present, the header is where you move the DIV from:*/document.getElementById(elmnt.id ).onmousedown = dragMouseDown;} else {/* otherwise, move the DIV from anywhere inside the DIV:*/elmnt.onmousedown = dragMouseDown;}function dragMouseDown(e) {e = e || window.event;// get the mouse cursor position at startup:pos3 = e.clientX;pos4 = e.clientY;document.onmouseup = closeDragElement;// call a function whenever the cursor moves:document.onmousemove = elementDrag;}function elementDrag(e) {e = e || window.event;// calculate the new cursor position:pos1 = pos3 - e.clientX;pos2 = pos4 - e.clientY;pos3 = e.clientX;pos4 = e.clientY;// set the element's new position:elmnt.style.top = (elmnt.offsetTop - pos2) + "px";elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";}function closeDragElement() {/* stop moving when mouse button is released:*/document.onmouseup = null;document.onmousemove = null;}
}

项目包:https://pan.baidu.com/s/1IYMhwrQxuCObrPimwyn1KA 
提取码:6xqb 
--来自百度网盘超级会员V3的分享

 三、一些问题

1.首先在运行的时候,发现了这个报错

去提示的位置查看 发现是已经被注释掉的齿轮的相关代码。

将其注释掉,重新打包bundles.js装入,问题解决 

2.编写js代码实现了画布的移动,但是当画布离开原来的位置时,点击触发的交互会变得不敏感。

暂时没什么精力处理这个问题,以后再看。

3.使用官方的SDK进行开发,在点击交互的问题上好像只看到了一个Body点击框的情况,在示例中没有看到同时有多个点击框判定不同事件的模型。在实际尝试中,也没能做出想要的结果。之后如果还不行的话,就换个非官方的SDK试试吧。。


http://www.ppmy.cn/news/488389.html

相关文章

hisiv3519交叉编译live555

先下载live555源码 wget http://www.live555.com/liveMedia/public/live555-latest.tar.gz 解压 tar xzvf live555-latest.tar.gz 将config.linux 文件复制一份为config.hi3519 COMPILE_OPTS $(INCLUDES) -I. -O2 -DSOCKLEN_Tsocklen_t -D_LARGEFILE_SOURCE1 -D_FILE_OFFSET_…

LIVE555 RTSP RTP/RTCP协议介绍

LIVE555 RTSP、RTP/RTCP协议介绍 一、概述 RTSP(Real-Time Stream Protocol )是一种基于文本的应用层协议&#xff0c;在语法及一些消息参数等方面&#xff0c;RTSP协议与HTTP协议类似。 RTSP被用于建立的控制媒体流的传输&#xff0c;它为多媒体服务扮演“网络远程控制”的角…

live555转发H264实时流实现直播的实现

本文介绍了在树莓派上通过live555实现了从树莓派的USB端口获取到的H264码流的实时直播的功能。 GitHub&#xff1a;https://github.com/SkyDreamcode/live555H264-V4l2LiveStreaming.git live555实现直播的方式是以testProgs/testOnDemandRTSPServer.cpp文件为参照对象。但是…

WPF编程,Live Charts使用说明(20)——饼图

后台 using System; using System.Windows.Controls; using LiveCharts; using LiveCharts.Wpf;namespace Wpf.PieChart {public partial class PieChartExample : UserControl{public PieChartExample(){InitializeComponent();PointLabel chartPoint >string.Format(&qu…

自定义LiveCD

目录 为什么要自定义LiveCD如何自定义Ubuntu Desktop CD系统要求安装预先安排获得基本系统 提取CD .iso内容解压缩桌面系统准备和chroot自定义 易于 先决条件任务GNOME的自定义背景更改gconf值&#xff08;字体&#xff0c;面板等&#xff09; 进行几次gconf更改设置区域默认…

Live2D看板娘详细实现

Live2D看板娘实现 国际惯例先上图&#xff1a; 所需资源&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1s7IJIqGnn-cNRAfoS-qG5w 提取码&#xff1a;dhf4 其中包含了看板娘所需的CSS&#xff0c;image,JS,Live2d所需的基本资源。 下面就来实现吧 开发工具ideato…

使用Open Live Writer配置CSDN及http500错误的解决

原贴地址连接:http://blog.csdn.net/qq_31105447/article/details/53468689 背景 作为一个菜鸟&#xff0c;了解到的信息总是非常滞后的。之前将博客园与Open Live Writer关联起来&#xff0c;发现在对博文的排版等变得很是便捷了。因此我就去查找CSDN是否支持Open Live Writer…

直播获奖(live)

题目描述&#xff1a; NOI2130 即将举行。为了增加观赏性&#xff0c;CCF决定逐一评出每个选手的成绩&#xff0c;并直播即时的获奖分数线。本次竞赛的获奖率为w%&#xff0c;即当前排名前w%的选手的最低成绩就是即时的分数线。 更具体地&#xff0c;若当前已评出了p个选手的…