おはようございます、Habr!
私たちの地域では、いつものように、予想外に冬が来ましたが、宇宙には季節がありません。そのため、webglでさまざまな宇宙のことについて話します。 銀河マップに関する以前の記事は、 ここで読むことができます 。 今日は、星系の地図についてお話します。
いつものように、ストーリーは段階的に進みます。 だから...
ステップ0-何をしたいですか?
星系の地図-その中にどんな情報があるべきか? まあ、最初は星です。 2番目は惑星、3番目は月です。
幻想的な要素を追加-ジャンプゲート、ジャンプゲート、または宇宙環境では単なるゲートと呼ばれます。 長距離をすばやく移動するために存在する宇宙フィクションの古典的な要素。
また、星系における位置のマーカーを作成します。
さらにいくつかの規則:何もペイントせず、ほとんどすべてを白黒にします。 第二-惑星と月の回転を複雑にし、追加しません。 これは非常に簡単に行えますが、私の意見ではトピックではありません。
ステップ1-スターと背景
繰り返しますが、マレビッチの長方形を描きます。
renderer.setClearColor(0x000000);
また、大ざっぱな星、白い円だけを描きます。
円を描くのは簡単ですが、置くのは難しいです。 通常、Three.jsを使用した作業の詳細については説明しませんが、ここでこの詳細について言及する必要があります。突然誰かが衝突します。
実際、カメラに近づいたとき、オブジェクトは視覚的に増加する必要はありません(アプローチはピクセルアートからの塗りつぶしになるため)が、ポイント間の距離は大きかったです(たとえば、オブジェクトの非常に近いクラスターがあり、それぞれを個別に確認する必要があります)。 THREE.Meshオブジェクトはそのような機会を提供しません;ここでは、私の意見では、THREE.ParticleSystemを使用する方が良いと考えています。
コメント付きの関数の完全なリストを提供します。
this.addStar = function(pos) { // var radius = 50; // var canvas = document.createElement('canvas'); canvas.width = radius*2; canvas.height = radius*2; // - var ctx = canvas.getContext('2d'); ctx.fillStyle = "#fff"; ctx.beginPath(); ctx.arc(radius,radius,radius,0,2*Math.PI); ctx.fill(); // var texture = new THREE.Texture(canvas) texture.needsUpdate = true; // var vertex = new THREE.Vector3(); vertex.x = pos.x; vertex.y = pos.y; vertex.z = 0; // var geometry = new THREE.Geometry(); // geometry.vertices.push( vertex ); // material = new THREE.ParticleBasicMaterial( { size: 215, map: texture, transparent: true } ); // particles = new THREE.ParticleSystem( geometry, material ); particles.sortParticles = true; this.scene.add(particles); }
同様に、星系の他のすべてのオブジェクトが追加されます。
ステップ2-惑星
惑星のマーカーを描画します。特別なことは考えず、ストロークで単純な円を作成します。
var radius = 15; // - var ctx = canvas.getContext('2d'); ctx.strokeStyle = "#666"; ctx.fillStyle = "#444"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(radius,radius,radius-2,0,2*Math.PI); ctx.fill(); ctx.stroke();
ポイントがおもしろくないというだけで、もっと多くの軌道が必要です。 円を作成するための通常のアルゴリズムで手でそれらを作成します。三角法で少しジオメトリを思い出すだけです。
this.addOrbit = function(pos, radius) { // . var resolution = 170; var size = 360 / resolution; // var geometry = new THREE.Geometry(); var material = new THREE.LineBasicMaterial( { color: 0x777777} ); for(var i = 0; i <= resolution; i++) { // , .. * * 1 . var segment = ( i * size ) * Math.PI / 180; // \ , \y , , .. . geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( Math.cos( segment ) * radius, Math.sin( segment ) * radius ), 0 ) ); } // var line = new THREE.Line( geometry, material ); line.position.x = pos.x; line.position.y = pos.y; this.scene.add(line); return line; }
すでに改善されていますが、改善されています。 「<星系の名前>惑星<星の惑星番号>」という形式で惑星の名前を追加します。 テキストを追加する機能は提供していませんが、面白くありません。 テキストが描画される同じパーティクルシステムとキャンバス。
ステップ3-月
ここではすべてが簡単です。描画コードは似ています。位置を中央ではなく、特定の惑星+惑星からのオフセットに配置するだけです。
var vertex = new THREE.Vector3(); vertex.x = planetPos.x + pos.x; vertex.y = planetPos.y + pos.y; vertex.z = 0;
さらに、軌道を掛けます:
// , moon.orbit = this.addOrbit(planetPos, vectorLength(pos));
ステップ4-ジャンプゲート
バビロン5シリーズのジャンプゲートの例の写真
これまでのところ、私たちは自分でゲートを描くのではなく、赤いマーカーの三角形を作成して名前を掛けます。
// - var ctx = canvas.getContext('2d'); ctx.strokeStyle = "#333"; ctx.fillStyle = "#f00"; ctx.lineWidth = 7; ctx.beginPath(); ctx.moveTo(len/2, 0); ctx.lineTo(0, len); ctx.lineTo(len, len); ctx.closePath(); ctx.stroke(); ctx.fill();
しかし、三角形が必要ないという理由だけで、同じマップがあります。 ゲート間の接続を描画する必要があります。 私たちは1つに飛び込みました-宇宙のどこに自分を見つけるのでしょうか? そのカードは便利です。
接続を構築するのは難しくありませんが、少し複雑になります。
次の構造を作成しましょう。
jgs:{ 0: {type:"jg", names: [ "Jumpgate Main Shipyard", ], id: 0, pos: {x:500, y:-50}, link: 1}, 1: {type:"jg", names: [ "Jumpgate Solar Plants" ], id: 1, pos: {x:-440, y:400}, link: 2}, 2: {type:"jg", names: [ "Jumpgate Trade Station" ], id: 2, pos: {x:200, y:-130}, link: 0}, 3: {type:"jg", names: [ "Jumpgate Ore Mining" ], id: 3, pos: {x:-300, y:-280}, link: 1}, 4: {type:"jg", names: [ "Jumpgate Cross" ], id: 4, pos: {x:-640, y:10}, link: 2} },
どこにでもリンクフィールドがあります-接続先のIDを指します。
// for (var v in list) { // ( ) list[data.jgs[v].id].link.push(this.addLine(data.jgs[v].pos, data.jgs[data.jgs[v].link].pos)); list[data.jgs[v].link].link.push(this.addLine(data.jgs[v].pos, data.jgs[data.jgs[v].link].pos)); }
つまり あるゲートの位置から別のゲートの位置まで線を追加します。 そして、反対の方向でも、私たちにとって有用です。
努力の結果:
ステップ5-インタラクティブ機能を追加する
惑星、月、ゲートを追加するための関数に次の行を追加します。
ジャンプゲート:
this.domEvent.bind(particles, "mouseover", function(e){ e.target.material.color.setHex(0xffffff); // for (var i = 0; i < e.target.link.length; i++) { e.target.link[i].material.color.setHex(0xffffff); } for (var i = 0; i < e.target.link2.length; i++) { e.target.link2[i].material.color.setHex(0xffffff); } // e.target.orbit.hover(); }); this.domEvent.bind(particles, "mouseout", function(e){ e.target.material.color.setHex(0xaaaaaa); // for (var i = 0; i < e.target.link.length; i++) { e.target.link[i].material.color.setHex(0xaaaaaa); } for (var i = 0; i < e.target.link2.length; i++) { e.target.link2[i].material.color.setHex(0xaaaaaa); } // e.target.orbit.unhover(); });
月の:
this.domEvent.bind(particles, "mouseover", function(e){ e.target.material.color.setHex(0xffffff); e.target.orbit.hover(); }); this.domEvent.bind(particles, "mouseout", function(e){ e.target.material.color.setHex(0xaaaaaa); e.target.orbit.unhover(); });
惑星:
this.domEvent.bind(particles, "mouseover", function(e){ e.target.material.color.setHex(0xffffff); e.target.orbit.hover(); }); this.domEvent.bind(particles, "mouseout", function(e){ e.target.material.color.setHex(0xaaaaaa); e.target.orbit.unhover(); });
ここでは、惑星と月-軌道、ゲート-通信と軌道のマウスオーバー、マウスアウト、ハイライトのハンドラーを追加します。
Three.jsはそのままで、パーティクルシステムとの交差点のチェックをサポートしていません。そこで、Googleでそれを考え、three.jsにねじ込んで、パーティクルシステムの頂点との交差点をチェックする機能に組み込みました。
次のようになります。
ステップ6-私たちはどこにいますか?
システム内の位置のマーカーを追加します。 超自然的なものを発明するのではなく、正方形と碑文を追加するだけです。
おわりに
まあ、彼らが望むすべてをしたように。 もちろん、二重星、小惑星帯、ガス雲など、さらに多くを追加できますが、彼らが言うように、善の最大の敵です。 いつものように、githubのすべてのコード、デモへのリンクはそこにあります。 Chrome、Firefoxで動作し、Safari、Opera、および多くのChrome形のブラウザで動作するはずです。 IE11はサポートされていません。
デモ: magistravsh.github.io/starsystemmap
コード: github.com/MagistrAVSH/starsystemmap
次回、さまざまなオブジェクト、船、ステーションの生成について書きたいと思っていますが、何か他のことができます:)