ボクセルに関するウィキペディアのページによると、「[...]ボクセルの位置は、他のボクセルとの相対的な位置(つまり、単一のボリュメトリックイメージを構成するデータ構造内の位置)に基づいて推測されます。」
そのようなデータ構造をどのように実装する必要がありますか?私は八分木について考えていましたが、聞いたことがない何か他のものがあるかどうか疑問に思っています。
ボクセルに関するウィキペディアのページによると、「[...]ボクセルの位置は、他のボクセルとの相対的な位置(つまり、単一のボリュメトリックイメージを構成するデータ構造内の位置)に基づいて推測されます。」
そのようなデータ構造をどのように実装する必要がありますか?私は八分木について考えていましたが、聞いたことがない何か他のものがあるかどうか疑問に思っています。
回答:
最初。各ボクセルについて何を知っているかを書きましょう:
voxel = (x, y, z, color) // or some other information
一般的な方法はこれだけです:
set of voxels = set of (x,y,z, color)
ボクセルは空間内のポイントであり、2つのポイントが1つの場所を占めることはないため(静的ボクセルデータについて話していると思います)、トリプレット(x、y、z)は各ボクセルを一意に識別します。
単純なデータには問題ないはずです。しかし、それは決して高速なデータ構造ではありません。
レンダリングは、スキャンラインアルゴリズムによって行われます。ボクセルに関するTomのハードウェア記事には、スキャンラインアルゴリズムのイメージがあります。
高速ルックアップが必要な場合、ルックアップの最速のデータ構造はハッシュ(配列、マップなど)です。だから、あなたはそれからハッシュを作成する必要があります。したがって、単純に、任意の要素を取得するための最速の方法が必要です。
array [x][y][z] of (color)
これには、x、y、z座標でボクセルを検索するためのO(1)があります。
問題は、スペース要件がO(D ^ 3)であるということです。ここで、Dはx、y、zの各数値の範囲です(256の値の範囲を持つCharの場合、256になるため、実数は忘れてください) 3 = 2 ^ 24 == 16 777 216配列の要素)。
しかし、それはあなたがボクセルで何をしたいかに依存します。レンダリングがあなたの望むものであるなら、おそらくあなたが望むのはこの配列でしょう。しかし、ストレージの問題はまだ残っています...
1つの方法は、配列でRLE圧縮を使用することです。ボクセルのスライス(ボクセルのセット。ボクセルには1つの座標定数値があります。たとえば、z = 13の平面のように)を想像してください。このようなボクセルのスライスは、MSPaintの単純な描画のように見えます。ボクセルモデルは、通常、考えられるすべての場所の一部を占めます(考えられるすべてのボクセルのD ^ 3スペース)。「座標のトリプレットからペアを取り、残りの軸を圧縮する」ことがトリックだと思います(たとえば、[x] [y]を取り、各要素について、指定されたx、yでz軸のすべてのボクセルを圧縮します。 。0から数個の要素があり、RLEはここで問題ありません):
array [x][y] of RLE compressed z "lines" of voxel; each uncompressed voxel has color
ストレージの問題を解決する他の方法は、ツリーデータ構造を使用した配列の代わりです。
tree data structure = recursively classified voxels
for octrees: recursively classified by which octant does voxel at (x,y,z) belong to
ボクセルが単純なハイトマップである場合は、それだけを保存できます。または、高さマップを生成する関数のパラメーターを保存することもできます。
そしてもちろん、すべての可能なアプローチを組み合わせることができます。ただし、コードが機能することをテストし、それが本当に高速であることを測定しない限り、無理をしないでください(最適化の価値があります)。
Octrees以外には、ボクセル、Google「voxlap」、「ken silverman」を使用したRLE圧縮があります...
彼らが話しているかもしれない2つの異なるデータ構造の側面があります。
配列構造
任意の数の次元の配列の要素を参照する場合、インデックス(たとえば、myArray[4][6][15]
)を渡すと、配列自体がその場所にあるものを知っていると考えてください。その場所にあるものがボクセルである場合、そのボクセルは独自のx、y、およびz座標を追加で記録する必要はありません-ボクセルを保持する配列は、配列インデックス付きの位置に基づいて暗黙的に世界の位置を指定します。
これが良い理由は、この種の配列アクセスに使用されるポインター演算が本質的に高速であり、一般的に言えば、言語間で見られるほとんどの高速(「ネイティブ」と呼ばれる)配列の基盤を提供するからです。これらの配列の欠点は、前述のポインター演算を適用できるように、バイト単位で同じサイズの要素を持たなければならないことです。
オクトリーズ
(これはウィキペディアが参照している可能性が低いため、この2番目に注意します。また、ボクセルの実装ではoctreeを使用する必要はありませんが、現代のもののほとんどはoctreeを使用しています。)
octreeのルートノードは、分割されていない単一のキューブです。例を設定しましょう。octreeのルート(立方体の中心)が{0, 0, 0}
3D空間にあるとします。その空間内にオブジェクトを配置し始めたら(読み取り:複数のオブジェクト)、octreeをさらに細分化します。これは、xy、xz、yz平面である3つの平面を使用してスライスすることにより、8(oct-)に分割する場所です。元のキューブには、8個の小さなキューブが正確に含まれるようになりました。これらのサブノードはそれぞれ、中央の親キューブからのオフセットとして配置されます。つまり、たとえば、正のxyzオクタントにあるキューブは、親からのオフセットを持ち、キューブの中心を正確に含む{root.width / 4, root.height / 4, root.depth / 4}
。各サブノードの絶対位置を指定するのではなく、親ノードをその子空間の原点と見なす方が論理的に理にかなっています。これは、シーングラフの機能と同じです。
これを2D図面で見るのは簡単です。正方形を描き、それを4つの等しい領域に分割します。オクトツリールートノードのように、親の正方形の中心がと見なされる場合{0, 0}
、子の正方形の4つの中心は次のようになります。
{root.width / 4, root.height / 4}
、
{-root.width / 4, root.height / 4}
、
{root.width / 4, -root.height / 4}
、
{-root.width / 4, -root.height / 4}
...親を基準として-3Dと同じ原理。
RLEを使用できます。ただし、SVO(Sparse Voxel Octree)を使用できます。idTech 6はSVOを使用します。SVOは、八分木データ表現へのレイキャスティングまたはレイトレーシングアプローチを使用した3Dコンピュータグラフィックスレンダリング手法です。
テクニックは多少異なりますが、一般的には、画面の解像度とサイズを考慮して、可視または可視の可能性のあるポイントのハル(スパースボクセル)の生成と処理に依存します。
より高速であるため、レイキャスティングを使用します。
通常、地形の3Dデータ構造を回避できます。代わりに、高さマップを使用できます。これは、実行時に非常に安価で効率的にボクセル化できます。私の経験では、通常、各列でレンダリングするのに必要な最小の高さを追跡するだけでなく、場合によっては、背面の列もカリングできるように、開始-停止-上部の角度がかかります。
ここに私が長い間作ったものがあります:http : //sites.google.com/site/williamedwardscoder/spinning-voxels-in-flash
地形に少数のオーバーハングや洞窟、またはハイトマップで表現できないその他のフィーチャがある場合、ハイトマップに穴を空けて、代替表現を作成できます。保証されています。
ボクセルの大規模な真の世界がある場合、スパースボクセル表現は価値があります。 ジョン・カーマックはここ数年、彼らと話をしています...