Three.js / WebGL上のGalaxyマップ







おやすみなさい。 空き時間に、私はThree.js / WebGLで宇宙をテーマにしたゲームを開発しており、ゲームのいくつかのコンポーネントに関する小さなシリーズの記事を書くことにしました。この記事では、銀河マップについて説明します。 物語は、私にとって通常の方法で-段階的に進みます。



Three.js自体の初期化コードと詳細は提供しません。ネットワークにはこれに関する情報がたくさんあります。

そして最初のステップ...



ステップ1-黒と黒の背景



まず、基板を作成する必要があります。 これは1行で簡単に実行できます。

renderer.setClearColor(0x000000);
      
      





次のようになります。







明らかにこれはMalevichの長方形であり、これが最初のステップを完了する場所です。

結局のところ、それは本当に簡単ですか?



ステップ2-そして星の完全な空



Malevichの長方形はすばらしいですが、星を追加する必要があります。

銀河の地図を作成しているため、銀河に似た渦巻きが必要です。 対数スパイラルを選びました。

まず、必要なすべての変数を書き留めます

 //     var countStars = 20000; var a = 1.1; ar b = 0.17; var windings = 3.7; var tMax = 2.0 * Math.PI * windings; var drift = 0.3
      
      





非常に単純なアルゴリズムを作成します。ループを通過して各星の座標(Wikipediaの公式)を計算し、それらを少しランダムにシフトして、銀河のように見えます。

 //   for (var i = 0; i < countStars; i++) { // +    var t = tMax * Math.random(); var x = a * Math.exp(b * t) * Math.cos(t); x = x + (drift*x*Math.random()) - (drift*x*Math.random()); var y = a * Math.exp(b * t) * Math.sin(t); y = y + (drift*y*Math.random()) - (drift*y*Math.random()) //    if (Math.random() > 0.5) { list.push({x:vec.x, y:vec.y}); } else { //  list.push({x:-vec.x, y:-vec.y}); } }
      
      





ポイントの数が非常に多いため、パーティクルのシステムでそれらを配置し、ラグがはるかに少なくなります。

 // var geometry = new THREE.Geometry(); //   var material = new THREE.ParticleSystemMaterial({ color: 0xeeeeee, size: 3 }); //  var particleSystem = new THREE.ParticleSystem( geometry, material ); //  for (var i = 0; i < list.length; i++) { addStar(list[i].x, list[i].y); } scene.add(particleSystem);
      
      





この段階でのaddStar関数:

 var addStar = function(x, y) { var v = new THREE.Vector3(); vx = x * 10; vy = y * 10; geometry.vertices.push(v); }
      
      





そして、我々はそれをやった...







穴の中央にあるものを詳しく見てみましょう。







うんざりしますが、修正は難しくありませんが、2サイクル追加します。

最初のサイクルでは、ポイントのリングを生成します。

 for (var i = 0; i < 4000; i++) { var vec = {x:Math.sRandom(0.8, 1.7),y:0}; var angle = Math.sRandom(0, Math.PI*2.5); vec = VectorRot(vec, angle); list.push({x:vec.x, y:vec.y}); }
      
      











2番目のサイクルは点の円を生成します。

 for (var i = 0; i < 4000; i++) { var vec = {x:Math.sRandom(0.001, 0.8),y:0}; var angle = Math.sRandom(0, Math.PI*2.5); vec = VectorRot(vec, angle); list.push({x:vec.x, y:vec.y}); }
      
      











素晴らしい、すでに銀河のようなものがあります。 しかし、星の名前が必要です。 %username%を持っていますが、星は持っていません。 公平ですか?



ステップ3-スターという名前の%starname%



さて、順番にやってみましょう。

名前を生成する関数を作成する必要があります。 星のグローバルリスト(座標+名前)が必要です。 星の追加を変更し、そこに名前の生成を含める必要があります。 これは名前の存在そのものです。 また、マウスオーバーイベント中に星の名前を表示する関数も必要です。 問題は、これはイベントをハングさせないパーティクルのシステムであるため、他の何かを考え出す必要があることを意味します。 多くのオプションがありますが、私は次のことを行いました:KDTreeのJD実装を見つけ、私たちが持っているすべてのポイント(つまり、同じグローバルリスト)をツリーに追い込み、mousemoveイベントハンドラーで次のように書きました:

 //        var projector = new THREE.Projector(); var vector = new THREE.Vector3( ( e.pageX / window.innerWidth ) * 2 - 1, - ( e.pageY / window.innerHeight ) * 2 + 1, 0.5 ); var pos = projector.unprojectVector( vector, e.data.self.camera ); //      e.data.self.sceneNames = new THREE.Scene(); //  KDTree      var items = e.data.self.tree.nearest({x:pos.x,y:pos.y}, 1, 100); //   label for (var i = 0; i < items.length; i++) { e.data.self.sceneNames.add(e.data.self.labelBasic(items[i][0].name,vector.x, vector.y, 60, "#f00")); }
      
      





もちろん、メッシュを再作成するたびに最適とは言えませんが、パフォーマンスは十分です。

すべてのコードを提供するわけではありません。最後にgithubにアクセスして、見たいと思っています。次のステップの前に、写真を見ていきます。













ステップ4-カオスに秩序をもたらす



そのため、星の名前である銀河はすでにありますが、それらを見ることができますが、マップがあるので、スペースのパーティションが必要です。 「聞いて、TX-82システムに飛んでケフィアを買ってください」と言ったら、a)TX-82という名前のシステムが唯一のものであるという事実ではないため、b)2万以上の星の中からシステムを見つける方法? c)ケフィアがすでに配達されているという事実ではない

そのような内訳を作りましょう:象限があり、セクターがあります。 銀河全体は4 * 4 = 16象限、各側に4分割されます。 次に、各象限は4つのセクターに分割されます。 つまり システムを象限としてアドレス指定できます#qX-qY-セクター(sx-sy)-system%starname%。

単純な線でそれを行います。ここでもコードは示しません。それは大きくて面白くありません-各線の始点と終点の座標を計算するだけです。 誰も気にしない-githubへようこそ。

ご想像のとおり、結果は記事のヘッダーにあります。 しかし、私は別の写真をあげます:







表記を追加するだけです-(1-1)、(3-3)、(2-3)のようなテキスト。 グリッドはありますが、表記はありません。 追加します。







ステップ5-チップとデール



写真のこれらの数字が何であるかを誤解しないようにしてください。 または、少なくとも試してみてください。 はい 2行のHTMLとCSS:

 <span id="quad" style="position:absolute;left:100px;top:10px;color:white;font-family:Arial;font-size:19px">#xy Quadrant</span> <span id="sector" style="position:absolute;left:100px;top:30px;color:#555;font-family:Arial;font-size:19px">(sx-sy) Sector</span>
      
      











ステップ6-私はどこですか?



そして、私たちに残された最後のことは、銀河における私たちの位置を示すことです。 私は頭にレンガを打ち、あなたがどこにいるか忘れました。 しかし、私たちはケフィアをどこに持ってくるべきかを話す必要があります、私たちは何をすべきですか? マップを開き、テクノロジーのおかげで:







はい、コードは次のとおりです。

 //  var addMarker = function(x, y) { // var g = new THREE.Geometry(); //   var m = new THREE.ParticleBasicMaterial({ color: 0x550000, size: 35 }); for (var i = 0; i < 100; i++) { g.vertices.push({x:x,y:y}); }; //  var p = new THREE.ParticleSystem( g, m ); this.sceneLabel.add(this.labelBasic(">> ", x , y , 70, "#f00")); this.sceneLabel.add(this.labelBasic(" <<", x , y , 70, "#f00")); this.sceneLabel.add(this.labelBasic(this.points[this.here].name, x , y , 60, "#f00")); this.sceneLabel.add(p); }
      
      





おわりに



そこで、地図を作りました。 この記事では、キーを押したまま地図を移動したり、ズームしたり、Three.jsでの作業をあまり詳しくしなかったなど、多くのことを引用しませんでした。

Github: github.com/MagistrAVSH/galmap

デモは最新のFF、Chrome、Operaで動作します。 IE11ではうまく動作せず、ラベルはまったく表示されず、WebGLを不正にサポートします。 magistravsh.github.io/galmap



将来のために、星系の地図、星雲ジェネレーター、さまざまなオブジェクトのジェネレーター、そして一般に幻想的な空間のテーマに関する記事を書くアイデアがあります:)興味があるなら、書いてください。



最後に、ネタバレの下で、さらに2つのスクリーンショット。

スクリーンショット











All Articles