web-dev-qa-db-ja.com

1D配列の3D配列を「フラット化」または「インデックス化」する方法

ゲームの「チャンク」システム用に3Dアレイを1Dアレイにフラット化しようとしています。それは3Dブロックゲームであり、基本的にチャンクシステムをMinecraftのシステムとほぼ同一にしたい(ただし、これはMinecraftのクローンではありません)。以前の2Dゲームでは、次のアルゴリズムを使用してフラット化された配列にアクセスしました。

Tiles[x + y * WIDTH]

ただし、Z軸が欠落しているため、これは明らかに3Dでは機能しません。この種のアルゴリズムを3D空間に実装する方法がわかりません。幅、高さ、深さはすべて一定です(幅は高さと同じくらいです)。

ただx + y*WIDTH + Z*DEPTH?私は数学が苦手で、3Dプログラミングを始めたばかりなので、かなり迷っています:|

PS。その理由は、私はループを作成し、そこからかなり多くのインデックスを取得しているからです。 1D配列は多次元配列よりも高速であることを知っています(理由は覚えていません:P)。これは必要ではないかもしれませんが、可能な限り良好なパフォーマンスが必要です:)

21
user925777

アルゴリズムはほとんど同じです。 3D配列がある場合Original[HEIGHT, WIDTH, DEPTH]その後、それをFlat[HEIGHT * WIDTH * DEPTH] 沿って

Flat[x + WIDTH * (y + DEPTH * z)] = Original[x, y, z]

余談ですが、.NETの多次元配列よりも配列の配列を優先する必要があります。パフォーマンスの違いは大きい

31

Javaの解決策は、両方を提供します:

  • 3Dから1Dへ
  • 1Dから3Dへ

以下は、3Dマトリックスをトラバースするために選択したパスの図解です。セルには、トラバーサル順に番号が付けられています。

2 Examples of 3D matrices

変換関数:

public int to1D( int x, int y, int z ) {
    return (z * xMax * yMax) + (y * xMax) + x;
}

public int[] to3D( int idx ) {
    final int z = idx / (xMax * yMax);
    idx -= (z * xMax * yMax);
    final int y = idx / xMax;
    final int x = idx % xMax;
    return new int[]{ x, y, z };
}
25
Samuel Kerrien

上記には少し修正が必要だと思います。 HEIGHTが10で、WIDTHが90であるとしましょう。1次元配列は900です。上記のロジックにより、配列9 + 89 * 89の最後の要素にいる場合、これは明らかに900を超えています。正しいアルゴリズムは次のとおりです。

Flat[x + HEIGHT* (y + WIDTH* z)] = Original[x, y, z], assuming Original[HEIGHT,WIDTH,DEPTH] 

皮肉なことに、HEIGHT> WIDTHの場合、オーバーフローは発生せず、単なる完全な結果が得られます;)

22
Martin

x + y*WIDTH + Z*WIDTH*DEPTH。それを直方体として視覚化します。最初にxに沿ってトラバースし、次に各yが「ライン」widthステップ長で、各zが"飛行機" WIDTH*DEPTHエリア内のステップ。

11
Tom Zych

あなたはほとんどそこにいます。 ZにWIDTHandDEPTHを掛ける必要があります。

Tiles[x + y*WIDTH + Z*WIDTH*DEPTH] = elements[x][y][z]; // or elements[x,y,z]
5
dlev

正しいアルゴリズムは次のとおりです。

Flat[ x * height * depth + y * depth + z ] = elements[x][y][z] 
where [WIDTH][HEIGHT][DEPTH]
2
Beta-Logics

TL; DR

正解はさまざまな方法で書くことができますが、理解して視覚化するのが非常に簡単な方法で書くことができるのが一番好きです。正確な答えは次のとおりです。

(width * height * z) + (width * y) + x

TS; DR

それを視覚化する:

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

someNumberToRepresentZは、どの行列にあるかを示します(depth)。どの行列にいるかを知るには、各行列の大きさを知る必要があります。マトリックスのサイズは2次元でwidth * height、シンプル。尋ねる質問は、「いくつのマトリックスは、私がいるマトリックスの前ですか?」です。答えはz

someNumberToRepresentZ = width * height * z

someNumberToRepresentYは、どの行にあるかを示します(height)。どの行にいるかを知るには、各行の大きさを知る必要があります。各行は1dで、サイズはwidthです。尋ねる質問は、「いくつの行は行の前にありますか?」です。答えはy

someNumberToRepresentY = width * y

someNumberToRepresentXは、どの列にいるかを示します(width)。どの列にいるかを知るには、単にxを使用します。

someNumberToRepresentX = x

その後の可視化

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

になる

(width * height * z) + (width * y) + x
2
Robert Plummer

1D配列での3D配列の説明をよりよく理解するには(最良の答えの深さはYサイズを意味すると思います)

IndexArray = x + y * InSizeX + z * InSizeX * InSizeY;

IndexArray = x + InSizeX * (y + z * InSizeY);
1
Evalds Urtans