Three.jsで直線をシーンに追加して透視投影と平行投影で描画して比較してみます。
Three.jsで直線を描画するには?
Three.jsで直線を描画するにはどうすればいいのでしょうか? 以下のようなサンプルプログラムを見かけますが、これでは動かない場合があります。
1 2 3 4 5 6 7 8 9 10 11 |
let geometry = new THREE.Geometry(); // ここでエラーがでる // 頂点座標の追加 geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( 150, 0, 0) ) ); geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( 0, 150, 0) ) ); // 線オブジェクトの生成 let line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x990000} ) ); // sceneにlineを追加 scene.add( line ); |
ではどうすればよいかというと
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const points = []; // 頂点座標の追加 points.push(new THREE.Vector3(- 4800, 0, 0)); points.push(new THREE.Vector3( 4800, 0, 0)); // ジオメトリとマテリアルの生成 let lineGeometry = new THREE.BufferGeometry().setFromPoints(points); const whiteMaterial = new THREE.LineBasicMaterial({ color: 0xffffff }); // 線オブジェクトを生成してシーンに追加する const line = new THREE.Line(lineGeometry, whiteMaterial); scene.add( line ); |
透視投影でもなく平行投影でもない不思議な世界
ところで次回からこんな感じのゲームを作ろうとしているのですが・・・
このゲームは3Dっぽく見えますが、これはこれまで作成してきた透視投影ではありません。透視投影と平行投影で描画したものと比較してみましょう。
透視投影の場合
これは縦横に等間隔で引いた直線を透視投影で描画したものです。
遠くにあるものは小さく描画されるので縦方向の直線は中央よりになり、横方向の直線は間隔が狭くなっています。
一応、ソースコードを示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>等間隔の直線を描画する</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <canvas id="myCanvas"></canvas> <script src="https://unpkg.com/three@0.140.2/build/three.min.js"></script> <script> // サイズを指定 const width = 960; const height = 540; // レンダラーを作成 const renderer = new THREE.WebGLRenderer({ canvas: document.querySelector('#myCanvas') }); // シーンを作成 const scene = new THREE.Scene(); // カメラを作成 const camera = new THREE.PerspectiveCamera(45, width / height); // ページの読み込みを待つ window.addEventListener('DOMContentLoaded', init); function init() { renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(width, height); camera.position.set(0, 500, +1000); camera.lookAt(new THREE.Vector3(0, 0, -100)); for(let i=-5; i <= 5; i++) LineX(200 * i); // Z座標を指定して、X軸に平行で両端のY座標が0の直線を描画する for(let i=-3; i <= 3; i++) LineZ(200 * i); // X座標を指定して、Z軸に平行で両端のY座標が0の直線を描画する renderer.render(scene, camera); // レンダリング } const whiteMaterial = new THREE.LineBasicMaterial({ color: 0xffffff }); const redMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 }); // Z座標を指定して、X軸に平行で両端のY座標が0の直線を描画する function LineX(z){ const points = []; points.push(new THREE.Vector3(- 4800, 0, z)); points.push(new THREE.Vector3( 4800, 0, z)); let lineGeometry = new THREE.BufferGeometry().setFromPoints(points); let line; if(z != 0) line = new THREE.Line(lineGeometry, whiteMaterial); else line = new THREE.Line(lineGeometry, redMaterial); scene.add( line ); } // X座標を指定して、Z軸に平行で両端のY座標が0の直線を描画する function LineZ(x){ const points = []; points.push(new THREE.Vector3( x, 0, 4800)); points.push(new THREE.Vector3( x, 0, - 4800)); let lineGeometry = new THREE.BufferGeometry().setFromPoints(points); let line; if(x != 0) line = new THREE.Line(lineGeometry, whiteMaterial); else line = new THREE.Line(lineGeometry, redMaterial); scene.add( line ); } </script> </body> </html> |
平行投影の場合
平行投影で描画するときはカメラを定義するときにTHREE.PerspectiveCameraを使うのではなく、THREE.OrthographicCameraを使えばOKです。
1 2 |
// 下のコードに変更 const camera = new THREE.PerspectiveCamera(45, width / height); const camera = new THREE.OrthographicCamera(-800, +800, 800 * height / width, -800 * height / width, 0, 2000); |
引数は描画される領域の左境界、描画される領域の右境界、描画される領域の上境界、描画される領域の下境界、シーンに描画されるカメラ位置を基準にした最小値、同最大値です。
平行投影だとこうなります。遠近感がないので手前にある3Dオブジェクトも奥にある3Dオブジェクトも同じ大きさで表示されます。縦横の直線の間隔は同じです。
ということでこのゲームを疑似3Dで作ろうとすると自分で実装しなければなりません。