Unityの無限3D洞窟


8

友人と私は、Unityでゲームを作って、無限の3D洞窟を飛んで、あらゆる方向にねじれたり曲がったりできることを望んでいます(ただし、ターンが不可能になるほどで​​はありません)。私たちは、それぞれが一定量曲がるトンネル「ピース」をいくつか作成し、前に来たものの最後にそれぞれを生成することを考えていました。

しかし、1つのトンネルピースの口が常に前のトンネルピースの端と完全に(位置と回転の両方で)整列することを確認する方法はわかりません。これを達成する方法について誰かがアドバイスを提供できますか?

私たちもそれを正しい方法で行っていますか、それとも手続き的に洞窟を生成するより良い方法がありますか?ボーナスポイント:洞窟の直径や形が変わる可能性があれば素晴らしいでしょう。

回答:


6

ゲームデザインに関しては、「正しい方法」と「間違った方法」はめったにありません。この問題を解決するには多くの方法がありますが、ここではいくつかの可能なアプローチを紹介します。

  • トンネルのピースを特定の方向にのみ開始と終了の両方に制限します。たとえば、軸に沿ってのみ。次に、セグメントの最初から最後までのオフセットと、セグメントの最初と最後の移動方向を示す列挙型を追跡する必要があります。このようにすると、最後のメッシュが終了した方向と同じ方向から開始するように常に次のメッシュを選択する限り、トンネルメッシュの回転についてまったく心配する必要はありません。

  • 各セグメントがローカルモデル空間の原点から始まり、トンネルが特定の軸に沿って移動するようにします(+ X、+ Z、または-Zが最も論理的な選択ですが、すべてのモデルで同じものを使用する必要があります)。次のメッシュを正しく変換できるように、トンネルの端の位置と最終的な移動方向を何らかの方法で保存します。(おそらく変換行列がこの情報を格納する最も簡単な方法ですが、変位ベクトル+クォータニオン、デュアルクォータニオン、変位+新しい基底ベクトル、変位+オイラー角回転などを使用することもできます。)

  • 新しい頂点データをいくつかのメッシュにストリーミングすることで、手続き的に洞窟を生成します。Meshクラスを使用してこれを行うことができます。新しい頂点データを生成する場合、最も簡単な方法は、おそらく前の洞窟セグメントとほぼ同じ方向のどこかで点を選択し、次に洞窟の中心をその点に向かって移動させることです。次に、円筒座標を使用して、手順に従って洞窟の壁に詳細を作成できます。円柱の端を押し出し、各頂点をその円柱の中心に近づけたり、中心から遠ざけたりして個別に平行移動すると考えてください。

既成のセグメントを使用するソリューションでは、すべてのメッシュがトンネルの中心の周りで同じ形状と直径を持っていることを確認する必要がありますが、セグメントをある程度オーバーラップさせ、各セグメントにフレアを持たせることでこれをある程度回避できます終わりに。正しく行われていれば、継ぎ目があることをプレーヤーにあまり明白にすべきではありません。

一方、完全に手続き的に生成されたジオメトリを使用する場合は、トラバースが不可能なセクションを生成しないようにするための作業が増え、衝突検出の問題が発生する可能性があります。

「無限」のゲームでは、浮動小数点表現の制限に注意する必要があります。プレーヤーがワールドの原点から離れすぎると、浮動小数点計算の精度が失われやすくなります(たとえば、2つの大きな値が互いに減算される場合)。これを回避するには、プレーヤーが世界を移動するのではなく、プレーヤーを中心に世界を移動させることができますが、通常は、プレーヤーの位置を時々確認するだけの方が簡単で、原点から遠すぎる場合はプレイヤーが原点またはその近くにいる世界。


2
+1特に「正しい方法ではない」コメント(私は少し同意する必要があります:多くの、多くの間違った方法があります...)
Steven Stadnicki

本当にありがとう!終了位置と方向が事前にわかっているいくつかの異なるトンネルピースを使用し、それらの位置/角度にマーカーを設定し、以前のピースのマーカーに対して新しいピースを配置しました。もっと手の込んだことをするのはクールでしたが、当分の間、より正当な手続き型の生成は、私たちのスキルの範囲と時間の制限をはるかに超えていました。再度、感謝します!
richardmherndon 14

3

これが私が最近実験したテクニックです。私のRenderMonkeyプロトタイプはバッドランズスタイルの峡谷の一部を示していますが、同じ原理が洞窟でも機能するはずです。

アイデアは、単純で予測可能なエッジを備えた、汎用的でまったく退屈なタイルから始めて、継ぎ目やギャップなしで簡単に整列できるようにすることです。

鈍い予測可能なタイル

これらの開始タイルは、モデル化した形状、または円柱状の幾何学的形状の手順で生成されたマカロニチューブである可能性があります(このフォームは、bcristとSteven Stadnickiの提案の変形です)。作成したモデルを使用すると、分岐パスなどの任意のトポロジや、開いた洞窟などの対象のポイントを簡単に処理できます。これは、純粋な手続き型(メタボールテクニックに関するGyroninjaの提案を参照)でも可能ですが、やりがいがあります。

タイルがワールドに配置されたら、ワールドスペースで適用されるノイズ関数を使用して、その頂点を置き換えます。これにより、タイル間の接続性とシームレス性が維持されます(一致する頂点は同じワールドスペース入力を持ち、同じ変位出力を取得するため)。ただし、すべてのタイルはユニークで有機的に見えます。

それはもっと面白いです

テクスチャと法線はワールドスペースでも適用されます-ここでは3平面マッピングを使用しています-そのため、隣接するタイルは完全にシームレスであり、トリッキーなUVアンラップ制約はありません。

またもっと面白い

このような手法により、タイル化されたマップの計画とレベルデザインの制御が容易になり、再生可能な結果に目に見える繰り返しや機械的な外観の構造がなくなることが期待されます。

衝突の表現を作成するために適用された低周波ノイズコンポーネントのみで低解像度メッシュを使用できます。bcristが指摘するように、トンネルの曲がりの半径と鋭さを基準にしてノイズの最大振幅を制御し、完全にピンチオフしないようにする必要があります。

さらにもう1つ注意:洞窟が本当に無限である場合、プレイヤーが原点から遠ざかるにつれて定期的に「中心を再設定」する必要がある場合があります。浮動小数点数は大きなマグニチュードで精度を失うため、物理学およびレンダリングアーティファクトが極端な距離で忍び込む可能性があります。これを行う場合、ワールドスペースノイズが大規模に周期的であり、周期が再中心化オフセットに正確に一致するようにしたいので、再中心化後にシームに遭遇することはありません。


2

洞窟を一連のポイントとしてモデル化し、それぞれにサイズを関連付け、それらを結ぶ線を追加できます。次に、各ポイントとラインをメタボールとメタシリンダーとして扱います。これにより、洞窟の基本的な形状が得られます。頂点をランダムにオフセットするなどして、バリエーションを追加し始めることができます。


2

ここでは、まだ明示的に言及されていない手続き型生成への別のアプローチがあります。スプラインスキニングです。Hermiteスプラインのバージョンを使用できます(これは、位置と接線を補間する曲線を提供します)曲線を定義します。新しいセグメントを生成するときは、位置(大まかに前のセグメントの方向に、bcristが言うように)と方向(ほぼ同じ方向)を選択します方向-たとえば、前の方向の明確に定義された円錐内)、新しい位置+方向および以前の位置+方向を使用して、洞窟の新しい「背骨」を構築します。このバックボーンを取得したら、円筒形の構成でスキンを適用できます。たとえば、曲線に沿った10点の位置と接線を決定し、それらの位置/接線を使用して直交する「フレーム」を見つけ、これらのフレームを使用して円筒セグメントを構築します。これに関する小さな注意点は、洞窟も曲がることができないということです それ以外の場合は、自己交差の問題が発生する可能性があります。

編集:これはアルゴリズムの大まかな疑似コードの内訳です:

Parameters:
  L = (average) segment length,
  V = segment length variation,
  R = cylinder radius,
  T = segment angular variation
  S = number of 'rings' per segment

Setup:
Choose an initial point P_0 and direction D_0 (for concreteness' sake, these can be
the origin and the X axis).  Set P_prev and D_prev to these values.
Initialize u_prev to be the Y axis and v_prev to be the Y and Z axes.
  (Note that (D_prev, u_prev, v_prev) form a mutually-orthogonal 'coordinate frame')

Generate a segment (do this as many times as you want):
{
  Choose a (temporary) direction D within a cone of size T around the previous direction D_prev
  Choose a segment length L_cur = at random from within the range [L-V, L+V].
  Set the current terminal point P_cur to P_prev+D*L_cur - this is the position
  we'll interpolate to
  Set the current terminal direction D_cur to a direction chosen at random from
  within a cone of size T around the previous direction.  (There are good ways
  of doing this - if you look back through gamedev.SE you should find some)
  'Build' the Hermite spline H that goes from (P_prev, D_prev) to (P_cur, D_cur)

  Now, skin that spline:
  for ( i = 1; i <= S; i++ ) {
    find the position P of the hermite spline H at t=i/S
    find the direction D of the spline at t (this will be just the derivative)
    'transport' the orthogonal frame to the new spot: for instance,
      v_new = D x u_prev
      u_new = v_new x D
    (note that this keeps u_new, v_new close to their old values, and orthogonal
    to each other and to D)
    Use the previous and current frames and positions to build a cylindrical 'ring':
    For theta from 0 to 2pi {
      find the points (P+(u_new, v_new, D) * (cos theta, sin theta, 0))
      and connect them to their counterparts from the previous ring
      (note that that multiplication is a matrix-vector multiply)
    }
    update u_prev and v_prev to u_new and v_new
  }
  update the other prev variables to their 'new' values
}

これは明らかに非常に大まかな疑似コードです。不明な部分がある場合は、私に知らせて説明してみましょう。しかし、巨大なコードダンプだけでは、すべての詳細をカバーするのは難しいでしょう...


(ちなみに、このアプローチの疑似コードが必要な場合は、私に知らせてください。前の仕事でこのようなことをしなければならなかったので、細かいところまですべて
練り上げました

あなたの実装を見てみたいと思います。似たようなことを1回行ったことがありますが、代わりに3D 3次ベジェ曲線を使用しています。
bcrist 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.