SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

JavaScriptとWebGLによるはじめての3Dプログラミング

「three.js」でつくるお手軽3Dマンガ作成ソフト - 中編

JavaScriptとWebGLによるはじめての3Dプログラミング(2)

ダウンロード サンプル (335.2 KB)

レイキャスターを利用した移動2

レイキャスターを利用した移動2
レイキャスターを利用した移動2

 「レイキャスターを利用した移動1」では、1つの3Dオブジェクトを選択して移動する方法を紹介しました。しかし、実際にゲームやツールにこういったUIを使う場合は、複数あるオブジェクトから、任意の一つのオブジェクトを選択して移動したくなるでしょう。

 「three.js」の「Raycaster」では、こういった処理に対応しています。前回説明しなかった、「intersectObject」関数の第2引数をtrueにすることで、複数の3Dオブジェクトを再帰的に検索して、光線が当たるすべての3Dオブジェクトを配列にして戻してくれます。

 さて、この「複数の3Dオブジェクト」ですが、シーン中のすべてのオブジェクトではありません。指定したグループ配下のオブジェクトになります。そのため、まずはオブジェクトをグループ化する必要があります。

 オブジェクトのグループは「Object3D」オブジェクトで行えます。「add」関数で3Dオブジェクトを追加してグループ化します。「intersectObject」関数の第1引数にこのグループを指定して、第2引数をtrueにすれば、光線が当たったオブジェクトの配列を得ることができます。

 光線が当たったオブジェクトの参照は「intersects[ ].object」に格納されています。マウスの移動開始時点で、どのオブジェクトを選択したか記録しておけば、複数のオブジェクトが戻り値として戻ってきた場合も、操作対象を限定できます。

 以下、レイキャスターを利用して、複数の3Dオブジェクトから、任意のオブジェクトを移動する「crocro.bc.useRaycaster2.js」を掲載します。

「crocro.bc.useRaycaster2.js」
//= サンプル:レイキャスターを利用した移動

//== レイキャスターを利用した移動
crocro.bc.useRaycaster2 = function() {
    // 変数の初期化
    var d3 = crocro.bc.d3;    // 3D格納用
    var group = new THREE.Object3D();    // グループ

    // 要素の作成と格納
    plt = crocro.bc.mkColPlate(0xff0000);
    plt.position.x = 50;
    plt.position.y = 50;
    plt.scale.x = 2;
    plt.scale.y = 2;
    plt.scale.z = 2;
    group.add(plt);

    plt = crocro.bc.mkColPlate(0x000ff0);
    plt.position.x = -50;
    plt.position.y = -50;
    plt.position.z = 2;
    plt.scale.x = 2;
    plt.scale.y = 2;
    plt.scale.z = 2;
    group.add(plt);

    d3.scene.add(group);

    crocro.bc.render();

    // マウス操作の作成
    d3.tgtGrp = group;
    crocro.bc.useRaycaster2_setMouse();

    // 終了処理
    crocro.bc.setFinalize(function() {
        var d3 = crocro.bc.d3;    // 3D格納用
        d3.tgtGrp = null;
        d3.tgtSel = null;
        d3.prjctr = null;
    })
};

//== マウス操作の作成
crocro.bc.useRaycaster2_setMouse = function() {
    // 変数の初期化
    var d3 = crocro.bc.d3;    // 3D格納用
    var cntnr = crocro.bc.cntnr;    // コンテナー

    var isAct = false;
    var posX, posY;
    var prjctr = new THREE.Projector();    // プロジェクター
    var offset = new THREE.Vector3();

    //=== イベントを元に光線の交差判定
    var chckIntrsct = function(event) {
        // 中心からの位置の取得
        posX = event.pageX - cntnr.offset().left;
        posY = event.pageY - cntnr.offset().top;

        // 描画範囲の比率に変換
        posX =  (posX / d3.w) * 2 - 1;
        posY = -(posY / d3.h) * 2 + 1;

        // マウス座標の作成
        var vector = new THREE.Vector3(posX, posY, 1);

        // スクリーン座標系をオブジェクトの座標系に変換
        prjctr.unprojectVector(vector, d3.camera);

        // レイキャスターを作成
        var ray = new THREE.Raycaster(
            d3.camera.position,        // 始点
            vector.sub(d3.camera.position).normalize()    // 向きベクトル
        );

        // 交差判定
        var intersects = ray.intersectObject(d3.tgtGrp, true);

        // 結果を戻す
        return intersects;
    };

    //=== マウス操作 開始
    var msStrt = function(event) {
        isAct = true;    // 動作状態に移行

        // イベントを元に光線の交差判定
        var intersects = chckIntrsct(event);

        // 有効か確認
        if (intersects.length > 0) {
            // 操作対象を決定
            d3.tgtSel = intersects[0].object;

            // 交差したのでオフセットを記録
            offset.copy(intersects[0].point).sub(d3.tgtSel.position);
        } else {
            isAct = false;    // 動作状態を解除
        }
    };

    //=== マウス操作 移動
    var msMv = function(event) {
        // 動作状態でなければ終了
        if (! isAct) {return;}

        // イベントを元に光線の交差判定
        var intersects = chckIntrsct(event);

        // 有効か確認
        if (intersects.length > 0) {
            // 開始時と同じ対象を選択
            var tgtIntrsct = intersects[0];
            for (var i = 0; i < intersects.length; i ++) {
                if (intersects[i].object == d3.tgtSel) {
                    tgtIntrsct = intersects[i];
                    break;
                }
            }

            // 交差しているので移動
            var pos = tgtIntrsct.point.sub(offset);
            d3.tgtSel.position = pos;
        }

        // レンダリング
        crocro.bc.render();
    };

    //=== マウス操作 終了
    var msEnd = function() {
        isAct = false;    // 動作状態を解除
    };

    //=== マウス操作の登録
    cntnr.mousedown(msStrt);
    cntnr.mousemove(msMv);
    cntnr.mouseup(msEnd);
    $(window).blur(msEnd);
}

次のページ
クォータニオンによる回転

この記事は参考になりましたか?

JavaScriptとWebGLによるはじめての3Dプログラミング連載記事一覧

もっと読む

この記事の著者

柳井 政和(ヤナイ マサカズ)

クロノス・クラウン合同会社 代表社員http://crocro.com/オンラインソフトを多数公開。プログラムを書いたり、ゲームを作ったり、記事を執筆したり、マンガを描いたり、小説を書いたりしています。「めもりーくりーなー」でオンラインソフト大賞に入賞。最近は、小説家デビューして小説も書いています(『裏切りのプログラム』他)。面白いことなら何でもOKのさすらいの企画屋です。 

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/7209 2013/06/24 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー