three.js を使った3Dモデル表示 part2


three.jsの更新が途絶えて１年近く経ってしまいました。
そろそろまとめたいと思います。

今回はカメラを移動させたいと思います。

htmlは一緒で、3DRender.jsに少し書き加えます。

render() 関数より下に追記しています。

**コード**

```3DRender.js
var scene,      // レンダリングするオブジェクトを入れる
    objmodel,   // モデルデータを入れる
    obj,        // モデルデータの角度などを変更するために重ねる
    camera,     // カメラのオブジェクト
    light,      // 太陽光のような光源のオブジェクト
    ambient,    // 自然光のような光源のオブジェクト
    axis,       // 補助線のオブジェクト
    renderer;   // 画面表示するためのオブジェクト

    // キー入力を受け取るための変数群
var a_push, s_push, d_push, w_push, up_push, down_push,
    q_push, e_push, r_push, zeroLook;


var Xrotate = 0,    // 回転した値を保存
    Radius;         // 3Dモデルからカメラまでの距離

init();
animate();

function　init (){


    var width  = 1000,  // 表示サイズ 横
        height = 600;   // 表示サイズ 縦

    Radius = 500;       // カメラの半径;

    scene = new THREE.Scene();      // 表示させるための大元、すべてのデータをこれに入れ込んでいく。

    // obj mtl を読み込んでいる時の処理
    var onProgress = function ( xhr ) {
        if ( xhr.lengthComputable ) {
            var percentComplete = xhr.loaded / xhr.total * 100;
            console.log( Math.round(percentComplete, 2) + '% downloaded' );
            }
    };

    // obj mtl が読み込めなかったときのエラー処理
    var onError = function ( xhr ) {    };

    // obj mtlの読み込み
    var ObjLoader = new THREE.OBJMTLLoader(); 
    ObjLoader.load("A6M_ZERO/zero2.obj", "A6M_ZERO/zero2.mtl",  function (object){
        objmodel = object.clone();
        objmodel.scale.set(10, 10, 10);            // 縮尺の初期化
        objmodel.rotation.set(0, 0, 0);         // 角度の初期化
        objmodel.position.set(0, 0, 0);         // 位置の初期化

    // objをObject3Dで包む
        obj = new THREE.Object3D();
        obj.add(objmodel);

        scene.add(obj);                     // sceneに追加
    }, onProgress, onError);        // obj mtl データは(.obj, .mtl. 初期処理, 読み込み時の処理, エラー処理)
                                    // と指定する。

    //light
    light = new THREE.DirectionalLight("white", 1);
    light.position.set(30, 200, 30);
    light.castShadow = true;
    scene.add(light);

    ambient = new THREE.AmbientLight(0xffffff);
    scene.add(ambient);

    //camera
    camera = new THREE.PerspectiveCamera(45, width / height, 1, 5000);
    camera.position.set(0, 0, 500);
    //camera.position.x = 0;
    //camera.position = new THREE.Vectror3(0,0,0); のような書き方もある


    // hepler
    axis = new THREE.AxisHelper(2000);  // 補助線を2000px分表示
    axis.position.set(0,-1,0);          // 零戦の真ん中に合わせるため、少しずらす
    scene.add(axis);

    // 画面表示
    renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height);        // 画面の大きさを設定
    renderer.setClearColor(0xeeeeee, 1);    
    renderer.shadowMapEnabled = true;       
    // html の container というid に追加
    document.getElementById('container').appendChild(renderer.domElement);

}

// 値を変更させる処理
function animate() {
    requestAnimationFrame(animate);     // フレームと再描画を制御してくれる関数。
                                        // そのブラウザのタブが非表示のとき、描画頻度が自動で低下するので、
                                        // メモリの消費を抑えることができる。
    cameramove();   // カメラ移動
    render();       // 再描画処理
}

function render() {
    renderer.render(scene, camera); // 再描画
}

function cameramove(){
    if(a_push)   { --Xrotate; }     // 時計回り
    if(d_push)   { ++Xrotate; }     // 反時計回り    
    if(Xrotate == -360 || 360 == Xrotate){ Xrotate = 0; }   // Xrotateが 360 を越えたら 0 で初期化
    
    // カメラ位置(零戦までの距離)を400〜1000までに制限
    if(200 < Radius){
        if(down_push){ Radius -= 10; }
    }
    if(Radius < 1000){
        if(up_push)  { Radius += 10; }
    }
    
    if(s_push)   {  // カメラ上移動
        if(-600 < camera.position.y){
            camera.position.y -= 10; 
        }
    }
    if(w_push)   {  // カメラ下移動
        if(camera.position.y < 600){
            camera.position.y += 10;
        }
    }

    // カメラの視点回転の計算
    camera.position.x = Radius * Math.sin(Xrotate * Math.PI / 180);
    camera.position.z = Radius * Math.cos(Xrotate * Math.PI / 180);
    
    // 常時の方向を向かせる
    if(zeroLook) { camera.lookAt(obj.position);}
}

// キーを押した時の処理
document.onkeydown = KeyDownFunc;
function KeyDownFunc(e){

    switch ( e.keyCode ) {
    case 65: // 左 A
        a_push = true;
        zeroLook = true;
        break;
    case 83: // 下 S
        s_push = true;
        zeroLook = true;
        break;
    case 68: // 右 D
        d_push = true;
        zeroLook = true;
        break;
    case 87: // 上 W
        w_push = true;
        zeroLook = true;
        break;
    case 219: // 手前 down
        down_push = true;
        break;
    case 221: // 奥 up
        up_push = true;
        break;
}
// キーを離した時の処理
document.onkeyup = KeyUpFunc;
function KeyUpFunc(e){

	switch ( e.keyCode ) {
    case 65: // 左 A
        a_push = false;
        break;
    case 83: // 下 S
        s_push = false;
        break;
    case 68: // 右 D
        d_push = false;
        break;
    case 87: // 上 W
        w_push = false;
        break;
    case 219: // 手前 down
        down_push = false;
        break;
    case 221: // 奥 up
        up_push = false;
        break;
	}
}
```

キーイベントを受け取り、その値でカメラの座標を変えています。
カメラの座標を変えただけだとオブジェクトが見えなくなるので、
lookAt関数を使うことで指定したオブジェクト方向にカメラの角度合わせています。
part1のコードに追記して実行してみてください

**開発環境**
MacOSX Yosemite 10.10.5
SublimeText3
MAMP varsion 3.4


自分の触った範囲では、モデルを表示し角度や全方位から見回せるようなコードまでしか触ってないので、モデルにモーションを付けたり、VR対応させたり色々試してみたいと思います。