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

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

Three.js 2画面表示

今回は、Three.jsで「2画面表示させる方法」を書きます。


2画面表示とは、こんな感じの事です。
f:id:gupuru:20131223194344p:plain
左と右、別々の事を表示させています。
ちなみに、左が立方体を上から見た画面で、右が真横からみたものです。


2画面表示させる方法は、簡単に説明しますと、カメラを2つ作り、シーンオブジェクトに追加するというものです。

やり方を書いていきます。

レンダラーオブジェクトを生成した後に、こちらを追加してください。

//rendererはレンダラーオブジェクト
 renderer.autoClear = false     

これを追加しないと、描画されません。
autoClearはWebGLRendererのプロパティの一つです。



カメラオブジェクトを2つ作ります。

//カメラオブジェクトを2つ作る。cameraLは左画面,cameraRは右画面です。
//position,lookAtは任意で追加してください。                                                                      
                                                                                                                         
var cameraL = new THREE.PerspectiveCamera( 45 , width / height , 1 , 10000 );     
scene.add(cameraL);
cameraL.position.set(100, 300, 500);     
cameraL.lookAt(scene.position);                                 
   
var cameraR = new THREE.PerspectiveCamera( 45 , width / height , 1 , 10000 );
scene.add(cameraR);
cameraR.position.set(0, 0, 569);  
cameraR.lookAt(scene.position);   


実際の描画処理の部分です。
これらを無限ループ関数に追加します。

var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
cameraL.aspect = 0.5 * SCREEN_WIDTH / SCREEN_HEIGHT;
cameraR.aspect = 0.5 * SCREEN_WIDTH / SCREEN_HEIGHT;
cameraR.updateProjectionMatrix();
cameraL.updateProjectionMatrix();
      
renderer.setViewport( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
renderer.clear();   
       
//左画面       
renderer.setViewport( 1, 1,   0.5 * SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2 );
renderer.render( scene, cameraL );
       
//右画面      
renderer.setViewport( 0.5 * SCREEN_WIDTH + 1, 1,   0.5 * SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2 );
renderer.render( scene, cameraR );          

「cameraL.aspect」でアスペクト比を調節しています。
updateProjectMatrix()は、カメラの内部状態を更新するものです。

以上で終わりです。

次に、青い立方体を表示するプログラムに「2画面表示」,「Orbitcontrols.js」を追加したコードを全文書きます。

<!DOCTYPE html>
<html>
  <head>
    <title>introduction</title>
        <meta charset="utf-8">
            <script src="Three.js"></script>
            <script src="OrbitControls.js"></script>
            <link rel="stylesheet" type="text/css" href="mobile/screan.css">
  </head>
        <body onload="threeStart();" , style="overflow: hidden;">
             <div id="canvas-frame"></div>
            <script>
  var width, height;                                                                  
  var renderer;                                                                    
  function initThree() {
    width = document.getElementById('canvas-frame').clientWidth;                  
    height =  document.getElementById('canvas-frame').clientHeight;               
    renderer = new THREE.WebGLRenderer({antialias: true});                      
    renderer.setSize(width, height);                                            
    document.getElementById('canvas-frame').appendChild(renderer.domElement);  
    renderer.shadowMapEnabled = true;           
    renderer.autoClear = false                             
  }

  var cameraL,cameraR;                                      
  var controls;                                                                    
  function initCamera() {                                                        
    cameraL = new THREE.PerspectiveCamera( 45 , width / height , 1 , 10000 );     
    scene.add(cameraL);
    cameraL.position.set(100, 300, 500);     
    cameraL.lookAt(scene.position);                                 
     
    cameraR = new THREE.PerspectiveCamera( 45 , width / height , 1 , 10000 );
    scene.add(cameraR);
    cameraR.position.set(0, 0, 569);  
    cameraR.lookAt(scene.position);   
    controls = new THREE.OrbitControls(cameraR);           
  }

  var scene;
  function initScene() {    
    scene = new THREE.Scene();
  }
  
  var light, light2;                                                
  function initLight() {                                          
    light = new THREE.DirectionalLight(0xcccccc,1.6);            
    light.position = new THREE.Vector3(-100, 500, 800);      
    light.castShadow = true;                                     
    light.shadowMapWidth = 2048;
    light.shadowMapHeight = 2048;
    scene.add(light);                                          
     
    light2 = new THREE.AmbientLight(0x333333);               
    scene.add(light2);                                    
  }

 var cube,plane;                                                     
  function initObject(){
  
        cube = new THREE.Mesh(                                         
                  new THREE.CubeGeometry(80,80,80),                       
                  new THREE.MeshPhongMaterial({                          
                     color: 0x0000ff,
                      wireframe:false                   
                       }));   
      cube.castShadow = true;   
       cube.receiveShadow = true;   
      scene.add(cube);                                             
      cube.position.set(0,100,100);                                  
      
     plane =  new THREE.Mesh(                                     
             new THREE.PlaneGeometry(1000, 1000, 10, 10),
              new THREE.MeshLambertMaterial({                      
                side: THREE.DoubleSide,                           
                 color: 0xCD5C5C                                              
                }));                      
        plane.position.set(0,0,1);                   
       plane.receiveShadow = true;
     scene.add(plane);                                
  }
      
  function loop(){  
          
        controls.update();   
        requestAnimationFrame(loop);
           
        var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
        cameraL.aspect = 0.5 * SCREEN_WIDTH / SCREEN_HEIGHT;
        cameraR.aspect = 0.5 * SCREEN_WIDTH / SCREEN_HEIGHT;
        cameraR.updateProjectionMatrix();
        cameraL.updateProjectionMatrix();
      
        renderer.setViewport( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
        renderer.clear();   
       
        renderer.setViewport( 1, 1,   0.5 * SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2 );
        renderer.render( scene, cameraL );
       
        renderer.setViewport( 0.5 * SCREEN_WIDTH + 1, 1,   0.5 * SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2 );
        renderer.render( scene, cameraR ); 
    }
   
  function threeStart() {
    initThree(); 
    initScene();    
    initCamera();
    initLight();
    initObject();
    loop();     
  }
           </script>
        </body>
</html>
div#canvas-frame{
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background-color: #EEEEEE;
}


2画面表示を少し応用すると、4画面表示なども出来るようです。


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