22
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

three.js+Electronで暴れまわるティラノサウルスを表示する

Last updated at Posted at 2018-12-10

はじめに

Office365のWordに、全人類が待望していた新機能が実装されました。

文書を活気づかせる: アニメーション 3D グラフィックスを挿入して、鼓動する心臓、周回する惑星、暴れ回るティラノサウルスをページ上に表示できます。

暴れ回るティラノサウルスをページ上に表示できます。

「あぁ、この文書に暴れまわるティラノサウルスを表示できればいいのになぁ」と思ったこと、誰しも一度はありますよね。誰が使うんだこの機能

ところで僕はOffice365を利用していないので、残念ながら文書ファイル上でティラノサウルスを暴れまわらせることができません。

そこで、普段利用しているgoogleドキュメント… だけなどとみみっちいことは言わず、
ウィンドウ全体でティラノサウルスを暴れさせてみようと思います。

具体的には、ティラノサウルスのMMDモデルをelectron上で表示してみます。

ティラノサウルスを用意する

こちらからお借りしました。

electron環境を作成する

以下の記事を参考に、ひとまず空のelectron環境を作成します。
https://qiita.com/Quramy/items/a4be32769366cfe55778

main.js
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

let mainWindow = null;

app.on('window-all-closed', function() {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {

  // ブラウザ(Chromium)の起動, 初期画面のロード
  mainWindow = new BrowserWindow({width: 800, height: 600});
  mainWindow.loadURL('file://' + __dirname + '/index.html');

  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Electron Read Us</title>
</head>
<body>
<h1>Hello, electron!</h1>
</body>
</html>

ティラノサウルスを召喚する

three.jsのサイトにexampleがあるのでこれを参考に、
MMDモデルをロード・表示してみます。ついでにサンプルのモーションを適用して、ティラノサウルスを踊らせ暴れさせてみましょう。

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Electron Read Us</title>
<script src="./js/three.min.js"></script>
<script src="js/libs/mmdparser.min.js"></script>
<script src="js/libs/ammo.js"></script>
<script src="js/loaders/TGALoader.js"></script>
<script src="js/loaders/MMDLoader.js"></script>
<script src="js/effects/OutlineEffect.js"></script>
<script src="js/animation/CCDIKSolver.js"></script>
<script src="js/animation/MMDPhysics.js"></script>
<script src="js/animation/MMDAnimationHelper.js"></script>
<script src="./js/index.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
index.js
window.addEventListener('load', init);

function init() {
  const width = 800;
  const height = 400;
  const renderer = new THREE.WebGLRenderer({
    canvas: document.querySelector('#canvas')
  });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(width, height);

  const scene = new THREE.Scene();

  const camera = new THREE.PerspectiveCamera(45, width / height);
  camera.position.set(0, 0, +100);

  var directionalLight = new THREE.DirectionalLight(0xffffff);
  directionalLight.position.set(0, 0.7, 0.7);
  scene.add(directionalLight);

  var modelFile = './models/rex.pmx';
  var vmdFiles = [ './models/wavefile_v2.vmd' ];

  var clock = new THREE.Clock();
  var helper = new THREE.MMDAnimationHelper();
  var physicsHelper, ikHelper, mesh;

  var loader = new THREE.MMDLoader();

  loader.loadWithAnimation( modelFile,vmdFiles, function (obj){
    mesh = obj.mesh;
    console.log("Loaded!!");
    mesh.position.y = -30;
    scene.add(mesh);

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

    ikHelper = helper.objects.get( mesh ).ikSolver.createHelper();
    ikHelper.visible = false;
    scene.add( ikHelper );

    physicsHelper = helper.objects.get( mesh ).physics.createHelper();
    physicsHelper.visible = false;
    scene.add( physicsHelper );

  }, onProgress, onError);

  var onProgress = function(e){
    if (e.lengthComputable){
      var percentComplete = e.loaded / e.total * 100;
      console.log(Math.round(percentComplete, 2) + "% downloaded");
    }
  };

  var onError = function(e){
    console.log("onError:" + e);
  };

  tick();

  function tick() {
    requestAnimationFrame(tick);
    helper.update( clock.getDelta() );
    renderer.render(scene, camera);
  }
}

現状のディレクトリ構成は以下のような感じです。

.
│  index.html
│  main.js
│  package.json
│  
├─js
│  │  index.js
│  │  three.min.js
│  │  
│  ├─animation
│  │      CCDIKSolver.js
│  │      MMDAnimationHelper.js
│  │      MMDPhysics.js
│  │      
│  ├─effects
│  │      OutlineEffect.js
│  │      
│  ├─libs
│  │      ammo.js
│  │      mmdparser.min.js
│  │      stats.min.js
│  │      
│  ├─loaders
│  │      MMDLoader.js
│  │      MTLLoader.js
│  │      OBJLoader.js
│  │      TGALoader.js
│  │      
│  └─renderers
│          Projector.js
│          
└─models
        rex.pmx
        tyranno1.jpg
        tyranno2.jpg
        wavefile_v2.vmd

electron . で実行してみます。

rex.gif

圧がすごい。

サンプルは女の子が踊るモーションなので、
恐竜に無理やり適用したらめちゃくちゃに破綻するのかと思いましたが、意外とそうでもないですね。キモイけど。

画像はgifなのでわかりにくいですが、実機だとぬるぬる動いて余計にキモイです。

ウィンドウを透明にする

UIを非表示、ウィンドウを透過状態にし、暴れるティラノサウルスだけが表示されるようにします。
また、常にウィンドウが最前面に来るようにしておきます。

main.js
  mainWindow = new BrowserWindow({width: 800, height: 600
    ,transparent: true
    ,frame: false
    ,toolbar: false
    ,alwaysOnTop: true
  });

このままだとthree.jsの描画領域は黒いままなので、こちらも設定を変更します。

index.js
const renderer = new THREE.WebGLRenderer({
    canvas: document.querySelector('#canvas'),
    alpha: true
  });

画面上でティラノサウルスが暴れてくれました。
これでOffice365がなくても、いつでもティラノサウルスを暴れさせることができます。

rexdoc.png

まとめ

突貫作業でしたが、比較的簡単にモデルを表示することができました。
3D版伺かとか作れそうです。

感想

3DCGはシーンやカメラの概念など、独特の感覚に慣れないと難しいですね。
これを機に、three.jsやunityを触って理解を深めようと思います。

22
8
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
22
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?