So dies bietet keine Details zu jedem Problem , das Sie mit Ihrem Ansatz begegnen werden, aber , wenn Sie jede Ecke zur nächsten nicht-Luft Voxel , um zu schaben Informationen von ihm (wie die Textur Probe) zuordnen mögen, Hier ist ein Beweis für die effiziente Methode, die ich mir ausgedacht habe:
Für jeden gegebenen Scheitelpunkt der Marschwürfel möchten wir ein Voxel auswählen, mit dem auf die Attribute des Scheitelpunkts geschlossen werden kann. Wir wählen das nächstgelegene Nicht-Luft-Voxel, das sich per Definition an derselben Kante befinden muss, auf der sich der Scheitelpunkt befindet. Da die von uns erzeugte „Oberfläche“ Luft aus Festkörpern abgrenzt, müssen die beiden Voxel entlang einer Kante, die einen Scheitelpunkt enthält, ein Festkörper und eine Luft sein. Wenn daher jedes Voxel neben dem aktuellen Würfel durch die Kombination seiner Neigungen entlang jeder Achse indiziert wird, können wir zwei seiner Neigungen durch die bestimmte Kante ableiten, auf der der Scheitelpunkt ruht, und die dritte Neigung durch Abtasten beider möglicher Ecken und Wählen Sie nur diejenige aus, die fest ist. Um das gewünschte Voxel effizient abzutasten, Wir erstellen eine Nachschlagetabelle, die jede der zwölf Würfelkanten jeweils zwei möglichen Voxelindizes zuordnet, wobei die oberen und unteren vier Bits jeweils Indizes in der Menge von acht möglichen Voxeln sind. Nachdem wir beide Voxel abgetastet haben, können wir die beiden Proben addieren, anstatt sie zu verzweigen, um die feste auszuwählen. Wenn 'Luft' ein Wert ungleich Null ist, können wir ihn einfach vom Endergebnis abziehen, da garantiert ist, dass einer der Operanden dieser Wert ist.
Hier ist meine Implementierung in Java, vorausgesetzt, Ecken und Kanten werden wie in Paul Bourkes populärem Artikel beschrieben indiziert (Ecke Null ist -X -Y -Z):
..und unter der Annahme, dass blockIds
es sich um a handelt, long
dessen Bytes jeweils einer Ecke entsprechen, von höchst bis niedrigstwertig, 0, 1, 4, 5, 3, 2, 7 und 6. (In Bezug auf die Neigungen XYZ sind die geordneten Werte 000 100, 010, 110, 001, 101, 011 und 111.)
private static final byte[] BLOCK_PICK_BITS_BY_VERT_INDEX = new byte[]{
(byte)0x67,
(byte)0x26,
(byte)0x23,
(byte)0x37,
(byte)0x45,
(byte)0x04,
(byte)0x01,
(byte)0x15,
(byte)0x57,
(byte)0x46,
(byte)0x02,
(byte)0x13
};
private static final int pickBlockIdForVertex(long blockIds, int vertIndex)
{
int bits = BLOCK_PICK_BITS_BY_VERT_INDEX[vertIndex];
int blockIndexA = bits >> 4;
int blockIndexB = bits & 0xf;
int blockIdA = (int)(blockIds >> 8 * blockIndexA) & 0xff;
int blockIdB = (int)(blockIds >> 8 * blockIndexB) & 0xff;
//assert (blockIdA == airBlockId) != (blockIdB == airBlockId);
//return blockIdA - nonZeroAirBlockId + blockIdB;
return blockIdA + blockIdB;
}
In C / C ++ kann es sinnvoll sein, long blockIds
in ein Array von Bytes / Kurzschlüssen / Zeigern zu wechseln und jeden Vier-Bit-Wert in der Tabelle entsprechend neu zuzuordnen bits = 7 - bits
. Ich habe es jedoch nicht profiliert, daher ist es long
möglicherweise noch schneller , alles in ein zu packen . Schließlich wird eine Luftblock-ID ungleich Null neu angeordnet, sodass bei einer großen Domäne von Block-IDs kein Überlauf auftritt. Würde im obigen Code nicht passieren, da ich ints
blockIds speichere, die es sind bytes
, aber es ist etwas zu beachten.
(Um 100% klar zu sein, trage ich diese Methode zur Public Domain bei und verzichte auf die Haftung gemäß der hier beschriebenen vollständigen Lizenz: http://unlicense.org/ )