Creating a voxel system and got stuck, finding myself in the need of information on how to implement it

664 views Asked by At

So, I should probably explain how I want to implement it first. My idea is fairly simple, I want to create each chunk and determine the location of each vertex by utilizing a floating point grid local to each chunk, I then want to place the voxels in a large 64 bit integer grid (each chunks location inferred by the integral value it has, 0,0,0 would be the middle and 20,20,20 would be twenty chunks away on the x, y and z axis) to create a massive world further I would perform some check to determine how the chunks would be generated inferred from their location within the integer grid, something I have yet to figure out. (less important than getting it running)

What I am having problems with:

  1. Figuring out how to generate 3D perlin noise with libnoise, the documentation didn't touch upon this subject from what I can tell and I am getting no decent results from asking google.
  2. Somehow placing the chunks in the integer grid
  3. figuring out exactly how one would then determine how solid the chunk is inferred from the location in the grid (I am thinking this would be simple as checking what the surrounding chunks are and where in the grid you are and determining it based on that data)
  4. Scattering various ores around with rarity based on the location inferred from the integer grid, this one is fairly easy but cannot be done until the others are solved.
  5. figuring out interval trees.

So, any ideas? the relevant code so far (removed light, occlusion,UV and normal calculation code as it is irrelevant to the question)

#define get(x, y, z)\
data[\
        clamp(x, size)+\
        clamp(y, size)*size+\
        clamp(z, size)*size*size\
    ]
#define put(x,y,z, value)\
    data[\
            (x)+\
            (y)*size+\
            (z)*size*size\
        ] = value
#define index(x, y, x) clamp (x, size)+clamp(y, size)*size+clamp(z, size)*size*size

#define foreach_xyz(start, end) \
    int x, y, z; \
    float xf, yf, zf;\
    for(x=(start); x<(end); x++\
    {\
        for(y=(start); y<(end); y++)\
            {\
                for (z=(start); z<(end); z++)\
                {\
                    xf=(float)x/(float)size;\
                    xy=(float)y/(float)size;\
                    xz=(float)z/(float)size;

#define endfor }}}

//removed pointless code from here

typedef struct //vertices
{
    float xVertex, yVertex, zVertex, wVertex;
} vertex;

//removed pointless code from here

typedef struct //cell
{
    float leftCell, rightCell, topCell, bottomCell, frontCell, backCell;
} cell;

//removed pointless code from here

int primitiveCount_CUBE (int size, byte* data)
{
    int value, count = 0;
    foreach_xyz(0, size)
        value = get(x,y,z)ĵ;
        if(!value)
        {
            if(get(x+1, y, z)) count++;
            if(get(x-1, y, z)) count++;
            if(get(x, y+1, z)) count++;
            if(get(x, y-1, z)) count++;
            if(get(x, y, z+1)) count++;
            if(get(x, y, z-1)) count++;
        }
        endfor
        return count;
}

//removed pointless code from here

void setPos(vertex** posPtr, float x0, float y0, float z0,
                         float x1, float y1, float z1,
                         float x2, float y2, float z2,
                         float x3, float y3, float z3)

//removed pointless code from here

void setData(vertex posPtr,
         float x0, float y0, float z0,
         float x1, float y1, float z1,
         float x2, float y2, float z2
         float x3, float y3, float z3,
         normal** normalPtr, float nx, float ny, float nz,
         normal** sPtr, float sx, float sy, float sz,
         normal** tPtr, float tx, float ty, float tz,
         UV** UVPtr, int value,
         color** lightPtr, color** gather,
         float** occlusionPtr, float occlusion)
{
    setPos(posPtr,
           x0, y0, z0
           x1, y1, z1,
           x2, y2, y3,
           x3, y3, z3);

    setNormal(normalPtr, nx, ny, nz
              sPtr, sx, sy, sz
              tPtr, tx, ty, tz);

    setUV(value, UVPtr);
    setLight(gather, lightPtr);
    setOcclusion(occlusion, occlusionPtr);
}

void tesselate(int size, unsigned char* data, cell* occlusion, color** gather,
               vertex pos, normal* Normal, normal* s, normal* t, float outOcc,
               UV* uv, color* light)
{
    float n = 0.5;
    int idx, value;
    cell* Cell;
    color* cellGather;

    foreach_xyz(0, size)
        idx = index(x,y,z);
        cell = occlusion + idx;
        cellGather = gather + idx;
        if(get(x, y, z) == 0)
        {
            value = get(x-1, y, z)
                if(value > 0)
                    setData(&pos, x-n, y-n, z-n,
                            x-n, y+n, z-n,
                            x-n, y+n, z+n,
                            x-n, y-n, z+n

                            &normal, 1, 0, 0,
                            &s, 0, 1, 0
                            &t, 0, 0, 1,
                            &UV, value,
                            &light, cellGather,
                            &outOcc, cell->leftCell);

            value¨= get(x, y-1, z);
            if(value== materials_cube.dirt)
            {
                value=materials_cube.grass;
            }
            if( value > 0 )
                setData(&pos, x-n, y-n, z-n,
                        x-n, y-n, z+n,
                        x+n, y-n, z+n,
                        x+n, y-n, z-n
                        &normal, 0, 1, 0,
                        &s, 0, 0, 1,
                        &t, 1, 0, 0,
                        &UV, value,
                        &light, cellGather
                        &outOcc, cell->bottomCell);

            value = get(x, y+1, z);
            if(value > 0)
                setData(&pos, x-n, y+n, z-n,
                        x+n, y+n, z-n,
                        x+n, y+n, z+n,
                        x-n, y+n, z+n,
                        &normal, 0, -1, 0,
                        &s, 1, 0, 0,
                        &t, 0, 0, 1,
                        &UV, value,
                        &light, cellGather
                        &outOcc, cell->topCell);

            value = get(x, y, z-1);
            if(value > 0)
                setData((&pos, x-n, y-n, z-n
                         x+n, y-n, z-n,
                         x+n, y+n, z-n,
                         x-n, y+n, z-n,
                         &normal, 0, 0, 1,
                         &s, 1, 0, 0,
                         &t, 0, 1, 0,
                         &UV, value,
                         &light, cellGather,
                         &outOcc, cell->backCell);

            value = get(x, y, z+1);
            if(value > 0)
                setData(&pos, x-n, y-n, z+n,
                         x-n, y+n, z+n,
                         x+n, y+n, z+n,
                         x+n, y-n, x+n,
                         &normal, 0, 0, -1,
                         &s, 0, 1, 0,
                         &t, 1, 0, 0,
                         &UV, value,
                         &light, cellGather,
                         &outOcc, cell->frontCell);
        }
    endfor
}

bool neighbors(int size, byte* data, int x, int y, int z)
{
    if(get(x-1, y, z)){return true;}
    if(get(x+1, y, z)){return true;}
    if(get(x, y-1, z)){return true;}
    if(get(x, y+1, z)){return true;}
    if(get(x, y, z-1)){return true;}
    if(get(x, y, z+1)){return true;}
    return false;
}

And that's as far as I can get it, you may notice that this code is very similar to a certain demo written in C and python, this is because a lot of the code was written after reading it and it kind of rubbed off on me

The problem is that it doesn't seem to cover my problems, it gave me a somewhat better understanding on how voxels work, that's it though.

So, any pointers on how I should go by solving this project of mine?

P.S, this is as much a minecraft clone as Battlefield 3 is a DOOM clone, I think I'll let you decide how to interpret that.

Oh and I've done my research, I found: the posts on 0fps, I am sure most of you are familiar with the blog https://sites.google.com/site/letsmakeavoxelengine and a few others including GPU gems 3, marching cubes and a few other things, none of which solve my problem.

1

There are 1 answers

2
Spektre On

I am not sure I get it right from your question but:

  • You want to implement Voxel world based on not full map but on regions instead
  • I am not see any map in your code (but could overlooked it)

I would do it like this (in pseudo code):

class cell
 {
public:
 // physical properties
 float m,Q; // unit mass ,charge, ... 
 float c0,c1,c2; // friction indexes (could determine if it is liquid,gas or solid
 float p[3],v[3],a[3]; // position,velocity,acceleration 3D
 };

class object // or region
 {
public:
 int x0,y0,z0; // obj origin (center preferably)
 int xs,ys,zs; // obj size in cells
 cell *map;     // *map[xs*ys*za] or ***map[xs][ys][zs] do not forget to write dynamic allocation/free resize ...
 };

List<object> world; // list of all objects/regions
  • you have to add remove properties you do or do not need
  • write functions for:
    • parsing the world
    • join split of regions
    • update position (dynamics)
    • events like collision, overheat, explode...

you can also save a lot of memory if your objects are:

1.homogenous

// instead of cell *map;
cell properties; // single property class for whole object
bool *map;         // just a bit map if voxel is empty or occupied by cell

2.sparse populated

// instead of int xs,ys,zs;
// instead of cell *map;
List<cell> map; 
List<int[3]> pos; // position inside object

3.or you can have 3 object class types to combine these approaches

  • use the best suited class for each object
  • and have 3 separate maps of the world (each for each class)

Also if your cell properties are constant then you can create a table of elements (cells)

  • and remember just an ID of element instead of cell for each Voxel

Hope it helps at least a little.