gl.enchant.js 上でメタセコイアのデータを読み込めるようにするプラグイン mqo.gl.enchant.js を作りました

phiary に引っ越しました. 毎日プログラミングやWebに関する情報を発信しています! RSS 登録してたまに覗いたり, tweet やハテブして拡散してもらえると幸いです.

Pocket

gl.enchant.js は標準で collada.gl.enchant.js という COLLADA(.dae) ファイルを読み込めるプラグインが付いています. ですが, dae はちょっと学生さんには馴染みがないかなぁ~と思い Metasequoia(メタセコイア)形式(.mqo) ファイルを読み込めるようにするプラグインを作ってみました.

なんとなぁ~く表示できたら良いかなぁ~という感じで2時間ぐらいで作ったので色々と怪しいですが一応表示できているみたいです. 基本的に使い方は callada.gl.enchant.js と同じで game.preload でロード, game.assets で取得できます.

サンプルは File API を使ってドラッグ & ドロップに対応しているので, ローカルにある mqo ファイルをバンバン放り込んで遊んでみてください.

Sample and Download

今回制作したサンプルはこちら.

最初は私が学生の頃作ったオリジナルキャラクター”まる吉”が表示されます.(※星のカー○ィとはなんの関係もありません) 他の mqo ファイルを読み込みたい場合はドラッグ & ドロップしてもらえれば表示されます.

また, ダウンロードした場合, フォルダ内の texture フォルダに入っているテクスチャ(png や jpg)をドラッグ & ドロップすると テクスチャとしてモデルに貼りつけられます.

マウスでカメラを回転, キーボードでモデルを回転させることができます.

Donwload はこちらから出来ます.

Code

今回制作したサンプルの全体コードです. debug-camera3d を使ったり ドラッグ & ドロップに対応したりとなんやかんやしています.

<!DOCTYPE html>

<html>
    
    <head>
        <meta charset="UTF-8">
        <title>gl.enchant.js で mqo ビューアー</title>
        <style>
            * {
                margin: 0px;
                padding: 0px;
            }
        </style>
        <script type="text/javascript" src="../js/gl.enchant.js/glMatrix-0.9.6.min.js"></script>
        <script type="text/javascript" src="../js/gl.enchant.js/enchant.js"></script>
        <script type="text/javascript" src="../js/gl.enchant.js/gl.enchant.js"></script>
        <script type="text/javascript" src="../js/gl.enchant.js/primitive.gl.enchant.js"></script>
        <script type="text/javascript" src="../js/gl.enchant.js/collada.gl.enchant.js"></script>
        <script type="text/javascript" src="debug-camera3d.gl.enchant.js"></script>
        <script type="text/javascript" src="mqo.gl.enchant.js"></script>
        <script>
            // おまじない
            enchant();
            
            //var MODEL_NAME = '../images/droid.dae';
            // var MODEL_NAME = 'model/planet.mqo';
            // var MODEL_NAME = 'model/skysphere.mqo';
            // var MODEL_NAME = 'model/inosisi.mqo';
            var MODEL_NAME = 'model/marukichi.mqo';
            
            DebugCamera3D.DEFAULT_DISTANCE = 24;
            
            window.onload = function() {
                var game = new Game(640, 640);
                game.fps = 60;
                game.keybind(90, 'a');      // z
                game.keybind(88, 'b');      // x
                game.keybind(32, "space");  // space
                                
                game.preload(MODEL_NAME);
                
                game.onload = function() {
                    // 3D 用シーン生成
                    var scene = new Scene3D();
                    scene.backgroundColor = [0.1, 0.2, 0.25, 1];
                    
                    // ライト生成
                    var light = new DirectionalLight(); // 平行光源生成
                    light.directionZ = 1;               // 向き
                    light.color = [1.0, 1.0, 1.0];      // 色
                    scene.setDirectionalLight(light);   // scene にセット
                    
                    // カメラ生成
                    var camera = new DebugCamera3D();   // カメラ生生
                    scene.setCamera(camera);            // scene にセット
                    camera.enable(game.rootScene);      // 有効化
                    
                    
                    // ターゲット
                    var target = new Sprite3D();        // 球体生成
                    target.x = target.y = target.z = 0; // 位置をセット
                    target.set(game.assets[MODEL_NAME]);
                    scene.addChild(target);             // scene にセット
                    
                    // モデルを回転
                    var phi   = 0;      // X軸回転値
                    var theta = 0;      // Y軸回転値
                    var offsetX = 0;    // touch の offsetX
                    var offsetY = 0;    // touch の offsetY
                    var matrix = new mat4.create(); // 回転行列用マトリックスバッファ
                    
                    // 更新イベント登録
                    game.rootScene.addEventListener("enterframe", function(e)
                    {
                        var input = game.input;
                        
                        // 十字キーによる回転
                        if (game.input.up)    { phi -= 0.05; }
                        if (game.input.down)  { phi += 0.05; }
                        if (game.input.right) { theta += 0.05; }
                        if (game.input.left)  { theta -= 0.05; }
                        
                        // Y軸, X軸回転行列を作成
                        mat4.identity(matrix);          // 単位行列化
                        mat4.rotateY(matrix, theta);    // Y軸回転
                        mat4.rotateX(matrix, phi);      // X軸回転
                        // 回転行列をセット
                        target.rotation = matrix;
                    });
                    
                    
                    document.ondragover  = function() { return false; };
                    document.ondragenter = function() { return false; };
                    document.ondrop = function(e) {
                        e.preventDefault();
                        var file    = e.dataTransfer.files[0];
                        var reader  = new FileReader();
                        var ext     = file.fileName.match(/\.\w+$/)[0];
                        if (ext) ext = ext.slice(1).toLowerCase();
                        var imageExt = { "png": true, "jpg": true, "bmp": true };
                        
                        if (ext == "mqo") {
                            // 現在のモデルを破棄して新たなモデルを追加
                            reader.onload = function(e) {
                                enchant.gl.Sprite3D.loadMqoFromData(e.target.result, function(model) {
                                    scene.removeChild(target);
                                    scene.addChild(model);
                                    target = model;
                                });
                            };
                        }
                        else if (imageExt[ext] === true) {
                            // 現在のモデルにテクスチャを貼り付ける
                            var texture = new Texture("texture/" + file.fileName);
                            for (var i=0,len=target.childNodes.length; i<len; ++i) {
                                var childNodeMesh = target.childNodes&#91;i&#93;.mesh;
                                childNodeMesh.texture = texture;
                            }
                        }
                        
                        reader.readAsText(file);
                    };
                };
                
                game.start();
                
            };
            
        </script>
    </head>
    <body>
    </body>
</html>

Plan

一応予定としている項目です.

スムージング角のサポート
今, 面法線か頂点法線のどちらか一方しか使えません. ちゃんと角度を比較してどちらかを選択するよう修正します.
日本語オブジェクトのサポート
日本語名のオブジェクトがあると止まります.
ミラー設定への対応
半分しか表示されないのはこの対応をしてないせいです. 近々ちゃんと対応します.
高速化
正規表現使いまくってたり, 配列への追加に push を使いまくっているのでちゃんと最適化します. 今より50%ぐらいは速度上がると思います.

Views

基本, 仕事ではモデルデータを扱うってなるとバイナリ化だったりバイナリ化したファイルの読み込みを作ったりするので, こういったテキストをパースしてってのは久々でなんか楽しかった.

メタセコはフリーウェアなので(シェアもあるけど)学生さんが1からモデル作って表示しながらゲーム作るにはもってこいな環境です. 私も学生の頃, かなりお世話になりました.

ぜひ, gl.enchant.js ゲーム制作に役立てて頂けたら幸いです.

あとちょっと気になったのが gl.enchant.js では gl.drawElements を使用しているのですが, gl.drawArrays の方が良いんじゃないかなと思いました. 基本的なプリミティブ以外は頂点を使いまわすことなんてそうそうないだろうし.(まるまる一個バッファ減るしね)

ふぅ~. 体調悪い... みなさん寒くなってきてるのでくれぐれも体にはお気をつけください.

そういえば, わりと真面目にモデルビューア作ったので近々公開します.

TRACK BACK URL

POST COMMENT

メールアドレスが公開されることはありません。

COMMENT