2016年11月20日日曜日

Three.jsで3Dオブジェクトをドラッグして移動させる

Three.js(r79)で、3Dオブジェクトをマウスで移動させてみる。具体的には、平面を作成して、その平面に対して立法体が平行に移動するようにする。


1.jsファイルの読み込み


three.min.jsとTrackballControlsを読み込む。ともにjs_r79というディレクトリにあるとする。




2.オブジェクトの作成


Three.jsで立法体を2つ作成して表示できるようにする。

// オブジェクトを格納する配列
var objects = [];

// シーンの作成
var scene = new THREE.Scene();
// カメラの作成
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
// レンダラーの作成
var renderer = new THREE.WebGLRenderer();

// レンダラーが描画するキャンバスサイズの設定
renderer.setSize( window.innerWidth, window.innerHeight );
// キャンバスをDOMツリーに追加
document.body.appendChild( renderer.domElement );

// TrackballControlsインスタンス作成
var controls = new THREE.TrackballControls( camera );

// ジオメトリーの作成
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
// マテリアルの作成
var material = new THREE.MeshNormalMaterial( { color: 0x00ff00 } );
// オブジェクトの作成
var cube = new THREE.Mesh( geometry, material );
// オブジェクトの位置調整
cube.position.x = 2.0;
// オブジェクトをシーンに追加
scene.add( cube );
objects.push( cube );

// オブジェクトを複製
var cube2 = cube.clone();
// オブジェクトの位置調整
cube.position.x = -2.0;
// オブジェクトをシーンに追加
scene.add( cube2 );
objects.push( cube2 );

// カメラ位置設定
camera.position.z = 5;
camera.position.x = 0.5;
camera.position.y = 0.5;

animate();
function animate() {
 requestAnimationFrame( animate );
 controls.update();
 renderer.render( scene, camera );
}

3.マウスイベントの追加


mousedown、mousemove、mouseupイベントのリスナーを登録する。平面を作成し、平面に対して平行に立法体を移動させる。平面の角度は、カメラの角度に合わせて変化させる(TrackballControlsで視点が変化するため)。

// この平面に対してオブジェクトを平行に動かす
var plane = new THREE.Plane();

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var offset = new THREE.Vector3();
var intersection = new THREE.Vector3();

// マウスオーバーしているオブジェクト
var mouseoveredObj;
// ドラッグしているオブジェクト
var draggedObj;

renderer.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
renderer.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );

function onDocumentMouseDown( event ) {
 event.preventDefault();

 raycaster.setFromCamera( mouse, camera );
 var intersects = raycaster.intersectObjects( objects );

 if ( intersects.length > 0 ) {
  // マウスドラッグしている間はTrackballControlsを無効にする
  controls.enabled = false;

  draggedObj = intersects[ 0 ].object;

  // rayとplaneの交点を求めてintersectionに設定
  if ( raycaster.ray.intersectPlane( plane, intersection ) ) {
   // ドラッグ中のオブジェクトとplaneの距離
   offset.copy( intersection ).sub( draggedObj.position );
  }
 }
}

function onDocumentMouseMove( event ) {
 event.preventDefault();

 mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
 mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

 raycaster.setFromCamera( mouse, camera );

 if ( draggedObj ) {
  // オブジェクトをドラッグして移動させているとき

  // rayとplaneの交点をintersectionに設定
  if ( raycaster.ray.intersectPlane( plane, intersection ) ) {
   // オブジェクトをplaneに対して平行に移動させる
   draggedObj.position.copy( intersection.sub( offset ) );
  }
 } else {
  // オブジェクトをドラッグしないでマウスを動かしている場合
  var intersects = raycaster.intersectObjects( objects );

  if ( intersects.length > 0 ) {
   if ( mouseoveredObj != intersects[ 0 ].object ) {
    // マウスオーバー中のオブジェクトを入れ替え
    mouseoveredObj = intersects[ 0 ].object;

    // plane.normalにカメラの方向ベクトルを設定
    // 平面の角度をカメラの向きに対して垂直に維持する
    camera.getWorldDirection( plane.normal );
   }
  } else {
   mouseoveredObj = null;
  }
 }
}

function onDocumentMouseUp( event ) {
 event.preventDefault();

 controls.enabled = true;

 if ( mouseoveredObj ) {
  draggedObj = null;
 }
}

4.実行結果


1~3を合わせると、以下のように立法体が2つ表示され、マウスでドラッグして移動させることができる。


0 件のコメント:

コメントを投稿