Edited at
WebGLDay 24

pixi.jsとLive2Dで雪降るシーンを作る

この記事はWebGL Advent Calendar 2016の24日目の記事です。

たまたま空いてたのでWebGLの軽いネタを書こうかと。

pixi.jsのLive2Dプラグインを作ってたら、すでに作ってる人がいたので使ってみました。

中身のソース見てたら自分と同じく、オフスクリーンにLive2D描画しSpriteのテクスチャとしてました。

pixi.jsを使う事でお手軽に雪降るシーンが作れてクリスマスっぽくできましたっ!



開発環境

Live2D WebGL SDK2.1

Pixi.js v4.1.1

Pixi-live2dプラグイン


導入方法

Pixi-live2dはnpmにも公開されてるので、パチパチとnpmコマンドを打っていけば簡単に導入できます。


1)ターミナルを開いて、まずは作業フォルダを作ります

# npm initコマンドで怒られないように大文字は使わない

mkdir pixi_live2d
cd pixi_live2d


2)npmコマンドで必要なライブラリをインストール

pixi.jsはv4.2.1以上だと仕様が変わったようで、activeTexture切り替えエラーで描画できなかった...。

そのため、pixi.jsはver.4.1.1をインストールします

# initコマンド実行後に色々と聞かれるがEnter連打

npm init
# pixi.jsをインストール
npm install pixi.js@4.1.1
# pixi-live2dをインストール
npm install pixi-live2d
# webpackをインストール
npm install webpack


3)Live2D SDKからLive2d.min.jsをコピーしてくる

# libフォルダを作り、live2d.min.jsをおく

mkdir lib

スクリーンショット 2016-12-24 13.38.02.png


4)Live2D SDKからLive2Dモデルをコピーしてくる

# assetsフォルダを作り、Live2Dモデルファイルをおく

mkdir assets

スクリーンショット 2016-12-24 13.38.56.png


5)webpackでライブラリのjsをまとめる

# webpackの設定ファイルを作る

touch webpack.config.js

中身は以下の通りでwebpackコマンド実行後にbundle.jsが出力されます


webpack.config.js

module.exports = {

entry :{
lib: ['./lib/live2d.min.js',
'./node_modules/pixi.js/bin/pixi.min.js',
'./node_modules/pixi-live2d/dist/index.js',
]
},
output : {
filename : './lib/bundle.js'
}
};

# webpackコマンド実行し、bindle.jsを生成

webpack


6)index.htmlとindex.jsを作成し、以下のように記述する。

このあたりはpixi-live2dのサンプルとほぼ同じです。


index.html

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Live2D Core Library -->
<!--<script src="lib/live2d.min.js"></script>-->
<!--<script src="node_modules/pixi.js/bin/pixi.min.js"></script>-->
<!--<script src="node_modules/pixi-live2d/dist/index.js"></script>-->
<script src="lib/bundle.js"></script>
<title>pixi-live2d</title>
</head>
<body>
<div id="app"></div>
<!-- User Script -->
<script src="index.js"></script>
</body>
</html>


7)index.jsを作成し、以下のようにする

これもpixi-live2dのサンプルのほぼコピペ


index.js

// レンダラーの生成

const renderer = new PIXI.WebGLRenderer(800, 600);
document.getElementById('app').appendChild(renderer.view);
// ステージの生成
const stage = new PIXI.Container();

// Live2Dのモデル定義
const modelHaru = {
"type":"Live2D Model Setting",
"name":"haru",
"model":"assets/haru/haru_01.moc",
"textures":
[
"assets/haru/haru_01.1024/texture_00.png",
"assets/haru/haru_01.1024/texture_01.png",
"assets/haru/haru_01.1024/texture_02.png"
],
"physics":"assets/haru/haru.physics.json",
"pose":"assets/haru/haru.pose.json",
"expressions":
[
{"name":"f01","file":"assets/haru/expressions/f01.exp.json"},
{"name":"f02","file":"assets/haru/expressions/f02.exp.json"},
{"name":"f03","file":"assets/haru/expressions/f03.exp.json"},
{"name":"f04","file":"assets/haru/expressions/f04.exp.json"},
{"name":"f05","file":"assets/haru/expressions/f05.exp.json"},
{"name":"f06","file":"assets/haru/expressions/f06.exp.json"},
{"name":"f07","file":"assets/haru/expressions/f07.exp.json"},
{"name":"f08","file":"assets/haru/expressions/f08.exp.json"}
],
"layout":
{
"center_x": 0,
"y": 1.2,
"width": 2.9
},
"hit_areas":
[
{"name":"head", "id":"D_REF.HEAD"},
{"name":"body", "id":"D_REF.BODY"}
],
"motions":
{
"idle":
[
{"file":"assets/haru/motions/idle_00.mtn" ,"fade_in":2000, "fade_out":2000},
{"file":"assets/haru/motions/idle_01.mtn" ,"fade_in":2000, "fade_out":2000},
{"file":"assets/haru/motions/idle_02.mtn" ,"fade_in":2000, "fade_out":2000}
],
"tap_body":
[
{ "file":"assets/haru/motions/tapBody_00.mtn" , "sound":"assets/haru/sounds/tapBody_00.mp3"},
{ "file":"assets/haru/motions/tapBody_01.mtn" , "sound":"assets/haru/sounds/tapBody_01.mp3"},
{ "file":"assets/haru/motions/tapBody_02.mtn" , "sound":"assets/haru/sounds/tapBody_02.mp3"}
],
"pinch_in":
[
{ "file":"assets/haru/motions/pinchIn_00.mtn", "sound":"assets/haru/sounds/pinchIn_00.mp3" }
],
"pinch_out":
[
{ "file":"assets/haru/motions/pinchOut_00.mtn", "sound":"assets/haru/sounds/pinchOut_00.mp3" }
],
"shake":
[
{ "file":"assets/haru/motions/shake_00.mtn", "sound":"assets/haru/sounds/shake_00.mp3","fade_in":500 }
],
"flick_head":
[
{ "file":"assets/haru/motions/flickHead_00.mtn", "sound":"assets/haru/sounds/flickHead_00.mp3" }
]
}
};

// Live2DのSpriteを生成
const live2dSprite = new PIXI.Live2DSprite(modelHaru, {
debugLog: false,
randomMotion: false,
eyeBlink: false,
});
stage.addChild(live2dSprite);

// 位置調整
live2dSprite.x = -105;
// live2dSprite.y = -150;
// スケール
live2dSprite.adjustScale(0,0,0.7);
// 移動
live2dSprite.adjustTranslate(0.4, 0);
// ランダムモーション
live2dSprite.startRandomMotion('idle');
// マウス操作
live2dSprite.on('mousemove', (evt) => {
const point = evt.data.global;
live2dSprite.setViewPoint(point.x, point.y);
});

function animate() {
requestAnimationFrame(animate);
renderer.render(stage);
}
animate();


8)実行結果

これでpixi.js上にLive2Dが描画できました!

スクリーンショット 2016-12-24 13.41.00.png

詳しいAPIの使い方はpixi-live2d APIを見ると良いです。

目パチやリップシンクなどtrue/falseを渡すだけでON/OFFできるようですね。


ソースコード

以下のサイトを参考に雪を降らせたソースもgithubにアップしておきました。

スクリーンショット 2016-12-24 14.15.24.png

pixi.jsを使って雪を降らせてみた。

github - Live2D-Pixijs-Test

pixi.jsは、stageごとにブラーフィルタかけられるのは便利ですね。

これで簡単にインタラクティブなサイトが作れそうな気がします!

では、よいクリスマスをお過ごしください!