space-filling curves: use LUT instead of calculating indices on the fly
parent
f48abfbe7f
commit
ad2c5c2c18
|
@ -2,6 +2,7 @@ package com.emamaker.voxeltest.intervaltrees;
|
|||
|
||||
import com.emamaker.voxeltest.intervaltrees.data.IntervalMap;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Config;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFilling;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.WorldManager;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.blocks.Blocks;
|
||||
import com.jme3.app.SimpleApplication;
|
||||
|
@ -34,6 +35,7 @@ public class Voxel extends SimpleApplication {
|
|||
getCamera().lookAt(new Vector3f(Config.CHUNK_SIZE,Config.CHUNK_SIZE, Config.CHUNK_SIZE), Vector3f.UNIT_Y);
|
||||
|
||||
pos.set(this.getCamera().getLocation());
|
||||
SpaceFilling.initLUT();
|
||||
worldManager.initWorld();
|
||||
// worldManager.benchmark();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.renderer;
|
||||
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Config;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFilling;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Utils;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.Chunk;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.WorldManager;
|
||||
|
@ -71,9 +72,9 @@ public class ChunkRenderer {
|
|||
*/
|
||||
/*
|
||||
* It's not feasible to just create a new mesh everytime a quad needs placing.
|
||||
* This ends up creating TONS of meshes the game with just lag out.
|
||||
* This ends up creating TONS of meshes and the game will just lag out.
|
||||
* As I did in the past, it's better to create a single mesh for each chunk,
|
||||
* containing all the quads. In the future, maybe traslucent blocks and liquids
|
||||
* containing all the quads. In the future, maybe translucent blocks and liquids
|
||||
* will need a separate mesh, but still on a per-chunk basis
|
||||
*/
|
||||
Vector3f[] vertices = new Vector3f[(Config.CHUNK_3DCOORD_MAX_INDEX + 1) * 8];
|
||||
|
@ -85,6 +86,7 @@ public class ChunkRenderer {
|
|||
short cIndex = 0;
|
||||
|
||||
public void greedyMeshing(WorldManager mgr, Chunk chunk) {
|
||||
long begin = System.nanoTime();
|
||||
|
||||
vIndex = 0;
|
||||
iIndex = 0;
|
||||
|
@ -93,10 +95,6 @@ public class ChunkRenderer {
|
|||
// convert tree to array since it is easier to work with it
|
||||
blocks = chunk.treeTo1DArray();
|
||||
|
||||
// System.out.println(Arrays.toString(blocks));
|
||||
|
||||
// chunk.chunkNode = new Node();
|
||||
|
||||
if (blocks.length == 0)
|
||||
return;
|
||||
|
||||
|
@ -131,9 +129,9 @@ public class ChunkRenderer {
|
|||
|
||||
for (x[v] = 0; x[v] < Config.CHUNK_SIZE; x[v]++) {
|
||||
for (x[u] = 0; x[u] < Config.CHUNK_SIZE; x[u]++) {
|
||||
Blocks b1 = (x[dim] >= 0) ? blocks[Utils.MortonToHilbert3D(Utils.Morton_3D_Encode_10bit((short)x[0], (short)x[1], (short)x[2]), Config.HILBERT_BITS)] : null;
|
||||
Blocks b1 = (x[dim] >= 0) ? blocks[SpaceFilling.HILBERT_XYZ_ENCODE[x[0]][x[1]][x[2]]] : null;
|
||||
Blocks b2 = (x[dim] < Config.CHUNK_SIZE - 1)
|
||||
? blocks[Utils.MortonToHilbert3D(Utils.Morton_3D_Encode_10bit((short)(x[0] + q[0]),(short)( x[1] + q[1]), (short) (x[2] + q[2])), Config.HILBERT_BITS)]
|
||||
? blocks[SpaceFilling.HILBERT_XYZ_ENCODE[x[0] + q[0]][x[1] + q[1]][x[2]+q[2]]]
|
||||
: null;
|
||||
|
||||
// This is the original line taken from rob's code, readapted (replace voxelFace
|
||||
|
@ -247,6 +245,7 @@ public class ChunkRenderer {
|
|||
geo.setMaterial(mat);
|
||||
chunk.chunkNode.attachChild(geo);
|
||||
}
|
||||
System.out.println("Greedy meshing of chunk took " + (System.nanoTime()-begin ) + " ns");
|
||||
}
|
||||
|
||||
final int VOXEL_SIZE = 1;
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.utils;
|
||||
|
||||
public class SpaceFilling {
|
||||
// http://and-what-happened.blogspot.com/2011/08/fast-2d-and-3d-hilbert-curves-and.html
|
||||
public static int[][][] MORTON_XYZ_ENCODE;
|
||||
public static short[][] MORTON_XYZ_DECODE;
|
||||
public static int[][][] HILBERT_XYZ_ENCODE;
|
||||
public static short[][] HILBERT_XYZ_DECODE;
|
||||
|
||||
public static void initLUT() {
|
||||
MORTON_XYZ_ENCODE = new int[Config.CHUNK_SIZE][Config.CHUNK_SIZE][Config.CHUNK_SIZE];
|
||||
MORTON_XYZ_DECODE = new short[Config.CHUNK_3DCOORD_MAX_INDEX + 1][3];
|
||||
HILBERT_XYZ_ENCODE = new int[Config.CHUNK_SIZE][Config.CHUNK_SIZE][Config.CHUNK_SIZE];
|
||||
HILBERT_XYZ_DECODE = new short[Config.CHUNK_3DCOORD_MAX_INDEX + 1][3];
|
||||
|
||||
int morton, hilbert;
|
||||
for (short i = 0; i < Config.CHUNK_SIZE; i++)
|
||||
for (short j = 0; j < Config.CHUNK_SIZE; j++)
|
||||
for (short k = 0; k < Config.CHUNK_SIZE; k++) {
|
||||
morton = Morton_3D_Encode_10bit(i,j,k);
|
||||
hilbert = MortonToHilbert3D(morton, Config.HILBERT_BITS);
|
||||
|
||||
MORTON_XYZ_ENCODE[i][j][k] = morton;
|
||||
MORTON_XYZ_DECODE[morton][0] = i;
|
||||
MORTON_XYZ_DECODE[morton][1] = j;
|
||||
MORTON_XYZ_DECODE[morton][2] = k;
|
||||
|
||||
HILBERT_XYZ_ENCODE[i][j][k] = hilbert;
|
||||
HILBERT_XYZ_DECODE[hilbert][0] = i;
|
||||
HILBERT_XYZ_DECODE[hilbert][1] = j;
|
||||
HILBERT_XYZ_DECODE[hilbert][2] = k;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Morton_3D_Encode_10bit(short index1, short index2, short index3) { // pack 3 10-bit indices into a 30-bit Morton code
|
||||
index1 &= 0x000003ff;
|
||||
index2 &= 0x000003ff;
|
||||
index3 &= 0x000003ff;
|
||||
index1 |= (index1 << 16);
|
||||
index2 |= (index2 << 16);
|
||||
index3 |= (index3 << 16);
|
||||
index1 &= 0x030000ff;
|
||||
index2 &= 0x030000ff;
|
||||
index3 &= 0x030000ff;
|
||||
index1 |= (index1 << 8);
|
||||
index2 |= (index2 << 8);
|
||||
index3 |= (index3 << 8);
|
||||
index1 &= 0x0300f00f;
|
||||
index2 &= 0x0300f00f;
|
||||
index3 &= 0x0300f00f;
|
||||
index1 |= (index1 << 4);
|
||||
index2 |= (index2 << 4);
|
||||
index3 |= (index3 << 4);
|
||||
index1 &= 0x030c30c3;
|
||||
index2 &= 0x030c30c3;
|
||||
index3 &= 0x030c30c3;
|
||||
index1 |= (index1 << 2);
|
||||
index2 |= (index2 << 2);
|
||||
index3 |= (index3 << 2);
|
||||
index1 &= 0x09249249;
|
||||
index2 &= 0x09249249;
|
||||
index3 &= 0x09249249;
|
||||
return (index1 | (index2 << 1) | (index3 << 2));
|
||||
}
|
||||
|
||||
public static short[] Morton_3D_Decode_10bit(int morton) { // unpack 3 10-bit indices from a 30-bit Morton code
|
||||
int value1 = morton;
|
||||
int value2 = (value1 >> 1);
|
||||
int value3 = (value1 >> 2);
|
||||
value1 &= 0x09249249;
|
||||
value2 &= 0x09249249;
|
||||
value3 &= 0x09249249;
|
||||
value1 |= (value1 >> 2);
|
||||
value2 |= (value2 >> 2);
|
||||
value3 |= (value3 >> 2);
|
||||
value1 &= 0x030c30c3;
|
||||
value2 &= 0x030c30c3;
|
||||
value3 &= 0x030c30c3;
|
||||
value1 |= (value1 >> 4);
|
||||
value2 |= (value2 >> 4);
|
||||
value3 |= (value3 >> 4);
|
||||
value1 &= 0x0300f00f;
|
||||
value2 &= 0x0300f00f;
|
||||
value3 &= 0x0300f00f;
|
||||
value1 |= (value1 >> 8);
|
||||
value2 |= (value2 >> 8);
|
||||
value3 |= (value3 >> 8);
|
||||
value1 &= 0x030000ff;
|
||||
value2 &= 0x030000ff;
|
||||
value3 &= 0x030000ff;
|
||||
value1 |= (value1 >> 16);
|
||||
value2 |= (value2 >> 16);
|
||||
value3 |= (value3 >> 16);
|
||||
value1 &= 0x000003ff;
|
||||
value2 &= 0x000003ff;
|
||||
value3 &= 0x000003ff;
|
||||
|
||||
return new short[]{(short) value1, (short) value2, (short) value3};
|
||||
}
|
||||
|
||||
public static int MortonToHilbert3D(int morton, int bits) {
|
||||
int hilbert = morton;
|
||||
if (bits > 1) {
|
||||
int block = ((bits * 3) - 3);
|
||||
int hcode = ((hilbert >> block) & 7);
|
||||
int mcode, shift, signs;
|
||||
shift = signs = 0;
|
||||
while (block > 0) {
|
||||
block -= 3;
|
||||
hcode <<= 2;
|
||||
mcode = ((0x20212021 >> hcode) & 3);
|
||||
shift = ((0x48 >> (7 - shift - mcode)) & 3);
|
||||
signs = ((signs | (signs << 3)) >> mcode);
|
||||
signs = ((signs ^ (0x53560300 >> hcode)) & 7);
|
||||
mcode = ((hilbert >> block) & 7);
|
||||
hcode = mcode;
|
||||
hcode = (((hcode | (hcode << 3)) >> shift) & 7);
|
||||
hcode ^= signs;
|
||||
hilbert ^= ((mcode ^ hcode) << block);
|
||||
}
|
||||
}
|
||||
hilbert ^= ((hilbert >> 1) & 0x92492492);
|
||||
hilbert ^= ((hilbert & 0x92492492) >> 1);
|
||||
return (hilbert);
|
||||
}
|
||||
|
||||
public static int HilbertToMorton3D(int hilbert, int bits) {
|
||||
int morton = hilbert;
|
||||
morton ^= ((morton & 0x92492492) >> 1);
|
||||
morton ^= ((morton >> 1) & 0x92492492);
|
||||
if (bits > 1) {
|
||||
int block = ((bits * 3) - 3);
|
||||
int hcode = ((morton >> block) & 7);
|
||||
int mcode, shift, signs;
|
||||
shift = signs = 0;
|
||||
while (block > 0) {
|
||||
block -= 3;
|
||||
hcode <<= 2;
|
||||
mcode = ((0x20212021 >> hcode) & 3);
|
||||
shift = ((0x48 >> (4 - shift + mcode)) & 3);
|
||||
signs = ((signs | (signs << 3)) >> mcode);
|
||||
signs = ((signs ^ (0x53560300 >> hcode)) & 7);
|
||||
hcode = ((morton >> block) & 7);
|
||||
mcode = hcode;
|
||||
mcode ^= signs;
|
||||
mcode = (((mcode | (mcode << 3)) >> shift) & 7);
|
||||
morton ^= ((hcode ^ mcode) << block);
|
||||
}
|
||||
}
|
||||
return (morton);
|
||||
}
|
||||
}
|
|
@ -19,132 +19,4 @@ public class Utils {
|
|||
final int x = idx % maxX;
|
||||
return new int[]{ x, y, z };
|
||||
}
|
||||
// http://and-what-happened.blogspot.com/2011/08/fast-2d-and-3d-hilbert-curves-and.html
|
||||
|
||||
public static int Morton_3D_Encode_10bit( short index1, short index2, short index3 )
|
||||
{ // pack 3 10-bit indices into a 30-bit Morton code
|
||||
index1 &= 0x000003ff;
|
||||
index2 &= 0x000003ff;
|
||||
index3 &= 0x000003ff;
|
||||
index1 |= ( index1 << 16 );
|
||||
index2 |= ( index2 << 16 );
|
||||
index3 |= ( index3 << 16 );
|
||||
index1 &= 0x030000ff;
|
||||
index2 &= 0x030000ff;
|
||||
index3 &= 0x030000ff;
|
||||
index1 |= ( index1 << 8 );
|
||||
index2 |= ( index2 << 8 );
|
||||
index3 |= ( index3 << 8 );
|
||||
index1 &= 0x0300f00f;
|
||||
index2 &= 0x0300f00f;
|
||||
index3 &= 0x0300f00f;
|
||||
index1 |= ( index1 << 4 );
|
||||
index2 |= ( index2 << 4 );
|
||||
index3 |= ( index3 << 4 );
|
||||
index1 &= 0x030c30c3;
|
||||
index2 &= 0x030c30c3;
|
||||
index3 &= 0x030c30c3;
|
||||
index1 |= ( index1 << 2 );
|
||||
index2 |= ( index2 << 2 );
|
||||
index3 |= ( index3 << 2 );
|
||||
index1 &= 0x09249249;
|
||||
index2 &= 0x09249249;
|
||||
index3 &= 0x09249249;
|
||||
return( index1 | ( index2 << 1 ) | ( index3 << 2 ) );
|
||||
}
|
||||
|
||||
public static short[] Morton_3D_Decode_10bit(int morton)
|
||||
{ // unpack 3 10-bit indices from a 30-bit Morton code
|
||||
int value1 = morton;
|
||||
int value2 = ( value1 >> 1 );
|
||||
int value3 = ( value1 >> 2 );
|
||||
value1 &= 0x09249249;
|
||||
value2 &= 0x09249249;
|
||||
value3 &= 0x09249249;
|
||||
value1 |= ( value1 >> 2 );
|
||||
value2 |= ( value2 >> 2 );
|
||||
value3 |= ( value3 >> 2 );
|
||||
value1 &= 0x030c30c3;
|
||||
value2 &= 0x030c30c3;
|
||||
value3 &= 0x030c30c3;
|
||||
value1 |= ( value1 >> 4 );
|
||||
value2 |= ( value2 >> 4 );
|
||||
value3 |= ( value3 >> 4 );
|
||||
value1 &= 0x0300f00f;
|
||||
value2 &= 0x0300f00f;
|
||||
value3 &= 0x0300f00f;
|
||||
value1 |= ( value1 >> 8 );
|
||||
value2 |= ( value2 >> 8 );
|
||||
value3 |= ( value3 >> 8 );
|
||||
value1 &= 0x030000ff;
|
||||
value2 &= 0x030000ff;
|
||||
value3 &= 0x030000ff;
|
||||
value1 |= ( value1 >> 16 );
|
||||
value2 |= ( value2 >> 16 );
|
||||
value3 |= ( value3 >> 16 );
|
||||
value1 &= 0x000003ff;
|
||||
value2 &= 0x000003ff;
|
||||
value3 &= 0x000003ff;
|
||||
|
||||
return new short[]{(short)value1, (short)value2, (short)value3};
|
||||
}
|
||||
|
||||
public static int MortonToHilbert3D( int morton, int bits )
|
||||
{
|
||||
int hilbert = morton;
|
||||
if ( bits > 1 )
|
||||
{
|
||||
int block = ( ( bits * 3 ) - 3 );
|
||||
int hcode = ( ( hilbert >> block ) & 7 );
|
||||
int mcode, shift, signs;
|
||||
shift = signs = 0;
|
||||
while ( block > 0 )
|
||||
{
|
||||
block -= 3;
|
||||
hcode <<= 2;
|
||||
mcode = ( ( 0x20212021 >> hcode ) & 3 );
|
||||
shift = ( ( 0x48 >> ( 7 - shift - mcode ) ) & 3 );
|
||||
signs = ( ( signs | ( signs << 3 ) ) >> mcode );
|
||||
signs = ( ( signs ^ ( 0x53560300 >> hcode ) ) & 7 );
|
||||
mcode = ( ( hilbert >> block ) & 7 );
|
||||
hcode = mcode;
|
||||
hcode = ( ( ( hcode | ( hcode << 3 ) ) >> shift ) & 7 );
|
||||
hcode ^= signs;
|
||||
hilbert ^= ( ( mcode ^ hcode ) << block );
|
||||
}
|
||||
}
|
||||
hilbert ^= ( ( hilbert >> 1 ) & 0x92492492 );
|
||||
hilbert ^= ( ( hilbert & 0x92492492 ) >> 1 );
|
||||
return( hilbert );
|
||||
}
|
||||
|
||||
public static int HilbertToMorton3D( int hilbert, int bits )
|
||||
{
|
||||
int morton = hilbert;
|
||||
morton ^= ( ( morton & 0x92492492 ) >> 1 );
|
||||
morton ^= ( ( morton >> 1 ) & 0x92492492 );
|
||||
if ( bits > 1 )
|
||||
{
|
||||
int block = ( ( bits * 3 ) - 3 );
|
||||
int hcode = ( ( morton >> block ) & 7 );
|
||||
int mcode, shift, signs;
|
||||
shift = signs = 0;
|
||||
while ( block > 0 )
|
||||
{
|
||||
block -= 3;
|
||||
hcode <<= 2;
|
||||
mcode = ( ( 0x20212021 >> hcode ) & 3 );
|
||||
shift = ( ( 0x48 >> ( 4 - shift + mcode ) ) & 3 );
|
||||
signs = ( ( signs | ( signs << 3 ) ) >> mcode );
|
||||
signs = ( ( signs ^ ( 0x53560300 >> hcode ) ) & 7 );
|
||||
hcode = ( ( morton >> block ) & 7 );
|
||||
mcode = hcode;
|
||||
mcode ^= signs;
|
||||
mcode = ( ( ( mcode | ( mcode << 3 ) ) >> shift ) & 7 );
|
||||
morton ^= ( ( hcode ^ mcode ) << block );
|
||||
}
|
||||
}
|
||||
return( morton );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.emamaker.voxeltest.intervaltrees.world;
|
|||
|
||||
import com.emamaker.voxeltest.intervaltrees.data.IntervalMap;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Config;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFilling;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Utils;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.blocks.Blocks;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
@ -111,7 +112,7 @@ public class Chunk {
|
|||
for (int k = 0; k < Config.CHUNK_SIZE; k++) {
|
||||
// Distance from 0,0,0
|
||||
dist = (int) Math.sqrt((i * i) + (j * j) + (k * k));
|
||||
hilbert = Utils.MortonToHilbert3D(Utils.Morton_3D_Encode_10bit((short)i,(short)j,(short)k), Config.HILBERT_BITS);
|
||||
hilbert = SpaceFilling.HILBERT_XYZ_ENCODE[i][j][k];
|
||||
if (dist <= (int) (Config.CHUNK_SIZE / 3))
|
||||
array[hilbert] = Blocks.STONE;
|
||||
else if (dist > (int) (Config.CHUNK_SIZE / 3) && dist <= (int) (2 * Config.CHUNK_SIZE / 3))
|
||||
|
|
Loading…
Reference in New Issue