SkyDrive へ移動 WinJS ストア : 『背景画像をチェンジする2画面アプリ』のテンプレート を元に、2画面目で Three.js の canvas_geometry_birds を組み込んで通常の Bird をテスト飛行させてから、平面画像で飛ばすように変更しています。元々、WEB ベースの Three.js で実装済だったものを、Windows ストアの JavaScript で実装しました。製品版になる前より、Three.js の Canvas バージョンは動作する事が解っていましたが、今回あらためて動作確認しました。但し、飛ばせる数は WEBブラウザよりはかなり少なくなります。 ▼ 飛ばす画像( 背景透過 ) もともと、Bird(3Dデータ) は簡単なアニメーションで成り立っています。その羽ばたき部分を平面画像の各頂点の移動に変えて実現しています。 ですから、ソースコード上の Bird オプジェクトは使用せずに、THREE.PlaneGeometry を使用しており、マテリアルとして画像をテクスチャ使用しています。また、さらに material.side = 2 なので両面仕様です。 ( THREE.FrontSide=0;THREE.BackSide=1;THREE.DoubleSide=2 )
texture = new THREE.Texture(this); texture.needsUpdate = true; material = new THREE.MeshBasicMaterial({ map: texture, overdraw: true }); material.side = 2
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight, SCREEN_WIDTH_HALF = SCREEN_WIDTH / 2, SCREEN_HEIGHT_HALF = SCREEN_HEIGHT / 2; var camera, scene, renderer = null, birds, bird; var boid, boids; var Bird = function () { var scope = this; THREE.Geometry.call( this ); v( 5, 0, 0 ); v( - 5, - 2, 1 ); v( - 5, 0, 0 ); v( - 5, - 2, - 1 ); v( 0, 2, - 6 ); v( 0, 2, 6 ); v( 2, 0, 0 ); v( - 3, 0, 0 ); f3( 0, 2, 1 ); // f3( 0, 3, 2 ); f3( 4, 7, 6 ); f3( 5, 6, 7 ); this.computeCentroids(); this.computeFaceNormals(); function v( x, y, z ) { scope.vertices.push( new THREE.Vector3( x, y, z ) ); } function f3( a, b, c ) { scope.faces.push( new THREE.Face3( a, b, c ) ); } } Bird.prototype = Object.create( THREE.Geometry.prototype ); var Boid = function () { var vector = new THREE.Vector3(), _acceleration, _width = 500, _height = 500, _depth = 200, _goal, _neighborhoodRadius = 100, _maxSpeed = 4, _maxSteerForce = 0.1, _avoidWalls = false; this.position = new THREE.Vector3(); this.velocity = new THREE.Vector3(); _acceleration = new THREE.Vector3(); this.setGoal = function (target) { _goal = target; } this.setAvoidWalls = function (value) { _avoidWalls = value; } this.setWorldSize = function (width, height, depth) { _width = width; _height = height; _depth = depth; } this.run = function (boids) { if (_avoidWalls) { vector.set(-_width, this.position.y, this.position.z); vector = this.avoid(vector); vector.multiplyScalar(5); _acceleration.add(vector); vector.set(_width, this.position.y, this.position.z); vector = this.avoid(vector); vector.multiplyScalar(5); _acceleration.add(vector); vector.set(this.position.x, -_height, this.position.z); vector = this.avoid(vector); vector.multiplyScalar(5); _acceleration.add(vector); vector.set(this.position.x, _height, this.position.z); vector = this.avoid(vector); vector.multiplyScalar(5); _acceleration.add(vector); vector.set(this.position.x, this.position.y, -_depth); vector = this.avoid(vector); vector.multiplyScalar(5); _acceleration.add(vector); vector.set(this.position.x, this.position.y, _depth); vector = this.avoid(vector); vector.multiplyScalar(5); _acceleration.add(vector); }/* else { this.checkBounds(); } */ if (Math.random() > 0.5) { this.flock(boids); } this.move(); } this.flock = function (boids) { if (_goal) { _acceleration.add(this.reach(_goal, 0.005)); } _acceleration.add(this.alignment(boids)); _acceleration.add(this.cohesion(boids)); _acceleration.add(this.separation(boids)); } this.move = function () { this.velocity.add(_acceleration); var l = this.velocity.length(); if (l > _maxSpeed) { this.velocity.divideScalar(l / _maxSpeed); } this.position.add(this.velocity); _acceleration.set(0, 0, 0); } this.checkBounds = function () { if (this.position.x > _width) this.position.x = -_width; if (this.position.x < -_width) this.position.x = _width; if (this.position.y > _height) this.position.y = -_height; if (this.position.y < -_height) this.position.y = _height; if (this.position.z > _depth) this.position.z = -_depth; if (this.position.z < -_depth) this.position.z = _depth; } // this.avoid = function (target) { var steer = new THREE.Vector3(); steer.copy(this.position); steer.sub(target); steer.multiplyScalar(1 / this.position.distanceToSquared(target)); return steer; } this.repulse = function (target) { var distance = this.position.distanceTo(target); if (distance < 150) { var steer = new THREE.Vector3(); steer.subVectors(this.position, target); steer.multiplyScalar(0.5 / distance); _acceleration.add(steer); } } this.reach = function (target, amount) { var steer = new THREE.Vector3(); steer.subVectors(target, this.position); steer.multiplyScalar(amount); return steer; } this.alignment = function (boids) { var boid, velSum = new THREE.Vector3(), count = 0; for (var i = 0, il = boids.length; i < il; i++) { if (Math.random() > 0.6) continue; boid = boids[i]; distance = boid.position.distanceTo(this.position); if (distance > 0 && distance <= _neighborhoodRadius) { velSum.add(boid.velocity); count++; } } if (count > 0) { velSum.divideScalar(count); var l = velSum.length(); if (l > _maxSteerForce) { velSum.divideScalar(l / _maxSteerForce); } } return velSum; } this.cohesion = function (boids) { var boid, distance, posSum = new THREE.Vector3(), steer = new THREE.Vector3(), count = 0; for (var i = 0, il = boids.length; i < il; i++) { if (Math.random() > 0.6) continue; boid = boids[i]; distance = boid.position.distanceTo(this.position); if (distance > 0 && distance <= _neighborhoodRadius) { posSum.add(boid.position); count++; } } if (count > 0) { posSum.divideScalar(count); } steer.subVectors(posSum, this.position); var l = steer.length(); if (l > _maxSteerForce) { steer.divideScalar(l / _maxSteerForce); } return steer; } this.separation = function (boids) { var boid, distance, posSum = new THREE.Vector3(), repulse = new THREE.Vector3(); for (var i = 0, il = boids.length; i < il; i++) { if (Math.random() > 0.6) continue; boid = boids[i]; distance = boid.position.distanceTo(this.position); if (distance > 0 && distance <= _neighborhoodRadius) { repulse.subVectors(this.position, boid.position); repulse.normalize(); repulse.divideScalar(distance); posSum.add(repulse); } } return posSum; } } function init() { if (renderer == null) { camera = new THREE.PerspectiveCamera(75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000); // エリアの中に視点を置く camera.position.z = 300; scene = new THREE.Scene(); birds = []; boids = []; //for (var i = 0; i < 30; i++) { // boid = boids[i] = new Boid(); // boid.position.x = Math.random() * 400 - 200; // boid.position.y = Math.random() * 400 - 200; // boid.position.z = Math.random() * 400 - 200; // boid.velocity.x = Math.random() * 2 - 1; // boid.velocity.y = Math.random() * 2 - 1; // boid.velocity.z = Math.random() * 2 - 1; // boid.setAvoidWalls(true); // boid.setWorldSize(500, 500, 400); // bird = birds[i] = new THREE.Mesh(new Bird(), new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, side: THREE.DoubleSide })); // bird.phase = Math.floor(Math.random() * 62.83); // bird.position = boids[i].position; // scene.add(bird); //} var image = new Image() image.onload = function () { texture = new THREE.Texture(this); texture.needsUpdate = true; material = new THREE.MeshBasicMaterial({ map: texture, overdraw: true }); material.side = 2 for (var i = 0; i < 30; i++) { boid = boids[i] = new Boid(); boid.position.x = Math.random() * 400 - 200; boid.position.y = Math.random() * 400 - 200; boid.position.z = Math.random() * 400 - 200; boid.velocity.x = Math.random() * 2 - 1; boid.velocity.y = Math.random() * 2 - 1; boid.velocity.z = Math.random() * 2 - 1; boid.setAvoidWalls(true); boid.setWorldSize(500, 500, 400); birds[i] = new THREE.Mesh(new THREE.PlaneGeometry(30, 30, 2, 1), material); bird = birds[i] bird.phase = Math.floor(Math.random() * 62.83); bird.position = boids[i].position; scene.add(bird); } }; image.src = "/images/Black_Eagle_Miku_Elf4.png"; renderer = new THREE.CanvasRenderer(); Debug.writeln("new THREE.CanvasRenderer()"); // renderer.autoClear = false; renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); document.addEventListener('mousemove', onDocumentMouseMove, false); } var target = document.querySelector("#contentHost"); target.appendChild(renderer.domElement); // document.body.appendChild(renderer.domElement); if (renderer == null) { window.addEventListener('resize', onWindowResize, false); } } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } function onDocumentMouseMove(event) { var vector = new THREE.Vector3(event.clientX - SCREEN_WIDTH_HALF, - event.clientY + SCREEN_HEIGHT_HALF, 0); for (var i = 0, il = boids.length; i < il; i++) { boid = boids[i]; vector.z = boid.position.z; boid.repulse(vector); } } // function animate() { requestAnimationFrame(animate); render(); } function render() { for (var i = 0, il = birds.length; i < il; i++) { boid = boids[i]; boid.run(boids); bird = birds[i]; bird.rotation.y = Math.atan2(-boid.velocity.z, boid.velocity.x); bird.rotation.z = Math.asin(boid.velocity.y / boid.velocity.length()); bird.rotation.x = (180 * Math.PI / 180) / 2; bird.phase = (bird.phase + (Math.max(0, bird.rotation.z) + 0.1)) % 62.83; bird.geometry.vertices[0].z = bird.geometry.vertices[2].z = Math.sin(bird.phase) * 15; //color = bird.material.color; //color.r = color.g = color.b = (500 - bird.position.z) / 1000; //bird.rotation.y = Math.atan2(-boid.velocity.z, boid.velocity.x); //bird.rotation.z = Math.asin(boid.velocity.y / boid.velocity.length()); //bird.phase = (bird.phase + (Math.max(0, bird.rotation.z) + 0.1)) % 62.83; //bird.geometry.vertices[5].y = bird.geometry.vertices[4].y = Math.sin(bird.phase) * 5; } renderer.render(scene, camera); }
Windows JS ストアとしての改造のキモは、default.html の contentHost をうまく使うところです。
|
【Win8 ストアアプリの最新記事】
- C# : HttpClient で Post と Get する汎用 static クラス
- Win8.1 ストアアプリ(JS) : Visual Studio 2013 で Three.js(v65) の WebGLRenderer の動作を確認しました
- WinJS ストア : 『背景画像をチェンジする2画面アプリ』のテンプレート
- VS2012ストア(C#) : WebView テンプレート
- VS2012(C#)ストア : ListView Twitter 検索テンプレート
- イラストを背景にして2ページの画面遷移を解りやすくした Windows Store テンプレート
- Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2012_Twitter
- Win8 ストア(C#) / PDF viewer sample (Windows 8.1)
- ストアアプリの TextBox のスクロールバー
- Win8 ストアアプリの、メモリ上にページを残す画面遷移と、前画面のコントロールの参照
- Win8 ストアアプリで、『選択肢を応答するダイアログ』を簡単に使うための MessageBox クラス
- Win8 ストアから Post 投稿
- Win8ストア XAML の AppBarButtonStyle のContent に指定する 16進数 Unicode の取得
- Win8 ストア : UrlEncode と UrlDecode
- Win8 ストア : HttpClient + XDocument で RSS の取得
- Win8 ストア : リストボックス テンプレート
- Win8 ストア : ファイルアクセス テンプレート
- Win8 ストア : ストアブランク テンプレート
- AppBar テンプレート / Win8 ストアアプリ(C#)
- Windows ストアアプリの AppBar を作成してテストする