Back to tech

Web上でもARでミクさんを踊らせたい

3 min read
Table of Contents

最近、自分の中でAR(拡張現実)が再ブレイク中です

はじめは三年前ぐらいに流行り、Unituyを使ってARを挑戦しました

AndroidでAR(拡張現実)をする [オブジェクの生成編] | Autumn-Color.com/ちょっとそこまで旅をします。
autumn-color.com
image

デバイスごとにアプリを作り直さなければならない点がどうしても開発に煩わしさを感じてしまい、一気にブレイクが去っていきました

しかし、Web上でもARができるようになったよ!というニュースをみて改めて挑戦をしてみました

挑戦をした結果、Web上にてARでミクさんを踊らせることができたので記事にします

デモ

解説云々を入れる前に先にデモを記述します

Lat式ミクに”地球最後の告白を”を踊らせています

ARマーカーをカメラに近づけるとミクさんが踊ってくれます

著作権の問題で音楽は流れません

Web上でARマーカーを使ってミクさんを踊らせてみた
www.youtube.com
image

手持ちのスマホやパソコンでも下記のサイトにて体験ができます

下のマーカー(Hiro Marker)を認識させてください

参考:https://commons.wikimedia.org/wiki/File:Hiro_marker_ARjs.png

体験するときに、スマートフォンの場合は下記のURLをコピーしてからブラウザで起動してください

また、iPhoneの方はsafariにてアクセスをしてください

momijinn.github.io
momijinn.github.io

使用したライブラリ

本プログラムはThree.jsとAR.jsを用いて作成をしています

Three.jsとは

Three.jsとは、ウェブブラウザ上にて簡単にCGを描画することができるJavaScirptのライブラリです

これを使うことで簡単に3Dコンテンツを作ることができます

threejs.org
threejs.org

このライブラリの主にMMDを取り扱うための関数を使っていきます

threejs.org
threejs.org

AR.jsとは

AR.jsとは、ウェブブラウザ上で簡単にARをすることができるJavaScirptライブラリです

また、非常に高速に動作することができるだけではなく、AndroidやiOS、windowsといったあらゆるプラットフォームで動作することが可能です

AR.js/README.md at master · jeromeetienne/AR.js
github.com
image

プログラム

プログラムはすべてGitHubに掲載しています

github.com
github.com

プログラムにて重要なのはindex.js(staitc/js/index.js)です

コメントアウトにて解説をいれているので、本記事では重要な箇所や開発中に困ったことを記載します

Hiroマーカーの使用

本プログラムはARのサンプルでよく使われているHiroマーカーを使い、このHiroマーカーを認識したらミクさんを召喚しています

サンプルを参考にして記述をしたのですが、マーカーを認識してくれませんでした

ネットで探してみると解決策が見つかり、どうやら”HREEx.ArToolkitContext.baseURL”の場所を変えろよということでした

link THREEx.ArToolkitContext.baseURL to local three.js folder · Issue #50 · jeromeetienne/AR.js
github.com
image

index.htmlにURLを変更する記述をしています

 <script>THREEx.ArToolkitContext.baseURL = 'https://jeromeetienne.github.io/AR.js/three.js/'</script>

Hiroマーカーは以下からダウンロードできます

commons.wikimedia.org
commons.wikimedia.org

MMDのスケールの縮小

MMDをインポートしたあとそのままマーカーへ投影するとミクさんがとてつもなく大きく投影されます

そのため、ミクさんの大きさを変換してあげます

私はObject3Dを作成し、そのなかにMMDのデータを追加後、追加したObject3Dを縮小するようにしました

new THREE.MMDLoader().loadWithAnimation( modelFile, vmdFiles, function ( mmd ) {
    mesh = mmd.mesh;

    // 3dobject
    var model = new THREE.Object3D();
    // Scaleの変換
    model.scale.x = 0.1;
    model.scale.y = 0.1;
    model.scale.z = 0.1;
    model.add(mesh);

   marker.add(model);

    //以下略
});

一応mmd.meshにもスケールを変換するための変数(scale.set)を持っています

一度以下のように追加してプログラムを動かしてみたのですが、初期状態時にミクさんのスカートが飛び跳ねて食い込んでいたのでobject3dを使用しました

new THREE.MMDLoader().loadWithAnimation( modelFile, vmdFiles, function ( mmd ) {
    mesh = mmd.mesh;

    mesh.scale.set(0.1, 0.1, 0.1);
    marker.add(mesh);

    //以下略
});

下記のように初期状態にてスカートが跳ね返り、食い込みます

レンダリング

Web上にてレンダリングをするにはrequestAnimationFrame()を呼び出して描画をします

本プログラムにもrequestAnimationFrame()を入れているのですがコメントアウトし、setIntarvalにて描画をしています

理由として、requestAnimationFrame()にするとミクさんが汚く描画されたためです

requestAnimationFrame()について詳しく追えてはいないのですが、setIntarvalでやったほうが綺麗にミクさんが描画されたのでこちらを採用しました

//Render
// function renderScene() {
//   requestAnimationFrame(renderScene);
//   if(source.ready === false){ return; }

//   context.update(source.domElement);
  
//   if(ready){
//     helper.update(clock.getDelta());
//   }

//   // renderer.render( scene, camera );
//   effect.render( scene, camera );
// }

setInterval(function(){
  if(source.ready === false){ return; }

  if(ready){
    helper.update(clock.getDelta());
  }

  renderer.render( scene, camera );
  context.update(source.domElement);
}, 1000 / 60); //60fps

requestAnimationFrame()で動かしたい場合は、function renderScene()のコメントアウトを外し、Index.jsの冒頭付近にあるrenderScene()のコメントアウトも外すします

そのあと、setInterval()内をコメントアウトするとrequestAnimationFrame()で動作します

左がsetInterval()での描写で左がrequestAnimationFrame()での描写です

requestAnimationFrame()が髪の毛の影?が強くなっている

音楽再生

冒頭にてデモは音楽を再生することができないと記述しました

しかし、音楽データをいれてコメントアウトされている部分を外すと音楽も再生することができます

まず、“static/mmd/music/“に”地球最後の告白を”の音源をmusic.mp3にリネームして配置します

(Amazonにて販売をしています:https://amzn.to/2ODiMzm)

つぎに”staitc/js/index.js”にて,“new THREE.MMDLoader().loadWithAnimation”内に入っている音楽を再生する箇所のコメントアウトを外します

before

helper = new THREE.MMDAnimationHelper( {
    afterglow: 2.0
});
    
new THREE.MMDLoader().loadWithAnimation( modelFile, vmdFiles, function ( mmd ) {
    mesh = mmd.mesh;

    // 3dobject
    var model = new THREE.Object3D();
    // Scaleの変換
    model.scale.x = 0.1;
    model.scale.y = 0.1;
    model.scale.z = 0.1;
    model.add(mesh);

    helper.add( mesh, {
    animation: mmd.animation,
    physics: true,
    });

    //add maker
    marker.add(model);
    
    //Audio
    // new THREE.AudioLoader().load(audioFile, function(buffer){
    //   var listener = new THREE.AudioListener();
    //   var audio = new THREE.Audio( listener ).setBuffer( buffer );

    //   listener.position.z = 1;
    
    //   helper.add( audio, audioParams );
    //   marker.add( listener );

    //   // Music Load Flag
    //   ready = true;
    // });
    ready = true;


}, onProgress, onError );

after

helper = new THREE.MMDAnimationHelper( {
    afterglow: 2.0
});
    
new THREE.MMDLoader().loadWithAnimation( modelFile, vmdFiles, function ( mmd ) {
    mesh = mmd.mesh;

    // 3dobject
    var model = new THREE.Object3D();
    // Scaleの変換
    model.scale.x = 0.1;
    model.scale.y = 0.1;
    model.scale.z = 0.1;
    model.add(mesh);

    helper.add( mesh, {
    animation: mmd.animation,
    physics: true,
    });

    //add maker
    marker.add(model);
    
    //Audio
    new THREE.AudioLoader().load(audioFile, function(buffer){
    var listener = new THREE.AudioListener();
    var audio = new THREE.Audio( listener ).setBuffer( buffer );

    listener.position.z = 1;
    
    helper.add( audio, audioParams );
    marker.add( listener );

    // Music Load Flag
    ready = true;
    });
    // ready = true; //ここのFlagをコメントアウトする


}, onProgress, onError );

その後、キャシュを削除後index.htmlを開き直すと音楽が流れます

本プログラムのライセンスについて

本プログラムに使用しているMMDやモーションは再配布が問題ないものを使用しています

製作者のLat様とよぴ様に感謝いたします

MMDのライセンス

製作者 : Lat
[email protected]
http://innoce.nobody.jp/

モーションのライセンス

製作者:よぴ
Twitter:@pyopi
Motion:https://www.nicovideo.jp/watch/sm25418510

いろんな端末でやってみた

いろんな端末で本当に動くのかやってみました

手元にあったWindows 10,iOS(iPad pro), Android(ASUS)でやってみました

Android端末だけ多少もっさり感があります

twitter.com
twitter.com

未解決

Webブラウザ上にてARマーカートラッキングしミクさんを踊らせるという目標は達成しました

しかし、最終的にやりたかった「ARマーカーを認識していなければ一時停止」というプログラムが実装できませんでした

音楽は一時停止するのですが、ミクさんは一時停止したあとに再生をすると一時停止した時間分進んだところから踊り始めます

一時停止したところからもう一度再生を始めてほしいのです

解決策をお待ちしています

まとめ

Webブラウザ上にてARマーカートラッキングしミクさんを踊らせるプログラムを作りました

様々な端末でやってみましたがどれも動作することを確認しました

一時停止機能の実装ができない状況なので解決策をお待ちしています

参考