three.js r73
 cannon.js 0.6.2
 Google Chrome 46.0.2490.86 m

■CSS3DRenderer.js [ サンプルページの表示 ] Prev Top Next
関連ページ:

今回はCSS3DRenderer.jsを使用します。
まずはCSS3DRenderer.jsをGitHubの three.js/examples/js/renderers/ からダウンロードしてください。

CSS3DRenderer.js は3D空間内で座標を指定してDOMをレンダリングするというものです。

なお実装にはCSS-EBLOGを参考にしました。

例によってTypeScript使ってますので PlayGround サイトでJavaScriptにコンパイルしてください。


---javascript.ts---  ↑
class myThree
{
   private renderer = null;
   private camera = null;
   private scene = null;
   
   private width: number = 600;
   private height: number = 400;

   // レンダラ―作成
   private createRenderer()
   {
      // レンダラ―は CSS3DRenderer.js を使用する
      var renderer = new THREE.CSS3DRenderer();
      renderer.setSize( this.width, this.height );
      
      return renderer;
   }

   // カメラ作成
   private createCamera()
   {
      const fov:number = 60;
      const aspect:number = this.width / this.height;
      const znear:number = 1.0;
      const zfar:number = 1000.0;
      var camera = new THREE.PerspectiveCamera( fov, aspect, znear, zfar );
      // カメラ視点
      camera.position.set( 0.0, 0.0, 50.0 );
      // カメラの注視点
      camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
      
      return camera;
   }

   // 地面メッシュ作成
   public createPlaneMesh()
   {
      // メッシュの代わりにDOMを作成する
      var element = document.createElement('div');
      element.style.width = "100px";
      element.style.height = "100px";
      var css = new THREE.CSS3DObject(element); 
      var img = document.createElement('img');
      img.width = 100;
      img.height = 100;
      img.src = 'Contents/Texture1.png';
      css.add( new THREE.CSS3DObject(img) );
      css.position.y = -15;
      css.rotation.x = Math.PI / 2;
      
      this.scene.add( css );
      
      return css;
   }

   // 箱じゃないけど箱作成
   public createBoxMesh()
   {
      var element = document.createElement('div');
      element.style.width = "20px";
      element.style.height = "20px";
      var css = new THREE.CSS3DObject(element); 
      var img = document.createElement('img');
      img.width = 20;
      img.height = 20;
      img.src = 'Contents/Texture.png';
      css.add( new THREE.CSS3DObject(img) );
      css.position.y = 15;
      
      this.scene.add( css );
      
      return css;
   }
   
   // シーン作成
   private createScene()
   {
      var scene = new THREE.Scene();
      return scene;
   }
   
   // Three作成
   public createTHREE()
   {
      if( this.renderer == null )
      {
         this.renderer = this.createRenderer();
         document.body.appendChild( this.renderer.domElement );
      }
      
      if( this.camera == null )
      {
         this.camera = this.createCamera();
      }
      
      this.scene = this.createScene();
   }

   // レンダリング
   public render()
   {
      if( this.renderer != null )
      {
         this.renderer.render( this.scene, this.camera );      
      }
   }
   
   public dispose()
   {
      if( this.renderer != null )
      {
         var element = document.getElementsByTagName("canvas");
         if( element.length == 1 )
         {
            document.body.removeChild(element[0]);
         }
         this.renderer.dispose();
         this.renderer = null;
      }
      this.camera = null;
   }
}

class myCannon
{
   private world = null;
   
   public createWorld()
   {
      // CANNONの世界を生成
      this.world = new CANNON.World();  
  
      // 重力加速度を設定
      this.world.gravity.set(0, -9.82, 0);  
      
      // 衝突している可能性のある剛体同士を見つける。
      // 本当に衝突しているか、衝突しているとしてどの程度めり込んでいるかは別途ナローフェーズで行う。
      this.world.broadphase = new CANNON.NaiveBroadphase();  

      // 反復計算回数
      this.world.solver.iterations = 10;  

      // 許容値。ある程度の誤差を許容することで不安定さを解消する。
      this.world.solver.tolerance = 0.1;  
   }
   
   public createPlane(width:number, height:number, depth:number, position:CANNON.Vec3, quaternion:CANNON.Quaternion)
   {
      var plane = new CANNON.Box(new CANNON.Vec3(width, height, depth));
      
      // 質量
      var mass:number = 0;
      
      var body = new CANNON.Body({mass:mass});
      body.position.copy( position );
      body.quaternion.copy( quaternion );
      
      body.addShape( plane );
      
      this.world.add( body );
      
      return body;
   }

   public createBox(width:number, height:number, depth:number, position:CANNON.Vec3, quaternion:CANNON.Quaternion)
   {
      var box = new CANNON.Box(new CANNON.Vec3(width, height, depth));
      
      // 質量
      var mass:number = 1;
      
      var body = new CANNON.Body({mass:mass});
      body.position.copy( position );
      body.quaternion.copy( quaternion );

      body.addShape( box );
      
      // z軸に1の角速度
      body.angularVelocity.set(0, 0, 1); 
      
      // 回転の減衰係数
      body.angularDamping = 0.1;  
      
      this.world.add( body );
      
      return body;
   }
   
   // FPS:1/60で更新
   public animationWorld()
   {
      this.world.step( 1/60 );
   }
}

class FPS
{
   private dispFrame: number = 0;
   private frame: number = 0;
   private timer: Date = new Date();
   
   public getFPS()
   {
      var now = new Date();
      
      // 1秒経過してない
      if( now.getTime() - this.timer.getTime() < 1000 )
      {
         this.frame++;
      }
      else
      {
         this.timer = now;
         this.dispFrame = this.frame;
         this.frame = 0;
      }
      
      return this.dispFrame;
   }
}

var mythree = new myThree();
var fps = new FPS();
var mesh = [];
var mycannon = new myCannon();
var body = [];

// cannon.jsで座標と姿勢を計算した値をthree.jsにコピーする
function animationMesh()
{
   for( var i=0; i<mesh.length; i++ )
   {
      mesh[i].position.copy( body[i].position );
      mesh[i].quaternion.copy( body[i].quaternion );
   }
}

// シーンの初期化
window.addEventListener('load', () =>
{
   if( mythree != null )
   {
      mythree.createTHREE();

      mesh[0] = mythree.createPlaneMesh();
      mesh[1] = mythree.createBoxMesh();
   }
   
   if( mycannon != null )
   {
      mycannon.createWorld();
      
      // THREE.jsと異なり半分の大きさで指定する
      body[0] = mycannon.createPlane(mesh[0].children[0].element.width / 2,
                                     mesh[0].children[0].element.height / 2,
                                     0.1,
                                     mesh[0].position,
                                     mesh[0].quaternion);

      body[1] = mycannon.createBox( mesh[1].children[0].element.width / 2,
                                    mesh[1].children[0].element.height / 2,
                                    0.1,
                                    mesh[1].position,
                                    mesh[1].quaternion);
   }
});

// メインループ
window.addEventListener('load', () =>
{
   ( function renderLoop ()
      {
         requestAnimationFrame( renderLoop );
         mycannon.animationWorld();
         animationMesh();
         
         mythree.render();

         // FPS表示
         var frame = fps.getFPS();
         $("div.fps").html( "FPS:" + frame );         
      }
   )();
});

Prev Top Next
inserted by FC2 system