HaxeとThreejsで3Dコンテンツを作る 初級編


はじめに

私はFlash/ActionScriptしかほぼわからなかったのですが、Haxeをちょっとやってみたら、ほぼFlashと同じ感覚で、CanvasとかWebGLを使ったゲームのようにインタラクティブなものが作れるようになりました。

今回はそんな便利なHaxeとThreejsを使い、以下のようなBoxを複数配置し、マウスに反応する簡単なサンプルを作ります。初心者向けの内容です。

開発環境

開発はWindowsでFlashDevelopを使ってます。インストールが終われば、コマンドラインを使わずに、コンパイルまでできるので便利です。インストールにはこの記事がとても参考になります。
http://dev.classmethod.jp/ria/html5/haxe-createjs-1/

macもいろいろありそうですが、ここではふれません。
(macで FlashDevelopを使う方法があります)
http://qiita.com/_nabe/items/662624c7b093da9195f2

Three.jsをHaxeで使えるようにする

externというインターフェイスが定義されているファイルが必要になります。github上で公開されているもの(https://github.com/tong/three.hx )があるのでそれを使います。以下のようにコマンドラインで書くと、threejsという名でライブラリとしてインストールされ、扱えるようになります。
haxelib git threejs https://github.com/tong/three.hx

これでもいいんですが、パソコンが変わったり、開発環境が変わったりするとなんか面倒なので、私は下記のようにexternディレクトリを作り、そこにexternファイル群を入れ、srcパスを通しています。ご参考までに。

サンプルコード

Boxをいっぱいおいて、マウスでカメラが動くという簡単なサンプルコードを書いてみました。Main.hxとMain3d.hxでできています。できあがると、こんなかんじです

Main.hx
package ;

import js.Browser;
import js.Lib;

class Main 
{

    private static var _main:Main3d;

    static function main() 
    {
        Browser.window.onload = untyped _init;
    }

    static private function _init() 
    {
        _main = new Main3d();
        _main.init();
    }

}
Main3d.hx
package ;

import js.Browser;
import three.BoxGeometry;
import three.DirectionalLight;
import three.Mesh;
import three.MeshLambertMaterial;
import three.PerspectiveCamera;
import three.PointLight;
import three.Scene;
import three.Vector3;
import three.WebGLRenderer;
/**
 * ...
 * @author nabe
 */

class Main3d
{

    private  var _scene     :Scene;
    private  var _camera        :PerspectiveCamera;
    private  var _renderer  :WebGLRenderer;
    private  var _mouseX    :Float = 0;
    private  var _mouseY    :Float = 0;
    private  var _amp       :Float = 400;

    var _down:Bool=false;

    public function new() 
    {
    }

    public function init() 
    {

        _scene = new Scene();
        _camera = new PerspectiveCamera(60, Browser.window.innerWidth / Browser.window.innerHeight, 10, 50000);

        _camera.near = 5;
        _camera.far = 40000;

        _scene.add(new PointLight(0xffffff, 3));
        var d:DirectionalLight = new DirectionalLight(0xffffff);
        d.position.set(1000, 1000, 100);
        _scene.add(d);

        _renderer = new WebGLRenderer();
        _renderer.setSize(Browser.window.innerWidth, Browser.window.innerHeight);
        Browser.document.body.appendChild(_renderer.domElement);

        //マウスの座標とってる
        _renderer.domElement.onmousemove = function(e){
            _mouseX = e.clientX;
            _mouseY = e.clientY;
        }

        //箱200個おいてる
        for(i in 0...200){
            var geo:BoxGeometry = new BoxGeometry(10,10,10);
            var mat:MeshLambertMaterial = new MeshLambertMaterial( { color:0xffffff * Math.random() } );
            var mesh:Mesh = new Mesh(geo, mat);
            mesh.position.set(
                1000 * (Math.random() - 0.5),
                1000 * (Math.random() - 0.5),
                1000 * (Math.random() - 0.5)
            );
            _scene.add( mesh ); 
        }

        _run();

    }

    private function _run():Void
    {
        //マウスによってカメラ動かしてる
        var rad:Float = _mouseX / Browser.window.innerWidth * Math.PI * 2;
        _camera.position.x = _amp * Math.cos(rad);
        _camera.position.y = 0;
        _camera.position.z = _amp * Math.sin(rad);
        _camera.lookAt(new Vector3());

        _renderer.render(_scene, _camera, null, false);     
        Three.requestAnimationFrame( untyped _run);
    }

}

おわりに

Haxeはクラス作るのも、エディタのコードの補間も、コンパイルエラーだしてくれるのも超便利です。ゲームみたいな複雑なものにとてもむくのではないでしょうか。js/htmlが分からない私でも楽しく開発できて、自然にjs/htmlもちょっとわかるようになりました。
逆にHTMLの開発(ふつうのWebページみたいなの?)とかには向いてないのかもしれないです。