Live2D plugin for PixiJS (with lipsync patch)
npm install @laffy1309/pixi-live2d-lipsyncpatchlive2dcubismcore.min.js,可以从 Cubism 4 SDK
live2d.min.js,从 2019/9/4 起
cubism2.js 和 cubism4.js,以及一个同时包含了两种版本的 index.js
index.js,_而不要同时使用_ cubism2.js 和 cubism4.js
cubism2.js+live2d.min.js 以支持 Cubism 2.1 模型
cubism4.js+live2dcubismcore.min.js 以支持 Cubism 3 和 Cubism 4 模型
index.js+live2d.min.js+live2dcubismcore.min.js 以支持所有版本的模型
sh
npm install pixi-live2d-display-lipsyncpatch
`
`js
import { Live2DModel } from 'pixi-live2d-display-lipsyncpatch';
// 如果只需要 Cubism 2.1
import { Live2DModel } from 'pixi-live2d-display-lipsyncpatch/cubism2';
// 如果只需要 Cubism 4
import { Live2DModel } from 'pixi-live2d-display-lipsyncpatch/cubism4';
`
#### 通过 CDN (口型同步修改版)
`html
`
通过这种方式加载的话,所有成员都会被导出到 PIXI.live2d 命名空间下,比如 PIXI.live2d.Live2DModel
基础使用
$3
`typescript
import { Live2DModel } from 'pixi-live2d-display-lipsyncpatch/cubism4';
import { Application, Ticker } from 'pixi.js';
(async function () {
const app = Application({
view: document.getElementById('canvas'),
});
const model = await Live2DModel.from('shizuku.model.json', {
// register Ticker for model
ticker: Ticker.shared,
});
app.stage.addChild(model);
// transforms
model.x = 100;
model.y = 100;
model.rotation = Math.PI;
model.skew.x = Math.PI;
model.scale.set(2, 2);
model.anchor.set(0.5, 0.5);
// interaction
model.on('hit', (hitAreas) => {
if (hitAreas.includes('body')) {
model.motion('tap_body');
}
});
})();
`
$3
`javascript
import * as PIXI from 'pixi.js';
import { Live2DModel } from 'pixi-live2d-display';
// 将 PIXI 暴露到 window 上,这样插件就可以通过 window.PIXI.Ticker 来自动更新模型
window.PIXI = PIXI;
(async function () {
const app = new PIXI.Application({
view: document.getElementById('canvas'),
});
const model = await Live2DModel.from('shizuku.model.json');
app.stage.addChild(model);
// 变换
model.x = 100;
model.y = 100;
model.rotation = Math.PI;
model.skew.x = Math.PI;
model.scale.set(2, 2);
model.anchor.set(0.5, 0.5);
// 交互
model.on('hit', (hitAreas) => {
if (hitAreas.includes('body')) {
model.motion('tap_body');
}
});
})();
`
口型同步
$3
`ts
const category_name = "Idle" // 模型动作名称
const animation_index = 0 // 该运动类别下的动画索引 [null => random]
const priority_number = 3 // 优先级编号 如果你想保持当前动画继续或强制移动到新动画 可以调整此值 [0: 无优先级, 1: 空闲, 2: 普通, 3: 强制]
const audio_link = "https://cdn.jsdelivr.net/gh/RaSan147/pixi-live2d-display@v1.0.3/playground/test.mp3" // 音频链接地址 [可选参数,可以为null或空] [相对或完整url路径] [mp3或wav文件]
const volume = 1; // 声音大小 [可选参数,可以为null或空][0.0-1.0]
const expression = 4; // 模型表情 [可选参数,可以为null或空] [index | expression表情名称]
const resetExpression = true; // 是否在动画结束后将表情expression重置为默认值 [可选参数,可以为null或空] [true | false] [default: true]
model.motion(category_name, animation_index, priority_number, {
sound: audio_link,
volume: volume,
expression: expression,
resetExpression: resetExpression
});
// 如果不想要声音 就忽略 sound 和 volume
model.motion(category_name, animation_index, priority_number);
model.motion(category_name, animation_index, priority_number, { expression: expression, resetExpression: resetExpression });
model.motion(category_name, animation_index, priority_number, { expression: expression, resetExpression: false });
`
$3
`ts
const audio_link = "https://cdn.jsdelivr.net/gh/RaSan147/pixi-live2d-display@v1.0.3/playground/test.mp3" // 音频链接地址 [可选参数,可以为null或空] [相对或完整url路径] [mp3或wav文件]
const volume = 1; // 声音大小 [可选参数,可以为null或空][0.0-1.0]
const expression = 4; // 模型表情 [可选参数,可以为null或空] [index | expression表情名称]
const resetExpression = true; // 是否在动画结束后将表情expression重置为默认值 [可选参数,可以为null或空] [true | false] [default: true]
const crossOrigin = "anonymous"; // 使用不同来源的音频 [可选] [default: null]
model.speak(audio_link, {
volume: volume,
expression: expression,
resetExpression: resetExpression,
crossOrigin: crossOrigin
});
// 或者如果您想保留某些默认设置
model.speak(audio_link);
model.speak(audio_link, { volume: volume });
model.speak(audio_link, { expression: expression, resetExpression: resetExpression });
`
$3
- 这两个函数都有 crossOrigin 参数。将其设置为 crossOrigin : "anonymous" 即可解决。
`ts
model.speak(audio_link, { expression: expression, crossOrigin: "anonymous" });
model.motion(category_name, animation_index, priority_number, { sound: audio_link, volume: volume, crossOrigin: "anonymous" });
`
$3
`ts
model.stopSpeaking();
`
$3
`ts
model.stopMotions();
`
$3
`ts
model.speak(audio_link, {
volume: volume,
onFinish: () => { console.log("Voiceline is over") },
onError: (err) => { console.log("Error: ", err) } // [如果发生任何错误]
});
model.motion(category_name, animation_index, priority_number, {
sound: audio_link,
volume: volume,
expression: expression,
onFinish: () => { console.log("Voiceline and Animation is over") },
onError: (err) => { console.log("Error: ", err) } // [如果发生任何错误]
});
`
$3
- 这也将停止运动和音频的播放并隐藏模型
`ts
model.destroy();
`
$3
https://user-images.githubusercontent.com/34002411/230723497-612146b1-5593-4dfa-911d-accb331c5b9b.mp4
请参阅此处了解更多文档: 文档
包导入
当按需导入 Pixi 的包时,需要手动注册相应的组件来启用可选功能
`javascript
import { Application } from '@pixi/app';
import { Ticker } from '@pixi/ticker';
import { InteractionManager } from '@pixi/interaction';
import { Live2DModel } from 'pixi-live2d-display';
// 为 Live2DModel 注册 Ticker
Live2DModel.registerTicker(Ticker);
// 为 Application 注册 Ticker
Application.registerPlugin(TickerPlugin);
// 注册 InteractionManager 以支持 Live2D 模型的自动交互
Renderer.registerPlugin('interaction', InteractionManager);
(async function () {
const app = new Application({
view: document.getElementById('canvas'),
});
const model = await Live2DModel.from('shizuku.model.json');
app.stage.addChild(model);
})();
``