LoginSignup
40
36

More than 5 years have passed since last update.

Three.jsとLive2D連携してみた

Posted at

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してあるので、興味ある人は参考にして下さい。

40
36
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
36