web-dev-qa-db-fra.com

Comment "aplatir" ou "indexer" un tableau 3D dans un tableau 1D?

J'essaye d'aplatir un tableau 3D en tableau 1D pour le système "chunk" dans mon jeu. Il s’agit d’un jeu de blocs en 3D et, fondamentalement, je souhaite que le système de blocs soit presque identique au système de Minecraft (toutefois, ce n’est en aucun cas un clone de Minecraft). Dans mes précédents jeux 2D, j'ai accédé au tableau aplati avec l'algorithme suivant:

Tiles[x + y * WIDTH]

Cependant, cela ne fonctionne évidemment pas avec la 3D car il manque l'axe Z. Je ne sais pas comment implémenter ce type d'algorithme dans l'espace 3D. La largeur, la hauteur et la profondeur sont toutes des constantes (et la largeur est aussi grande que la hauteur).

Est-ce juste x + y*WIDTH + Z*DEPTH? Je suis assez mauvais en maths et je commence juste à programmer en 3D, alors je suis assez perdu: |

PS. La raison en est que je boucle et que je tire pas mal de choses par index. Je sais que les tableaux 1D sont plus rapides que les tableaux multidimensionnels (pour des raisons que je ne me souviens plus: P). Même si cela peut ne pas être nécessaire, je veux la meilleure performance possible :)

19
user925777

L'algorithme est essentiellement le même. Si vous avez un tableau 3D Original[HEIGHT, WIDTH, DEPTH], vous pouvez le transformer en Flat[HEIGHT * WIDTH * DEPTH] par

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

En passant, vous devriez préférer les tableaux de tableaux aux tableaux multidimensionnels dans .NET. Les différences de performance sont significatives

28
Gideon Engelberth

Voici une solution en Java qui vous donne les deux:

  • de 3D à 1D
  • de 1D à 3D

Ci-dessous, une illustration graphique du chemin que j'ai choisi pour parcourir la matrice 3D. Les cellules sont numérotées dans leur ordre de parcours:

 2 Examples of 3D matrices

Fonctions de conversion:

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 };
}
23
Samuel Kerrien

Je pense que ce qui précède nécessite une petite correction. Disons que vous avez une hauteur de 10, et une largeur de 90, un tableau à une dimension sera 900. Selon la logique ci-dessus, si vous êtes au dernier élément du tableau 9 + 89 * 89, il est évident qu'il est supérieur à 900. L'algorithme correct est:

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

Ironiquement, si vous avez la HAUTEUR> LARGEUR, vous ne rencontrerez pas de débordement, complétez simplement les résultats douteux;)

18
Martin

x + y*WIDTH + Z*WIDTH*DEPTH. Visualisez-le sous la forme d'un solide rectangulaire: vous parcourez d'abord x, puis chaque y est une "ligne" width longue, et chaque z est un "avion" WIDTH*DEPTH croissant.

11
Tom Zych

Tu y es presque. Vous devez multiplier Z par WIDTH et DEPTH:

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

L'algorithme correct est:

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

TL; DR

La bonne réponse peut être écrite de différentes manières, mais je l’aime mieux quand elle peut être écrite d’une manière très facile à comprendre et à visualiser. Voici la réponse exacte:

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

TS; DR

Visualisez le:

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

someNumberToRepresentZ indique la matrice sur laquelle nous sommes (depth). Pour savoir sur quelle matrice nous sommes, nous devons savoir quelle est la taille de chaque matrice. Une matrice est de taille 2D en tant que width * height, simple. La question à poser est " combien de matrices sont avant la matrice sur laquelle je suis?" La réponse est z:

someNumberToRepresentZ = width * height * z

someNumberToRepresentY indique la rangée sur laquelle nous nous trouvons (height). Pour savoir à quelle rangée nous nous trouvons, nous devons savoir quelle est la taille de chaque rangée: Chaque rangée vaut 1d, de taille width. La question à poser est " combien de lignes sont avant la ligne sur laquelle je suis?". La réponse est y:

someNumberToRepresentY = width * y

someNumberToRepresentX indique la colonne sur laquelle nous sommes (width). Pour savoir sur quelle colonne nous nous trouvons, nous utilisons simplement x:

someNumberToRepresentX = x

Notre visualisation alors de

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

Devient

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

Pour mieux comprendre la description d'un tableau 3D dans un tableau 1D, je suppose que (la meilleure réponse est Profondeur, taille Y)

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

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