地形生成のためのOctreeの構築


9

以前にマーチングキューブ/四面体を実装して、IsoSurfaceをレンダリングしました。これは機能しましたが(YouTube)、ビューの距離に基づいて可変の詳細レベルを実装する(または古い、遠いチャンクを削除する)ことを回避できなかったため、パフォーマンスは悲惨でした。

今回はもう一度やってみることにしました。Build()が呼び出されたときに次のように機能するOctreeNodeを作成することから始めました。

  • チャンクが小さすぎてビルドできない場合は、すぐに戻ります。
  • サーフェスがこのチャンクのボリュームを通過する場合は、ワークアウトしてください。
  • その場合は、LODを上げるかどうかを決定します(カメラが近いため)。
  • その場合、8つの子を生成し、同じプロセスを呼び出します
  • そうでない場合は、現在のノードの寸法を使用してメッシュを構築します

いくつかのPseudoCode:

OctNode Build() {
    if(this.ChunkSize < minChunkSize) {
        return null;
    }
    densityRange = densitySource¹.GetDensityRange(this.bounds);
    if(densityRange.min < surface < densityRange.max) {
        if(loDProvider.DesiredLod(bounds > currentLoD) {
            for(i 1 to 8) {
                if(children[i] == null) {
                    children[i] = new OctNode(...)
                }
                children[i] = children[i].Build();
            }
        } else {
            BuildMesh();
        }
        return this;
    }
}

densityある時点での密度を返すだけでなく、密度ソースは、特定のボリュームの可能な密度範囲を決定できます。

²LoDプロバイダーは、境界ボックスを取り、カメラの位置/錐台、ユーザー設定などに基づいて、最大の望ましいLoDを返します。

だから...これはかなりうまくいきます。単純な球を密度ソースとして使用し、すべてのノードを表示します。

フルオクトリー

そして葉だけ:

葉だけを表示するOctree

ただし、いくつかの問題があります。

  • 初期バウンディングボリュームを定義する必要があります(それが大きいほど、実行する必要のある処理が多くなります)。
  • ツリーのルートでは、葉の深さがどれほどかわからないので、LoD番号付けは最低品質(ルート)から始まり、チャンクが小さくなるにつれて増加します。LoDは最初のボリュームに対して相対的になっているので、特定のサイズ/品質で物事をやりたいときはあまり役に立ちません。

私はいくつかのオプションを考えましたが、どちらにも欠陥があるようです:

  • オクトリーのコレクションを維持し、距離に応じて追加/削除します。どのようにうまくメッシュするかがわかりません¹さらに、特に任意の3Dサーフェスが必要な場合(空のボリュームが繰り返し計算されるのを避けるため)には、既知の空ノードのリストが必要になります。
  • 親ノードを現在のルートに追加してから、元のノードに7つの兄弟を追加します。これは機能し、オンデマンドですが、プレイヤーがランドスケープを移動するときに、慎重に縮小するのは複雑に見えます。また、LoD番号の意味がさらに減ります。

¹[以下のQについて説明します]現在、ツリー内の2つの物理的に隣接するノードが異なるLODにある場合、メッシュが生成されるときに継ぎ目がないように頂点を強制するコードがあります。周囲の複数のノードの密度を知ることでこれを行うことができます。2つの独立したオクツリーが並んでいるシナリオでは、この情報を取得する簡単な方法がないため、継ぎ目が生じます。

これに取り組むための最適な方法は何ですか?

回答:


1

正確な質問に答えているかどうかわからないので、分割して回答します。特定の質問の詳細について誤解がある場合は、コメントでお気軽に返信してください。

初期バウンディングボリュームを定義する必要があります(それが大きいほど、実行する必要のある処理が多くなります)。

これはそうあるべきではないようです。octreeは粒度が指数関数的に増加するため、上部にいくつかのレベルを追加すると、パフォーマンスヒットのごくわずかな正味の増加になります。

ツリーのルートでは、葉の深さがどれほどかわからないので、LoD番号付けは最低品質(ルート)から始まり、チャンクが小さくなるにつれて増加します。LoDは最初のボリュームに対して相対的になっているので、特定のサイズ/品質で物事をやりたいときはあまり役に立ちません。

ルートオクツリーを「十分に大きい値」に修正した場合、「初期ボリュームに対するLoD」は問題になりません。そして、前述のように、上部に追加のレベルがあることは全体的なパフォーマンスに影響を与えるとは思いません。

オクトリーのコレクションを維持し、距離に応じて追加/削除します。どのようにうまくメッシュするかがわかりません。特に、任意の3Dサーフェスが必要な場合(空のボリュームが繰り返し計算されるのを避けるため)には、既知の空のノードのリストが必要になります。

私が理解しているように、この提案された解決策は、以前の詳細な領域から離れるときにLoDを下げることです。私はそれが「増加するLoD」コードパスに非常に似ているはずだと思います:

if (loDProvider.DesiredLod(bounds) <(is a lot less than)< currentLoD) { 
    for(i = 1 to 8) { 
        children[i].Destroy();
    }
    BuildMesh();
}

次に、あなたが支出していない、あまりにもすべて高解像度のノードが削除されていますので、あなたは、遠く離れている間、あまりにも多くの「アクティブ」のノードがないという事実に頼ることができるので、遠方のノードをチェックする多くの時間を。


小さなノードがロックスケールであると仮定すると、私が大陸を移動するときに、何百ものレベルではないにしても数十のレベルが潜在的に意味されます。

オクツリーの対数スケールはそれをまだ実現可能にすると思います。トップレベルの幅が1,000,0000,000 m(これは実際の地球の25倍の幅であり、表面積が625倍になります)で、最下位レベルのビットが10cmである場合、それはおそらくオクツリーの32レベルです十分に管理可能です。地球の100倍の広さ(および表面積が10000倍)の惑星が必要な場合、それはオクツリーの追加の3〜4レベルにすぎません。この時点で、プレイヤーが世界中を歩くには数百年かかります。単純な浮動小数点演算を使用すると、世界中で精度エラーが蓄積されます。

オクトリーのコレクションを維持し、距離に応じて追加/削除します。どのようにうまくメッシュするかがわかりません¹さらに、特に任意の3Dサーフェスが必要な場合(空のボリュームが繰り返し計算されるのを避けるため)には、既知の空ノードのリストが必要になります。

これは、10億km幅のオクツリーを持つのと基本的に同等ではありませんが、たとえば1 kmのブロックごとにポインタのリストを保持しているのではないでしょうか。その場合、「メッシュ」は単に2 kmサイズのノードに依存することになります。中間レベルの各「大きなブロック」へのローカル参照を維持することで、「おそらく数十の追加のオクツリーレベル」が心配な場合に、最上位ノードを反復処理する必要がなくなります。


回答ありがとうございます。地形が無限であるため、大量の初期ボリュームを選択することはできません(それが私の目標です)。ビデオを見てアイデアを得てください。そのため、ノードのツリーはさらに高くなるだけです。小さなノードがロックスケールであると仮定すると、私が大陸を移動するときに、何百というレベルではなくても何十ものレベルが潜在的に意味されます。再:メッシュ全体、質問にさらに詳細を追加しましょう[完了]
基本的な

プレーヤーに関する限り、「10億マイル」は「無限」にかなり近いです。回答に追加された固定初期ボリュームの引数が増えました。
ジミー

まだ納得できません。既知の役に立たない処理が30層以上あるのはなぜですか?エレガントではなく、効率的です。歩き回る時間についてはあなたのポイントをとりますが、私たちは単に地形生成について話しています。原点を中心にしなければならないということも、高速で飛行することも不可能ではありません(ただし、その速度でメッシュを作成することはありません!)。FWIW精度の問題を回避するために、内部でdoubleを使用しています。
ベーシック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.