17

重要な注意:この質問は、ジオメトリのカリング (錐台のカリング、背面のカリング、オクルージョンのカリング、またはそれらの仲間) に関するものではありませ

ユニット キューブ レンダリングされた世界 (マインクラフト) で、カメラがどこにあっても、どの角度からも見ることができないジオメトリ面のリストから削除する方法のアルゴリズムを見つけようとしています。

たとえば、2 つの正方形があるとします。

+----+      +----+
|    |      |    |
|    |      |    |
+----+      +----+

明らかに 8 つの側面が表示されています (各正方形に 4 つ)。次に、正方形を一緒に移動します

+----+----+
|         |
|         |
+----+----+

8面だったのが6面になりました!真ん中で触れている二人は、カメラをどこに置いても、どの角度から見ても見えません。(四角は質感が違うので4面とは言えません。)

(立方体の 3D でも同じことが機能しますが、12 の面 (立方体あたり 6 つ) は 2 つの接触がなくなるため 10 になります。)

私の質問は、これらの隠された顔を認識するのに役立つアルゴリズムは何ですか? (私は自分でグーグルをやってうれしいですが、これが何と呼ばれているのかさえ知りません!)特に、真ん中の中空のスポットを処理するものを探しています。そこにはありますが、ジオメトリに囲まれているため、それらを見ることはできません。

例えば:

+----+----+----+----+
|                   |
|                   |
+    +----+         +
|    |    |         |
|    | A  |         |
+    +----+         +
|                   |
|                   |
+----+----+----+----+

この場合、18 の「見える」側面があると考えるかもしれませんが、カメラがジオメトリの外側にあることがわかっているため、正方形「A」の 4 つの側面は見えません。

さらに複雑なことに、ブロックが追加または削除された場合に迅速に更新できるアルゴリズムを見つけたいと思っています (これもMineCraft風です)。

ありがとう!

4

1 に答える 1

22

あなたの質問の最初の部分は非常に単純です。各立方体が別の立方体に直接隣接している場合は、その立方体と共有する面を削除します。

これは、ブロックが配置または削除されたときにのみ再計算されるため、パフォーマンスの問題ではありません (変更された頂点データの変更とアップロードのコストを除けば)。ブロックの配置と削除の影響は非常に局所的です。6 つの隣接するキューブとそれ自体にのみ影響するため、問題にはなりません。また、キューブベースの環境を処理するために必要な明らかなものを除いて、特別なデータ構造は必要ありません。

地形を構築するための初期コストは多少かかるかもしれませんが、それは 1 回限りのコストです。ロード時間にそれを考慮してください。フレームのスペースで多くの配置と削除を行っている場合、問題になる可能性があります。

より難しい問題は、密閉された内部の取り外しです。私の提案:それは価値がありません。封印された内部を取り除こうとすると、ブロックの配置または削除が非ローカル操作になります。バッチ カウント (可能な場合はテクスチャ アトラス/配列を使用) と頂点データの最適化に時間を費やすことで、パフォーマンスが向上する可能性があります。

密閉された内部を削除するには、内部を検出できる必要があります。したがって、隣接する面の双方向グラフを維持する必要があります。面ごとに、隣接する 4 つの面があります。隣接する 2 つの立方体の間にあるためにカリングされた面 (これまでは「死んだ面」と呼ばれていました) は、グラフに含めるべきではありません。

立方体を配置したら、面グラフの隣接情報を更新する必要があります。死んだ顔を取り除く必要があります。配置後のライブ面の隣接には、配置された新しいブロックによって追加された新しい面を組み込む必要があります。これを行うアルゴリズムは、座って可能性を計画すれば、かなり簡単です。たとえば、次の正方形があるとします。

  A
+++++
+   +
+   + B
+   +
+++++

面 A と面 B は隣接しています。新しいブロックを配置すると、隣接関係が変更されます。

     +++++
     +   +
   C +   +
     +   +
  A  +++++
+++++  D
+   +
+   + B
+   +
+++++

A は C に隣接し、B は D に隣接しています。

立方体が削除されたら、面グラフの隣接情報を再度更新する必要があります。基本的に、前の操作を元に戻す必要があります。

この隣接グラフの要点は次のとおりです。死んでいないすべての面がグラフ内で接続されている場合、グラフの 1 サイクルだけが表示されます。他のすべてのグラフ サイクルは表示されません。グラフのサイクルは、直接的または間接的にすべて互いに接続されている面のグループです。

大きな問題はこれです: 目に見えるサイクルをどのように見つけますか? 次のアルゴリズムは、ブロックがエンティティによって配置/削除されることを前提としています。これは、配置されたブロックの少なくとも 1 つの面が表示されることを意味します。また、ブロックを削除することでライブになる死んだ顔が表示されることも意味します。

ブロックを配置すると、面の 1 つまたは複数の新しいサイクルを作成できます。これを検出するには、まず、ブロックを配置して作成した非デッド面 (何かに直接隣接していない面) をすべて見つけます。これらのうち少なくとも 1 つが表示されます。その顔を見つけます。

次に、新しいブロックの他のすべての非デッド面について、A* (A-star) グラフ検索を使用してその面を見つけます。A* は、プライオリティ キューに基づくグラフ検索アルゴリズムです。この場合、アルゴリズムの「距離」は、現在の面がある正方形と可視面がある正方形の間の距離です。

A* が顔を見つけられない場合は、検索したすべての顔 (おそらく、テストするときにバッファーに格納する必要があります) が非表示サイクルの一部であるため、選別できることがわかります。後で参照できるように、これらの面を非表示としてマークする必要があります。

ブロックの削除ははるかに簡単です。ブロックを削除するときは、ブロックの少なくとも 1 つの面が表示されている必要があります (上記の前提を参照してください)。したがって、削除するブロックに見えない面がいくつかある場合、それらの見えない面を含むサイクル内のすべての面が見えるようになる必要があります。したがって、ブロックを削除する前に、見えない面がないかチェックしてください。ある場合は、深さ優先検索を使用してそのサイクル内のすべての顔を見つけ、それらをバッファーに入れます。ブロックを削除すると、それらの面がすべて表示されるようになります。

ブロックをテレポートできるようになると、事態はさらに複雑になります。ブロックを配置すると、そのブロックの面がまったく表示されない可能性があります。つまり、世界のどこかで目に見える顔を見つける必要があります。次に、通常どおりその顔に向かって A* 検索を行います。見えている顔が近くにあるといいので、検索はそれほど遠くなくてもかまいません。

除去では、ブロックに隣接する目に見えない面サイクルをすべて見つける必要があります。次に、前と同じように、その 1 つの目に見える顔を見つける必要があります。次に、ブロックを削除し、それらのサイクルを A* で検索して、目に見える顔が見つかるかどうかを確認します。目に見えるサイクル。目に見えないサイクル。

また、ライブ面を持たない (つまり、他のブロックに完全に埋め込まれている) ブロックを削除するには、特別なケースが必要です。これにより、目に見えない 6 面サイクルが作成されます。

おそらく、努力する価値がない理由がわかったでしょうか?正直なところ、これが必要であることを示す実際のプロファイリング データを手元に持っていない限り、それを追求しないことを強くお勧めします。必要以上の仕事をしている可能性が高く、関係のないことに多くの時間を費やしている可能性があります。

今、私は袖口からこの投稿を書きました。機能する最も単純なアルゴリズムを考えました。内部を作成できるブロックの配置を先制的に見つけたり、削除すると内部が見えるようになるブロックを見つけたりするなど、このアルゴリズムの可能な改善については調査していません。したがって、私はこのアルゴリズムがかなり力ずくであることを率直に認めます。しかし、より良いものを見つけるにはいくらかの努力が必要です。繰り返しますが、必要なパフォーマンスを達成するためにこれを行う必要があると言っているプロファイリング データがない限り、私はそれをしないことをお勧めします。

于 2011-06-12T04:49:12.440 に答える