Posted at

Three.jsとLive2D連携してみた

More than 3 years have passed since last update.

Three.jsにLive2D組み込んでみたかったので、ちょっとトライしてみました。



開発環境

Live2D WebGL SDK2.1

Three.js(Revision:79)


実装内容

Live2D側へは、WebGLコンテキストが渡せば描画できるので以下のコードで渡しました。

// GLの取得の仕方

var renderer = new THREE.WebGLRenderer();
var gl = renderer.getContext();
// glをLive2Dに渡す

THREE.PlaneGeometryクラスのようなLive2Dクラスを作りたかったのですが、インデクスバッファやUV情報を渡すLive2D APIがないので以下のように実装しました。

1)Three.jsでオフスクリーンレンダリングを生成

2)オフスクリーンレンダリングでLive2D描画

3)オフスクリーンレンダリング結果をPlaneのテクスチャとして扱う


ソースコード

Three.jsと連携用にLive2DRender.jsというクラスを作りました。

(githubへもUPしておきました - Live2D_ThreeJS

それ以外のクラスはLive2D WebGL SDKから持ってきてます。

Three.jsのbuildフォルダ配下に入れています。

01_finder.png

HTML部分は、以下のように実装すればThree.js内でLive2D描画できます。


index.html

<!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8">
<title>Simple Live2D</title>
</meta>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="../../build/three.js"></script>
<!-- Live2Dのコアライブラリ -->
<script src="../../build/Live2D/lib/live2d.min.js"></script>
<!-- Live2Dの便利機能が入ったクラス群 -->
<script src="../../build/Live2D/framework/Live2DFramework.js"></script>
<!-- Live2Dモデルやテクスチャロード管理クラス -->
<script src="../../build/Live2D/src/PlatformManager.js"></script>
<!-- Live2Dモデルの生成やチェンジを行うクラス -->
<script src="../../build/Live2D/src/LAppLive2DManager.js"></script>
<!-- Three.js用のカスタムクラス -->
<script src="Live2DRender.js"></script>
<script>
// シーン生成
var scene = new THREE.Scene();
// カメラ生成
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 5;

// レンダラー生成
var renderer = new THREE.WebGLRenderer();
// レンダラーのサイズ指定
renderer.setSize( window.innerWidth, window.innerHeight );
// DOMを追加
document.body.appendChild( renderer.domElement );

// オフスクリーン用(Live2Dを描画)
var offScene1 = new THREE.Scene();
var offRenderTarget1 = new THREE.WebGLRenderTarget(
window.innerWidth,
window.innerHeight,
{
minFilter: THREE.LinearFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBAFormat
}
);

var textureLoader = new THREE.TextureLoader();
// 背景テクスチャのロード
var background = textureLoader.load("../../assets/images/background.jpg");
// プレーン生成
var backgeo = new THREE.PlaneGeometry( 8, 8, 1, 1 );
var backmat = new THREE.MeshBasicMaterial( { map: background } );
var backmesh = new THREE.Mesh( backgeo, backmat );
scene.add( backmesh );

// Live2Dモデルパス
var MODEL_PATH1 = "../../assets/Epsilon2.1/";
var MODEL_JSON1 = "Epsilon2.1.model.json";
// Live2Dモデル生成
var live2dmodel1 = new THREE.Live2DRender( renderer, MODEL_PATH1, MODEL_JSON1 );

// オフスクリーンを描画するPlane生成
var geometry1 = new THREE.PlaneGeometry( 6, 6, 1, 1 );
// レンダーテクスチャをテクスチャにする
var material1 = new THREE.MeshBasicMaterial( { map:offRenderTarget1.texture } );
var plane1 = new THREE.Mesh( geometry1, material1 );
// この1行がないと透過部分が抜けない
plane1.material.transparent = true;
scene.add( plane1 );

// リサイズへの対応
window.addEventListener('resize', function(){
renderer.setSize( window.innerWidth, window.innerHeight );
// オフスクリーンのレンダーターゲットもリサイズ
offRenderTarget1.setSize( window.innerWidth, window.innerHeight );
// マウスドラッグ座標もリサイズ
live2dmodel1.setMouseView(renderer);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}, false);

// コンテキストメニューの表示を阻止
document.addEventListener('contextmenu', function(e){
// 右クリックの挙動を阻止する
e.preventDefault();
}, false);

// マウスクリック処理
document.addEventListener('mousedown', function(e){
switch(e.button){
case 0: // 左クリック
// ランダムモーション指定
live2dmodel1.setRandomMotion();
// 特定のモーション指定は、setMotion("ファイル名")を使う。
// 例:live2dmodel.setMotion("Epsilon2.1_m_08.mtn");
break;
case 2: // 右クリック
// ランダム表情切り替え
live2dmodel1.setRandomExpression();
// 特定の表情切り替えは、setExpression("ファイル名")を使う。
// 例:live2dmodel.setExpression("f04.exp.json");
break;
}
});

/**
* 描画処理
*/

var render = function () {
requestAnimationFrame( render );
// オフスクリーン切り替え描画
renderer.render( offScene1, camera, offRenderTarget1 );
// オフスクリーンにLive2D描画
live2dmodel1.draw();
// resetGLStateしないとgl.useProgramが呼ばれず以下のエラーになる
// [error]location is not from current program
renderer.resetGLState();
// Mainシーンで描画
renderer.render( scene, camera );
};

render();
</script>
</body>
</html>


02_simple.png

DEMOページ

<操作方法>

左クリック:ランダムモーション再生

右クリック:ランダム表情切り替え

マウスドラッグ:ドラッグしてる方を見る


応用編

これを応用するとThree.jsの機能も使えて色々できます!

・Live2Dを2体描画(DEMOページ

03_two.png

・Cubeと組み合わせる(DEMOページ

04_cube.png

・レンズフレアと組み合わせる(DEMOページ

05_lensfre.png

古いjsで書いてすいませんが、こちらもgithubにソースUPしてあるので、興味ある人は参考にして下さい。