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にコンパイルしてください。
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 ); } )(); });