Three.jsを使って、作ってみた

プログラミング関連の事を色々書いています(^^) 週末はレストランやコンビニのお菓子のことを書いています。

Three.js 3Dモデルをマウスでクリック(ピッキング処理)

3Dプリンター楽しすぎです(笑)
「3Dプリンターで印刷できる3Dモデルを無料でダウンロード出来るサイト」って、ないのかな??
無いなら、つくろうかな・・・あると、便利な気がする。


今回は、「Three.jsの3Dモデル」をマウスでクリックする方法を書きます。

専門的には、「ピッキング処理」と言うのかな??
ちなみに、これはThree.jsの標準機能の一つです。

まずは、実際のソースコードから~
・クリック判定の部分(ピッキング処理)

var projector = new THREE.Projector();
//マウスのグローバル変数
var mouse = { x: 0, y: 0 };  
//オブジェクト格納グローバル変数
var targetList = [];         

//マウスが押された時
 window.onmousedown = function (ev){
    if (ev.target == renderer.domElement) { 
    
        //マウス座標2D変換
        var rect = ev.target.getBoundingClientRect();    
        mouse.x =  ev.clientX - rect.left;
        mouse.y =  ev.clientY - rect.top;
        
        //マウス座標3D変換 width(横)やheight(縦)は画面サイズ
        mouse.x =  (mouse.x / width) * 2 - 1;           
        mouse.y = -(mouse.y / height) * 2 + 1;
        
        // マウスベクトル
        var vector = new THREE.Vector3( mouse.x, mouse.y ,1);

       // vector はスクリーン座標系なので, オブジェクトの座標系に変換
        projector.unprojectVector( vector, camera );

        // 始点, 向きベクトルを渡してレイを作成
        var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
        
         // クリック判定
        var obj = ray.intersectObjects( targetList );
        
         // クリックしていたら、alertを表示  
        if ( obj.length > 0 ){                       
          
          alert("click!!")
          
       } 
 
    }
   }; 

・「立方体」の生成の部分

//「立方体」の生成
 var cube = new THREE.Mesh(
     //立方体の大きさ(300,300,300)                                           
     new THREE.CubeGeometry(300,300,300),                          
     new THREE.MeshPhongMaterial({                                      
               color: 0x990000 //球の色
      }));
        
 //sceneにcubeを追加
      scene.add(cube);       

//targetListにcubeを入れる
      targetList.push(cube);

これらの実行例がコレです。(分かりやすくするため、「地面」,「立方体にテクスチャ 貼付け」,「xyz軸」,を追加しています。)
f:id:gupuru:20131130192154p:plain
真ん中にある立方体をマウスで、クリックするとalertがでます。
f:id:gupuru:20131202182942p:plain
画像の通り、ちゃんとalertが出ています。どの角度からクリックしても反応します。

では、詳しく見ていきます。

重要なのは、

  var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
  var obj = ray.intersectObjects( targetList );
        
         // クリックしていたら、alertを表示  
        if ( obj.length > 0 ){                       
          
          alert("click!!")
          
       } 

ここです。ここで、3Dモデルがクリックされたかの判定を行っています。
THREE.Raycasterクラスには、「intersectObjects」という交差判定を行うメソッドが用意されています。
第一引数にメッシュのリストを渡すと、全てのメッシュとの交差判定を行うことができて、交差したメッシュのみのをリストとして返してくれます。
intersectObjectsの結果のlengthが0より大きければ、衝突しています。
targetListの中には、オブジェクトを入れています。

 targetList.push(cube);

このような形で、入れています。

次は、マウス座標を取得している所です。

//マウス座標2D変換①
var rect = ev.target.getBoundingClientRect();    
mouse.x =  ev.clientX - rect.left;
mouse.y =  ev.clientY - rect.top;
        
//マウス座標3D変換②
mouse.x =  (mouse.x / width) * 2 - 1;           
mouse.y = -(mouse.y / height) * 2 + 1;

①で取得したのは、マウス2D座標です。①の座標を②の部分で3D座標に変換しています。
width,heightは、画面サイズです。widthは横,heightは縦です。
「* 2 - 1」,「* 2 + 1」等で、X軸,Y軸共に「-1 ~ 1」の間に収まるように調整しています。



簡単に、マウスのクリック判定ができるので、便利です。
他にも、これを応用すると、「マウスカーソルが重なった時・・・」などのこともできます。


これで終わりです。
ご不明な点などがありましたら、遠慮なくご質問ください。
ありがとうございました!