GLBasic forum

Main forum => GLBasic - en => Topic started by: WPShadow on 2013-Oct-01

Title: Voxel - Visibility
Post by: WPShadow on 2013-Oct-01
Hi,

I've got a little problem with the visibility of cubes. I work on a little experiment, where I try to make a big cube with 16 x 16 x 16 small cube.

Now I need only the cubes that the camera can see, everything else isn't necessary to render. The only problem that I have is to detect which cube is hidden.

I tried X_COLLISIONRAY but I've no idea how to use it right.

This is my code for now...

Code: (glbasic) [Select]
// --------------------------------- //
// Project: voxel
// Start: Tuesday, October 01, 2013
// IDE Version: 11.322


// SETCURRENTDIR("Media") // go to media files

TYPE cube_type
typ
x
y
z
active
ENDTYPE

GLOBAL cube[] AS cube_type
GLOBAL counter, visible, size_total

main()



FUNCTION main:

CreateCube(0, 1, RGB(255, 0, 0))
CreateCube(1, 1, RGB(0, 255, 0))
CreateCube(2, 1, RGB(0, 0, 255))

size_total = 16

create_base_chunk(size_total)



WHILE TRUE

X_MAKE3D 1, 1000, 45



X_CAMERA 25, 25, 20, 0, 0, 0



visible = 0

draw_chunk(size_total)

X_MAKE2D

PRINT "counter: " + counter, 0, 0
PRINT "visible: " + visible, 0, 20



SHOWSCREEN

WEND


ENDFUNCTION

FUNCTION draw_chunk: size

FOREACH c IN cube[]

IF c.active = TRUE
INC visible, 1

X_MOVEMENT c.x - (size/2), c.z - (size/2), c.y - (size/2)
X_DRAWOBJ c.typ, 0
ENDIF

NEXT



ENDFUNCTION


FUNCTION create_base_chunk: size
LOCAL tmp_x, tmp_y, tmp_z
LOCAL c AS cube_type
LOCAL hit

FOR tmp_x = 0 TO size - 1
FOR tmp_y = 0 TO size - 1
FOR tmp_z = 0 TO size - 1

c.typ = RND(2)
c.x = tmp_x
c.y = tmp_y
c.z = tmp_z





c.active = TRUE





DIMPUSH cube[], c


INC counter, 1

NEXT
NEXT
NEXT



ENDFUNCTION




// ------------------------------------------------------------- //
// -=#  CREATECUBE  #=-
// ------------------------------------------------------------- //
FUNCTION CreateCube: num, sz, col
        // Diese Variablen sind als LOCAL definiert:
        // num, sz,
        sz=sz/2
        X_OBJSTART num
                // Front Face
                X_OBJADDVERTEX  sz, -sz,  sz, 1, 0, col
                X_OBJADDVERTEX -sz, -sz,  sz, 0, 0, col
                X_OBJADDVERTEX  sz,  sz,  sz, 1, 1, col
                X_OBJADDVERTEX -sz,  sz,  sz, 0, 1, col
                X_OBJNEWGROUP
                // Back Face
                X_OBJADDVERTEX -sz,  sz, -sz, 1, 1, col
                X_OBJADDVERTEX -sz, -sz, -sz, 1, 0, col
                X_OBJADDVERTEX  sz,  sz, -sz, 0, 1, col
                X_OBJADDVERTEX  sz, -sz, -sz, 0, 0, col
                X_OBJNEWGROUP
                // Top Face
                X_OBJADDVERTEX -sz,  sz,  sz, 0, 0, col
                X_OBJADDVERTEX -sz,  sz, -sz, 0, 1, col
                X_OBJADDVERTEX  sz,  sz,  sz, 1, 0, col
                X_OBJADDVERTEX  sz,  sz, -sz, 1, 1, col
                X_OBJNEWGROUP
                // Bottom Face
                X_OBJADDVERTEX  sz, -sz, -sz, 0, 1, col
                X_OBJADDVERTEX -sz, -sz, -sz, 1, 1, col
                X_OBJADDVERTEX  sz, -sz,  sz, 0, 0, col
                X_OBJADDVERTEX -sz, -sz,  sz, 1, 0, col
                X_OBJNEWGROUP
                // Right face
                X_OBJADDVERTEX  sz,  sz, -sz, 1, 1, col
                X_OBJADDVERTEX  sz, -sz, -sz, 1, 0, col
                X_OBJADDVERTEX  sz,  sz,  sz, 0, 1, col
                X_OBJADDVERTEX  sz, -sz,  sz, 0, 0, col
                X_OBJNEWGROUP
                // Left Face
                X_OBJADDVERTEX -sz, -sz,  sz, 1, 0, col
                X_OBJADDVERTEX -sz, -sz, -sz, 0, 0, co :ol
                X_OBJADDVERTEX -sz,  sz,  sz, 1, 1, col
                X_OBJADDVERTEX -sz,  sz, -sz, 0, 1, col
                X_OBJNEWGROUP
        X_OBJEND

ENDFUNCTION // sz

Any idea how I can implement it right?

CU

W.
Title: Re: Voxel - Visibility
Post by: WPShadow on 2013-Oct-01
It is more an experiment than a real project. I try to find out, how I can program it by myself.  =D

Quote
Another question: with assembled voxel objects, shouldn't we only be interested in the outside layer?  That would reduce the amount of data sent to the graphics card enormously...

I know, only to draw the "outside" of the box will reduce the whole thing.

I tried it like this:

Code: (glbasic) [Select]
FUNCTION create_base_chunk: size
LOCAL tmp_x, tmp_y, tmp_z
LOCAL c AS cube_type
LOCAL hit

FOR tmp_x = 0 TO size - 1
FOR tmp_y = 0 TO size - 1
FOR tmp_z = 0 TO size - 1

c.typ = RND(2)
c.x = tmp_x
c.y = tmp_y
c.z = tmp_z




IF c.x = 0 OR c.x = size - 1 OR c.y = 0 OR c.y = size - 1 OR c.z = 0 OR c.z = size - 1
c.active = TRUE
ELSE
c.active = FALSE
ENDIF





DIMPUSH cube[], c


INC anzahl, 1

NEXT
NEXT
NEXT



ENDFUNCTION


But shouldn't it be possible to reduce it more than that? With this I reduced it from 4096 to 1352, but the camera cannot see the backside, so that cubes are not necessary.
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-01
In my 3D maze game, each level is dynamically shaped, and not just a simple cube.
The outside walls enclosing the maze can be any shape, so I created a routine that detects what is around each wall segment to determine if a wall face should be drawn or not (and facing which way).  (See photo to understand what I'm referring to).  It dynamically creates a final 3d wall model containing only the quads it requires.

This algorithm is almost exactly what you would want for mindcraft style cube drawing with face exclusion.
Here's the main loop for x, y, z dimensions:

Code: (glbasic) [Select]
// Create 'walls' model
FOR y = 0 TO sy
FOR z = 0 TO sz
FOR x = 0 TO sx
IF level.map[y][z][x].node = MAP_MT
xPos = x * gridSizeXZ
yPos = y * gridSizeY
zPos = z * gridSizeXZ

IF (x = 0)  OR (x > 0  AND level.map[y][z][x-1].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_W], xPos, yPos, zPos, walls) // Draw Wall West?
IF (x = sx) OR (x < sx AND level.map[y][z][x+1].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_E], xPos, yPos, zPos, walls) // Draw Wall East?
IF (z = 0)  OR (z > 0  AND level.map[y][z-1][x].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_N], xPos, yPos, zPos, walls) // Draw Wall South?
IF (z = sz) OR (z < sz AND level.map[y][z+1][x].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_S], xPos, yPos, zPos, walls) // Draw Wall North?
IF (y = 0)  OR (y > 0  AND level.map[y-1][z][x].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_B], xPos, yPos, zPos, walls) // Draw Wall Bottom?
IF (y = sy) OR (y < sy AND level.map[y+1][z][x].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_T], xPos, yPos, zPos, walls) // Draw Wall Top?
ENDIF
NEXT
NEXT
NEXT

The 3d array contains simple ints (but I only use the first 8 bits (a byte)).
The constant MAP_MT means that array position is within the maze area, and MAP_NL means a null space meaning it is outside of the shape of the maze area.

It is therefore just checking which array positions are separating the solid from the empty, and draws only the correct wall faces it needs.

If you want to see how this is used and initialized, here's the entire (?) code for my wall detection, and the final result is one large wall model with only the front facing wall faces displayed:
(It references custom types I created to simplify the code)

Code: (glbasic) [Select]
GLOBAL sp_walls% = 777 // Wall Sprite Texture ID

FUNCTION Walls_Init:
LOCAL V_TNL% = 0 // Vertice Top North Left
LOCAL V_TNR% = 1 // Vertice Top North Right
LOCAL V_TSL% = 2 // Vertice Top South Left
LOCAL V_TSR% = 3 // Vertice Top South Right
LOCAL V_BNL% = 4 // Vertice Bottom North Left
LOCAL V_BNR% = 5 // Vertice Bottom North Right
LOCAL V_BSL% = 6 // Vertice Bottom South Left
LOCAL V_BSR% = 7 // Vertice Bottom South Right

LOCAL Q_N% = 0 // Quad North
LOCAL Q_S% = 1 // Quad South
LOCAL Q_W% = 2 // Quad West
LOCAL Q_E% = 3 // Quad East
LOCAL Q_T% = 4 // Quad Top
LOCAL Q_B% = 5 // Quad Bottom

LOCAL x%,y%,z%,  sx%,sy%,sz%
LOCAL vx[] AS TVertice
LOCAL quads[] AS TQuad
LOCAL is_even%
LOCAL xPos#, yPos#, zPos#

LOCAL uv1 AS TUv
LOCAL uv2 AS TUv
uv1.Set(0, 0)
uv2.Set(1, 1)

DIM vx[8]
DIM quads[6]

// Initialize level
level = _worlds[_world_ix].levels[_level_ix]
sx = level.size.x - 1
sy = level.size.y - 1
sz = level.size.z - 1

ALIAS walls AS _worlds[_world_ix].walls

level.Create()

en_walls.mesh.Clear()
// Set up base vertices
//     o-----o
//    /|    /|
//   / |   / |
//  o-----o  o
//  | /   | /
//  |/    |/
//  0-----o

vx[V_TNL].Set(         0, gridSizeY,          0, RGB(255,255,255))
vx[V_TNR].Set(gridSizeXZ, gridSizeY,          0, RGB(255,255,255))
vx[V_TSL].Set(         0, gridSizeY, gridSizeXZ, RGB(255,255,255))
vx[V_TSR].Set(gridSizeXZ, gridSizeY, gridSizeXZ, RGB(255,255,255))
vx[V_BNL].Set(         0,         0,          0, RGB(255,255,255))
vx[V_BNR].Set(gridSizeXZ,         0,          0, RGB(255,255,255))
vx[V_BSL].Set(         0,         0, gridSizeXZ, RGB(255,255,255))
vx[V_BSR].Set(gridSizeXZ,         0, gridSizeXZ, RGB(255,255,255))

quads[Q_N].Set(vx[V_TNL], vx[V_TNR], vx[V_BNR], vx[V_BNL], uv1, uv2)
quads[Q_S].Set(vx[V_TSR], vx[V_TSL], vx[V_BSL], vx[V_BSR], uv1, uv2)
quads[Q_W].Set(vx[V_TSL], vx[V_TNL], vx[V_BNL], vx[V_BSL], uv1, uv2)
quads[Q_E].Set(vx[V_TNR], vx[V_TSR], vx[V_BSR], vx[V_BNR], uv1, uv2)
quads[Q_T].Set(vx[V_TSL], vx[V_TSR], vx[V_TNR], vx[V_TNL], uv1, uv2)
quads[Q_B].Set(vx[V_BNL], vx[V_BNR], vx[V_BSR], vx[V_BSL], uv1, uv2)

// Create 'walls' model
FOR y = 0 TO sy
FOR z = 0 TO sz
FOR x = 0 TO sx
IF level.map[y][z][x].node = MAP_MT
xPos = x * gridSizeXZ
yPos = y * gridSizeY
zPos = z * gridSizeXZ

IF (x = 0)  OR (x > 0  AND level.map[y][z][x-1].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_W], xPos, yPos, zPos, walls) // Draw Wall West?
IF (x = sx) OR (x < sx AND level.map[y][z][x+1].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_E], xPos, yPos, zPos, walls) // Draw Wall East?
IF (z = 0)  OR (z > 0  AND level.map[y][z-1][x].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_N], xPos, yPos, zPos, walls) // Draw Wall South?
IF (z = sz) OR (z < sz AND level.map[y][z+1][x].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_S], xPos, yPos, zPos, walls) // Draw Wall North?
IF (y = 0)  OR (y > 0  AND level.map[y-1][z][x].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_B], xPos, yPos, zPos, walls) // Draw Wall Bottom?
IF (y = sy) OR (y < sy AND level.map[y+1][z][x].node = MAP_NL) THEN Walls_QuadAdd(quads[Q_T], xPos, yPos, zPos, walls) // Draw Wall Top?
ENDIF
NEXT
NEXT
NEXT

en_walls.mesh.Generate()
ENDFUNCTION

// Offset the 'local' quad into world space (ie, move the quad to 'x,y,z')
FUNCTION Walls_QuadAdd: quad AS TQuad, x#, y#, z#, walls AS TWalls
LOCAL quad_offset AS TQuad
quad_offset = quad.Copy()
quad_offset.Adjust(x-(gridSizeXZ/2.0), y-(gridSizeY/2.0), z-(gridSizeXZ/2.0))
en_walls.mesh.QuadAdd(quad_offset)
ENDFUNCTION

This cross maze preview may make things clear (excuse the unfinished UI!).  Back faces aren't being displayed to allow you to see the maze while previewing (the maze is slowly spinning around so you can see it from all angles).  The walls are shaped into a cross and only the required faces are added.
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-01
If it helps, here's my dynamic mesh library I use to make creating custom meshes simpler. (Only quads are possible to add to a mesh for now).  I hope it is self explanatory, with the above code showing its usage.

Code: (glbasic) [Select]
CONSTANT CULLMODE_BOTH% = 0
CONSTANT CULLMODE_FRONT% = 1
CONSTANT CULLMODE_BACK% = -1

//-------------------------------------------------------------------------- U V
TYPE TUv
u#
v#

FUNCTION Set: u#, v#
self.u = u
self.v = v
ENDFUNCTION
ENDTYPE

//---------------------------------------------------------------- V e r t i c e
TYPE TVertice
x
y
z
colour%
uv AS TUv

FUNCTION Set: x, y, z, colour%, u=0.0, v=0.0
self.x = x
self.y = y
self.z = z
self.colour = colour
self.uv.Set(u, v)
ENDFUNCTION

FUNCTION Clear%:
self.x = -9999
self.y = -9999
self.z = -9999
self.colour = -9999
self.uv.Set(0.0, 0.0)
ENDFUNCTION

FUNCTION Adjust%: x#, y#, z#
INC self.x, x
INC self.y, y
INC self.z, z
ENDFUNCTION

ENDTYPE

//---------------------------------------------------------------------- Q u a d
TYPE TQuad
v1 AS TVertice
v2 AS TVertice
v3 AS TVertice
v4 AS TVertice

FUNCTION Clear%:
self.v1.Clear()
self.v2.Clear()
self.v3.Clear()
self.v4.Clear()
ENDFUNCTION

FUNCTION Set%: v1 AS TVertice, v2 AS TVertice, v3 AS TVertice, v4 AS TVertice, uv1 AS TUv, uv2 AS TUv, colour%=-9999
self.v1 = v1
self.v2 = v2
self.v3 = v3
self.v4 = v4
self.SetUv(uv1, uv2)
IF (colour <> -9999) THEN self.ColourSet(colour)
ENDFUNCTION

FUNCTION Adjust%: x#, y#, z#
self.v1.Adjust(x, y, z)
self.v2.Adjust(x, y, z)
self.v3.Adjust(x, y, z)
self.v4.Adjust(x, y, z)
ENDFUNCTION

FUNCTION Copy AS TQuad:
LOCAL dest AS TQuad
dest.Clear()
dest.v1 = self.v1
dest.v2 = self.v2
dest.v3 = self.v3
dest.v4 = self.v4
RETURN dest
ENDFUNCTION

FUNCTION SetUv%: uv1 AS TUv, uv2 AS TUv
self.v1.uv.u = uv1.u; self.v1.uv.v = uv1.v
self.v2.uv.u = uv2.u; self.v2.uv.v = uv1.v
self.v3.uv.u = uv2.u; self.v3.uv.v = uv2.v
self.v4.uv.u = uv1.u; self.v4.uv.v = uv2.v
ENDFUNCTION

FUNCTION ColourSet%: colour%
self.v1.colour = colour
self.v2.colour = colour
self.v3.colour = colour
self.v4.colour = colour
ENDFUNCTION

ENDTYPE



//---------------------------------------------------------------------- M e s h
TYPE TMesh
quads[] AS TQuad

// Must call this before using. It clears any previous quads, plus sets the model id used for displaying this 3d model.
FUNCTION Clear:
IF self.id < 0 THEN self.id = Mesh_CreateID()
DIM self.quads[0]
ENDFUNCTION

//     5-----4
//    /| .  /|
//   / |   /.|
//  0-----1  7
//  | /.  | /
//  |/    |/
//  3-----2
FUNCTION NewCube: width, height, depth, colour%, uv1 AS TUv, uv2 AS TUv
LOCAL w, h, d
LOCAL vx[] AS TVertice

DIM vx[8]
w = width / 2.0
h = height / 2.0
d = depth / 2.0

vx[0].Set(-w, h, d, colour) // FTL
vx[1].Set( w, h, d, colour) // FTR
vx[2].Set( w,-h, d, colour) // FBR
vx[3].Set(-w,-h, d, colour) // FBL
vx[4].Set( w, h,-d, colour) // BTR
vx[5].Set(-w, h,-d, colour) // BTL
vx[6].Set(-w,-h,-d, colour) // BBL
vx[7].Set( w,-h,-d, colour) // BBR

self.QuadAddV4(vx[0], vx[1], vx[2], vx[3], uv1, uv2) // Front
self.QuadAddV4(vx[5], vx[0], vx[3], vx[6], uv1, uv2) // Left
self.QuadAddV4(vx[1], vx[4], vx[7], vx[2], uv1, uv2) // Right
self.QuadAddV4(vx[5], vx[4], vx[1], vx[0], uv1, uv2) // Top
self.QuadAddV4(vx[3], vx[2], vx[7], vx[6], uv1, uv2) // Bottom
self.QuadAddV4(vx[4], vx[5], vx[6], vx[7], uv1, uv2) // Back

self.Generate()

DIM vx[0]
ENDFUNCTION

FUNCTION QuadAdd%: quad AS TQuad
DIMPUSH self.quads[], quad
ENDFUNCTION

FUNCTION QuadAddV4%: v1 AS TVertice, v2 AS TVertice, v3 AS TVertice, v4 AS TVertice, uv1 AS TUv, uv2 AS TUv
LOCAL quad AS TQuad
quad.Set(v1, v2, v3, v4, uv1, uv2)
DIMPUSH self.quads[], quad
ENDFUNCTION

// Call this when all the quads have been set.  This will add the actual vertices to the model.
FUNCTION Generate%:
LOCAL qx%
LOCAL qty%
qty = LEN(self.quads[]) - 1
X_OBJSTART self.id
FOR qx = 0 TO qty
self.QuadGenerate(qx)
IF qx < qty THEN X_OBJNEWGROUP
NEXT
X_OBJEND
ENDFUNCTION

FUNCTION QuadGenerate: qx%, cullmode%=CULLMODE_FRONT
ALIAS quad AS self.quads[qx]
IF (cullmode = CULLMODE_BACK) OR (cullmode = CULLMODE_BOTH)
X_OBJADDVERTEX quad.v1.x, quad.v1.y, quad.v1.z, quad.v1.uv.u, quad.v1.uv.v, quad.v1.colour
X_OBJADDVERTEX quad.v4.x, quad.v4.y, quad.v4.z, quad.v4.uv.u, quad.v4.uv.v, quad.v4.colour
X_OBJADDVERTEX quad.v2.x, quad.v2.y, quad.v2.z, quad.v2.uv.u, quad.v2.uv.v, quad.v2.colour
X_OBJADDVERTEX quad.v3.x, quad.v3.y, quad.v3.z, quad.v3.uv.u, quad.v3.uv.v, quad.v3.colour
ENDIF
IF (cullmode = CULLMODE_FRONT) OR (cullmode = CULLMODE_BOTH)
quad.Adjust(0, -0.0001, 0)
X_OBJADDVERTEX quad.v2.x, quad.v2.y, quad.v2.z, quad.v2.uv.u, quad.v2.uv.v, quad.v2.colour
X_OBJADDVERTEX quad.v3.x, quad.v3.y, quad.v3.z, quad.v3.uv.u, quad.v3.uv.v, quad.v3.colour
X_OBJADDVERTEX quad.v1.x, quad.v1.y, quad.v1.z, quad.v1.uv.u, quad.v1.uv.v, quad.v1.colour
X_OBJADDVERTEX quad.v4.x, quad.v4.y, quad.v4.z, quad.v4.uv.u, quad.v4.uv.v, quad.v4.colour
ENDIF
RETURN
ENDFUNCTION

ENDTYPE

FUNCTION Mesh_CreateID%:
STATIC id% = 1000 // Leave room for other models loaded from a file
INC id
RETURN id
ENDFUNCTION
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-01
I went through the code and attempted to create the exact logic you would need in your situation.  Not tested so expect a bug or two.  And, it uses the above dynamic mesh library.

Code: (glbasic) [Select]
CONSTANT CUBE_AIR = 0
CONSTANT CUBE_DIRT = 1

GLOBAL walls AS TMesh
GLOBAL cubes[] // A 3 dimensional array with integers where 0 is empty (CUBE_AIR), and 1 is where a dirt cube is located (CUBE_DIRT).  For this code, it is assumed to be already dimensioned and filled with data.

FUNCTION Walls_Init:
        LOCAL V_TNL% = 0        // Vertice Top North Left
        LOCAL V_TNR% = 1        // Vertice Top North Right
        LOCAL V_TSL% = 2        // Vertice Top South Left
        LOCAL V_TSR% = 3        // Vertice Top South Right
        LOCAL V_BNL% = 4        // Vertice Bottom North Left
        LOCAL V_BNR% = 5        // Vertice Bottom North Right
        LOCAL V_BSL% = 6        // Vertice Bottom South Left
        LOCAL V_BSR% = 7        // Vertice Bottom South Right

        LOCAL Q_N% = 0          // Quad North
        LOCAL Q_S% = 1          // Quad South
        LOCAL Q_W% = 2          // Quad West
        LOCAL Q_E% = 3          // Quad East
        LOCAL Q_T% = 4          // Quad Top
        LOCAL Q_B% = 5          // Quad Bottom

        LOCAL x%,y%,z%,  sx%,sy%,sz%
        LOCAL vx[]              AS TVertice
        LOCAL quads[]   AS TQuad

        LOCAL uv1 AS TUv
        LOCAL uv2 AS TUv
        uv1.Set(0, 0)
        uv2.Set(1, 1)

        DIM vx[8]
        DIM quads[6]

sx = BOUNDS(cubes[], 0) - 1 // World width
sy = BOUNDS(cubes[], 1) - 1 // World height
sz = BOUNDS(cubes[], 2) - 1 // World depth

        walls.Clear()

        // Set up base vertices
        //     o-----o
        //    /|    /|
        //   / |   / |
        //  o-----o  o
        //  | /   | /
        //  |/    |/
        //  0-----o

// Assuming a cube size of 1,1,1
        vx[V_TNL].Set(0, 1, 0, RGB(255,255,255))
        vx[V_TNR].Set(1, 1, 0, RGB(255,255,255))
        vx[V_TSL].Set(0, 1, 1, RGB(255,255,255))
        vx[V_TSR].Set(1, 1, 1, RGB(255,255,255))
        vx[V_BNL].Set(0, 0, 0, RGB(255,255,255))
        vx[V_BNR].Set(1, 0, 0, RGB(255,255,255))
        vx[V_BSL].Set(0, 0, 1, RGB(255,255,255))
        vx[V_BSR].Set(1, 0, 1, RGB(255,255,255))

        quads[Q_N].Set(vx[V_TNL], vx[V_TNR], vx[V_BNR], vx[V_BNL], uv1, uv2)
        quads[Q_S].Set(vx[V_TSR], vx[V_TSL], vx[V_BSL], vx[V_BSR], uv1, uv2)
        quads[Q_W].Set(vx[V_TSL], vx[V_TNL], vx[V_BNL], vx[V_BSL], uv1, uv2)
        quads[Q_E].Set(vx[V_TNR], vx[V_TSR], vx[V_BSR], vx[V_BNR], uv1, uv2)
        quads[Q_T].Set(vx[V_TSL], vx[V_TSR], vx[V_TNR], vx[V_TNL], uv1, uv2)
        quads[Q_B].Set(vx[V_BNL], vx[V_BNR], vx[V_BSR], vx[V_BSL], uv1, uv2)

        // Create 'walls' model
FOR x = 0 TO sx
FOR y = 0 TO sy
                FOR z = 0 TO sz
IF cubes[x][y][z] <> CUBE_AIR // Evaluate all non-air cubes
IF (x = 0)  OR (x > 0   AND cubes[x-1][y][z] = CUBE_AIR) THEN Walls_QuadAdd(quads[Q_W], x,y,z, walls) // Draw Wall West?
IF (x = sx) OR (x < sx  AND cubes[x+1][y][z] = CUBE_AIR) THEN Walls_QuadAdd(quads[Q_E], x,y,z, walls) // Draw Wall East?
IF (z = 0)  OR (z > 0   AND cubes[x][y][z-1] = CUBE_AIR) THEN Walls_QuadAdd(quads[Q_N], x,y,z, walls) // Draw Wall South?
IF (z = sz) OR (z < sz  AND cubes[x][y][z+1] = CUBE_AIR) THEN Walls_QuadAdd(quads[Q_S], x,y,z, walls) // Draw Wall North?
IF (y = 0)  OR (y > 0   AND cubes[x][y-1][z] = CUBE_AIR) THEN Walls_QuadAdd(quads[Q_B], x,y,z, walls) // Draw Wall Bottom?
IF (y = sy) OR (y < sy  AND cubes[x][y+1][z] = CUBE_AIR) THEN Walls_QuadAdd(quads[Q_T], x,y,z, walls) // Draw Wall Top?
ENDIF
NEXT
NEXT
NEXT

        walls.Generate()  // Now you can display this model using 'walls.id'.
ENDFUNCTION

// Offset the 'local' quad into world space (ie: move the quad to 'x,y,z')
FUNCTION Walls_QuadAdd: quad AS TQuad, x#, y#, z#, walls AS TMesh
        LOCAL quad_offset AS TQuad
        quad_offset = quad.Copy()
        quad_offset.Adjust(x-0.5, y-0.5, z-0.5)
        walls.QuadAdd(quad_offset)
ENDFUNCTION

[Edit] Various changes to improve code
Title: Re: Voxel - Visibility
Post by: mentalthink on 2013-Oct-01
I leave some days ago in some part of the forum (sorry I don't know where is, (conversation with Bigsofty Erico and me)), and explains how do a Voxel Engine from Zero... It's C++, but practically all can be traslate without too much problems (I think  :P)

About X_ray coll in Examples folder you have a simple Sample, take a lool it's easy to use, I have a similar code in my 3D Lighting Editor, not is complex to use.

I give you this idea, I'm not sure if works, but perhaps runs, from the camera launch some rays to the target of the camera, in example a matrix of 16 rays, separatex X units, then when you detect some cube draw it, the others you have to hide...
Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-01
It all looks incredibly sofisticated! Congratulations, love the screen shot! :good:
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-01
I made quite a few changes to my latest post above to fix things, or simplify things.

If you wanted different cube types, such as grass, rock, dirt, it shouldn't be too difficult to adapt the code.
You would need a texture atlas (sprite sheet) that contains all of the faces of each cube (well, a cube has the four side faces that are the same, perhaps five if you make the bottom the same as the sides, plus a custom top image).  You would need some kind of lookup to find the desired uv locations for each face for each cube.  Then lookup those uvs inside the nested FOR loop, depending on which cube type your are evaluating.

[Edit] Then you would want to implement a chunking system, to break the world model into smaller model units, perhaps 8x8x8, to help with occuling and processing in open gl.
Title: Re: Voxel - Visibility
Post by: WPShadow on 2013-Oct-02
Hey,

thanks for the examples, they are really great. It will take a little time to analyse my current code and see how I can use it with your examples.

But I will reply as fast as I can... (I think arround the weekend)

CU

W.

Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-02
Cool, can't wait to see what you come up with! 
I wanted to try a voxel like render engine for some time now, but never got around to it.
Oh, and just thinking about the code I posted, it may render the cubes inside-out (as my game you were inside the walls).  You would just reverse the vertice winding direction to get the quads to face the other way.
Title: Re: Voxel - Visibility
Post by: Schranz0r on 2013-Oct-02
Code from me and WP yesterday:

Code: (glbasic) [Select]
// --------------------------------- //
// Project: RL Test Chunks
// Start: Tuesday, October 01, 2013
// IDE Version: 11.414

GLOBAL CHUNKSIZE = 12
GLOBAL CUBESIZE = 1


GLOBAL CUBE_TOP = 1
GLOBAL CUBE_BOTTOM = 2
GLOBAL CUBE_LEFT = 4
GLOBAL CUBE_RIGHT = 8
GLOBAL CUBE_FRONT = 16
GLOBAL CUBE_BACK = 32

GLOBAL Counter = 0

TYPE TCube
typ% // 0 = Air, 1 = dirt
x#;y#;z#
active% // False/True
bin% // 1 = top, 2 = bottom, 4 = left, 8 = right, 16 = front, 32 = back
ENDTYPE


TYPE TChunk
cubes[] AS TCube
x#;y#;z#

FUNCTION Create:
REDIM self.cubes[CHUNKSIZE+2][CHUNKSIZE+2][CHUNKSIZE+2]


FOR x = 1 TO CHUNKSIZE
FOR y = 1 TO CHUNKSIZE
FOR z = 1 TO CHUNKSIZE

self.cubes[x][y][z].typ = RND(1)
self.cubes[x][y][z].x = x*CUBESIZE/2
self.cubes[x][y][z].y = y*CUBESIZE/2
self.cubes[x][y][z].z = z*CUBESIZE/2
self.cubes[x][y][z].active = TRUE
//DEBUG "X:"+x+" Y:"+y+" Z:"+z+" TYP:"+self.cubes[x][y][z].typ+"\n"

NEXT
NEXT
NEXT


ENDFUNCTION


FUNCTION CheckSides:
X_OBJSTART 1
FOR x = 1 TO CHUNKSIZE
FOR y = 1 TO CHUNKSIZE
FOR z = 1 TO CHUNKSIZE


IF self.cubes[x][y][z].typ > 0
// Face left active
IF self.cubes[x-1][y][z].typ = 0; RenderLeft(CUBESIZE,x, y, z, RGB(255,0,0)); INC Counter; ENDIF
// Face right active
IF self.cubes[x+1][y][z].typ = 0; RenderRight(CUBESIZE,x, y, z, RGB(255,0,0)); INC Counter; ENDIF
// Face bottom active
IF self.cubes[x][y-1][z].typ = 0; RenderBottom(CUBESIZE,x, y, z, RGB(0,255,0)); INC Counter; ENDIF
// Face top active
IF self.cubes[x][y+1][z].typ = 0; RenderTop(CUBESIZE,x, y, z, RGB(0,255,0)); INC Counter; ENDIF
// Face front active
IF self.cubes[x][y][z+1].typ = 0; RenderFront(CUBESIZE,x, y, z, RGB(0,0,255)); INC Counter; ENDIF
// Face back active
IF self.cubes[x][y][z-1].typ = 0; RenderBack(CUBESIZE,x, y, z, RGB(0,0,255)); INC Counter; ENDIF
ENDIF

NEXT
NEXT
NEXT
X_OBJEND
ENDFUNCTION

ENDTYPE


LOCAL chunk1 AS TChunk
chunk1.Create()
chunk1.CheckSides()

LOCAL phi

WHILE TRUE

INC phi
X_MAKE3D 1, 1000, 45
X_CAMERA 0, 0, 30, 0, 0, 0


X_ROTATION phi,0,.15,0

X_PUSHMATRIX
X_MOVEMENT -CHUNKSIZE/2,-CHUNKSIZE/2,-CHUNKSIZE/2
X_DRAWOBJ 1, 0
X_POPMATRIX

X_MAKE2D

PRINT Counter,10,10

SHOWSCREEN
WEND
END


FUNCTION RenderFront: sz, x, y, z, col
                // Front Face
                sz=sz/2
                X_OBJADDVERTEX x+ sz, y-sz,  z+sz, 1, 0, col
                X_OBJADDVERTEX x-sz, y-sz,  z+sz, 0, 0, col
                X_OBJADDVERTEX x+ sz, y+ sz,  z+sz, 1, 1, col
                X_OBJADDVERTEX x-sz,  y+sz,  z+sz, 0, 1, col
                X_OBJNEWGROUP
ENDFUNCTION

FUNCTION RenderBack: sz, x, y, z, col
sz=sz/2
                X_OBJADDVERTEX x-sz, y+ sz, z-sz, 1, 1, col
                X_OBJADDVERTEX x-sz, y-sz, z-sz, 1, 0, col
                X_OBJADDVERTEX x+ sz, y+ sz, z-sz, 0, 1, col
                X_OBJADDVERTEX x+ sz, y-sz, z-sz, 0, 0, col
                X_OBJNEWGROUP
ENDFUNCTION

FUNCTION RenderTop: sz, x, y, z, col
                // Top Face
                sz=sz/2
                X_OBJADDVERTEX x-sz, y+ sz,  z+sz, 0, 0, col
                X_OBJADDVERTEX x-sz, y+ sz, z-sz, 0, 1, col
                X_OBJADDVERTEX x+ sz, y+ sz, z+ sz, 1, 0, col
                X_OBJADDVERTEX x+ sz, y+sz, z-sz, 1, 1, col
                X_OBJNEWGROUP
ENDFUNCTION

FUNCTION RenderBottom: sz, x, y, z, col
                // Bottom Face
                sz=sz/2
                X_OBJADDVERTEX  x+sz, y-sz, z-sz, 0, 1, col
                X_OBJADDVERTEX x-sz, y-sz, z-sz, 1, 1, col
                X_OBJADDVERTEX  x+sz, y-sz, z+ sz, 0, 0, col
                X_OBJADDVERTEX x-sz, y-sz,  z+sz, 1, 0, col
                X_OBJNEWGROUP
ENDFUNCTION

FUNCTION RenderRight: sz, x, y, z, col
                // Right face
                sz=sz/2
                X_OBJADDVERTEX  x+sz,  y+sz, z-sz, 1, 1, col
                X_OBJADDVERTEX  x+sz, y-sz, z-sz, 1, 0, col
                X_OBJADDVERTEX  x+sz,  y+sz, z+ sz, 0, 1, col
                X_OBJADDVERTEX  x+sz, y-sz,  z+sz, 0, 0, col
                X_OBJNEWGROUP
ENDFUNCTION

FUNCTION RenderLeft: sz, x, y, z, col
                // Left Face
                sz=sz/2
                X_OBJADDVERTEX x-sz, y-sz, z+ sz, 1, 0, col
                X_OBJADDVERTEX x-sz, y-sz, z-sz, 0, 0, col
                X_OBJADDVERTEX x-sz,  y+sz,  z+sz, 1, 1, col
                X_OBJADDVERTEX x-sz,  y+sz, z-sz, 0, 1, col
                X_OBJNEWGROUP
ENDFUNCTION

someone have improvements?!
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-02
Nice!  Looking through your code I see it works basically how mine was structured, with obvious differences.

I like how you were planning to not create the quads in the CheckSides() function, but only update the cube.bin value by adding up CUBE_TOP + CUBE_LEFT + CUBE_BACK (for example) to predetermine which sides this cube has exposed.  I assume you were then going to write a function to actually create the geometry such as CreateSides().  (As of now the .bin value isn't used, nor the CUBE_TOP... constants).  But you combined them, which works just the same.

Any screenshots?!
Are you planning on adding multiple chunks?  Automatic chunking?
Now, get a perlin noise generator to create random MineCraft style worlds with multiple ground types!
Title: Re: Voxel - Visibility
Post by: Schranz0r on 2013-Oct-02
Yes the first plan was a binarysystem for the sides...
We had some bugs ( display all sides correct ), it was awful!
We fixed it at like 12 pm ^^ horrible time to code...

What's the next plans:
- improve the renderspeed
- improve the CheckSides()  (atm realy realy reeeeeeealy slow :(  )
- "re-implement" the' binarysides' TCube.bin
- experiment with chunks / threading / Perlinnoise in 3D
- give up because we suck :D
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-02
Sounds like a great to-do list.
I'm so good, I already skipped to your last step!  Wait, that's a contradiction!?

I notice you dimension your array CHUNKSIZE+2.
And, in your CheckSides() routine, you have checks such as:
Code: (glbasic) [Select]
IF self.cubes[x-1][y][z].typ = 0; RenderLeft(...I assume the CHUNKSIZE+2 was so your checks didn't go outside of your array bounds, and the outer perimeter of you chunk (in the array) doesn't actually contain any cubes. 

Does your code actually render the very outside faces (where x=1 for example)?  If not, a simple addition should fix this such as:
Code: (glbasic) [Select]
IF (x=1) OR (self.cubes[x-1][y][z].typ = 0); RenderLeft(...
Plus, you could update your array to be exactly CHUNKSIZE (no +2), then start your loops at zero, and add one more check (the x > 0), as I did:
Code: (glbasic) [Select]
// Draw Wall West?
IF (x = 0)  OR (x > 0   AND cubes[x-1][y][z] = CUBE_AIR) THEN Walls_QuadAdd(quads[Q_W], x,y,z, walls)
You would save some memory by not having a blank buffer surrounding the chunk.

And you find it 'reallllly' slow eh?  I wonder why, that's basically how I render my maze walls, and including generating a random maze, calculating the wall faces, and displaying everything, it takes less than a second I think. (I had profiling code to verify, but can't remember the actual results!)

Keep us updated.
Title: Re: Voxel - Visibility
Post by: Schranz0r on 2013-Oct-02
New Version:

Code: (glbasic) [Select]
// --------------------------------- //
// Project: RL Test Chunks
// Start: Tuesday, October 01, 2013
// IDE Version: 11.414

GLOBAL CHUNKSIZE = 18
GLOBAL CUBESIZE = 1


GLOBAL CUBE_TOP = 1
GLOBAL CUBE_BOTTOM = 2
GLOBAL CUBE_LEFT = 4
GLOBAL CUBE_RIGHT = 8
GLOBAL CUBE_FRONT = 16
GLOBAL CUBE_BACK = 32

GLOBAL FACE_TOP = 10 
GLOBAL FACE_BOTTOM = 11
GLOBAL FACE_LEFT = 12
GLOBAL FACE_RIGHT = 13
GLOBAL FACE_FRONT = 14
GLOBAL FACE_BACK = 15


RenderTop(FACE_TOP,1,RGB(255,0,0))
RenderBottom(FACE_BOTTOM,1,RGB(0,0,255))
RenderLeft(FACE_LEFT,1,RGB(0,255,0))
RenderRight(FACE_RIGHT,1,RGB(255,255,0))
RenderFront(FACE_FRONT,1,RGB(0,255,255))
RenderBack(FACE_BACK,1,RGB(255,255,255))

GLOBAL Counter = 0

TYPE TCube
typ% // 0 = Air, 1 = dirt
x#;y#;z#
active% // False/True
bin% // 1 = top, 2 = bottom, 4 = left, 8 = right, 16 = front, 32 = back
ENDTYPE


TYPE TChunk
cubes[] AS TCube
x#;y#;z#

FUNCTION Create:
REDIM self.cubes[CHUNKSIZE+2][CHUNKSIZE+2][CHUNKSIZE+2]


FOR x = 1 TO CHUNKSIZE
FOR y = 1 TO CHUNKSIZE
FOR z = 1 TO CHUNKSIZE

self.cubes[x][y][z].typ = RND(1)
self.cubes[x][y][z].x = x*CUBESIZE/2
self.cubes[x][y][z].y = y*CUBESIZE/2
self.cubes[x][y][z].z = z*CUBESIZE/2
self.cubes[x][y][z].active = TRUE
//DEBUG "X:"+x+" Y:"+y+" Z:"+z+" TYP:"+self.cubes[x][y][z].typ+"\n"

NEXT
NEXT
NEXT


ENDFUNCTION

FUNCTION CheckSides_BIN:

FOR x = 1 TO CHUNKSIZE
FOR y = 1 TO CHUNKSIZE
FOR z = 1 TO CHUNKSIZE


IF self.cubes[x][y][z].typ > 0
// Face left active
IF self.cubes[x-1][y][z].typ = 0; INC self.cubes[x][y][z].bin, CUBE_LEFT; INC Counter; ENDIF
// Face right active
IF self.cubes[x+1][y][z].typ = 0; INC self.cubes[x][y][z].bin, CUBE_RIGHT; INC Counter; ENDIF
// Face bottom active
IF self.cubes[x][y-1][z].typ = 0; INC self.cubes[x][y][z].bin, CUBE_BOTTOM; INC Counter; ENDIF
// Face top active
IF self.cubes[x][y+1][z].typ = 0; INC self.cubes[x][y][z].bin, CUBE_TOP; INC Counter; ENDIF
// Face front active
IF self.cubes[x][y][z+1].typ = 0; INC self.cubes[x][y][z].bin, CUBE_FRONT; INC Counter; ENDIF
// Face back active
IF self.cubes[x][y][z-1].typ = 0; INC self.cubes[x][y][z].bin, CUBE_BACK; INC Counter; ENDIF
ENDIF

NEXT
NEXT
NEXT

ENDFUNCTION

FUNCTION Render:
X_MOVEMENT -CHUNKSIZE/2-CUBESIZE/2, -CHUNKSIZE/2-CUBESIZE/2, -CHUNKSIZE/2-CUBESIZE/2
X_PUSHMATRIX

FOR x = 1 TO CHUNKSIZE
FOR y = 1 TO CHUNKSIZE
FOR z = 1 TO CHUNKSIZE
IF self.cubes[x][y][z].bin = 0 THEN CONTINUE
LOCAL tmp_bin = self.cubes[x][y][z].bin
LOCAL v, d
//DEBUG "BIN: "+self.cubes[x][y][z].bin+"\n"
// 1 = top, 2 = bottom, 4 = left, 8 = right, 16 = front, 32 = back
IF tmp_bin >= CUBE_BACK

//Draw back
X_MOVEMENT x, y, z
X_DRAWOBJ FACE_BACK, 0
// v = tmp_bin
DEC tmp_bin, CUBE_BACK
// d = tmp_bin
// DEBUG "BACK V: "+v+"N: "+d+"\n"
ENDIF

IF tmp_bin > 0
IF tmp_bin >= CUBE_FRONT
//draw front
X_MOVEMENT x, y, z
X_DRAWOBJ FACE_FRONT, 0
// v = tmp_bin
DEC tmp_bin, CUBE_FRONT
// d = tmp_bin
// DEBUG "FRONT V: "+v+"N: "+d+"\n"
ENDIF
ENDIF

IF tmp_bin > 0
IF tmp_bin >= CUBE_RIGHT
//draw right
X_MOVEMENT x, y, z
X_DRAWOBJ FACE_RIGHT, 0
// v = tmp_bin
DEC tmp_bin, CUBE_RIGHT
// d = tmp_bin
// DEBUG "RIGHT V: "+v+"N: "+d+"\n"
ENDIF
ENDIF

IF tmp_bin > 0
IF tmp_bin >= CUBE_LEFT
//draw left
X_MOVEMENT x, y, z
X_DRAWOBJ FACE_LEFT, 0
// v = tmp_bin
DEC tmp_bin, CUBE_LEFT
// d = tmp_bin
// DEBUG "LEFT V: "+v+"N: "+d+"\n"
ENDIF
ENDIF

IF tmp_bin > 0
IF tmp_bin >= CUBE_BOTTOM
//draw bottom
X_MOVEMENT x, y, z
X_DRAWOBJ FACE_BOTTOM, 0
// v = tmp_bin
DEC tmp_bin, CUBE_BOTTOM
// d = tmp_bin
// DEBUG "BOTTOM V: "+v+"N: "+d+"\n"
ENDIF
ENDIF

IF tmp_bin > 0
IF tmp_bin = CUBE_TOP
//draw top
X_MOVEMENT x, y, z
X_DRAWOBJ FACE_TOP, 0
// v = tmp_bin
DEC tmp_bin, CUBE_TOP
// d = tmp_bin
// DEBUG "BACK V: "+v+"N: "+d+"\n"
ENDIF
ENDIF

NEXT
NEXT
NEXT

X_POPMATRIX

ENDFUNCTION

ENDTYPE


LOCAL chunk1 AS TChunk
chunk1.Create()
chunk1.CheckSides_BIN()


LOCAL phi

WHILE TRUE

INC phi
X_MAKE3D 1, 1000, 45
X_CAMERA 0, 0, 50, 0, 0, 0

X_SPOT_LT -2, 0, 0,0,100, 0,0,0,90

X_ROTATION phi,.25,.5,1
X_PUSHMATRIX
chunk1.Render()
X_POPMATRIX


X_MAKE2D

PRINT Counter,10,10

SHOWSCREEN
WEND
END


FUNCTION RenderFront: num, sz, col
                sz=sz/2
X_OBJSTART num
                // Front Face
                X_OBJADDVERTEX  sz, -sz,  sz, 1, 0, col
                X_OBJADDVERTEX -sz, -sz,  sz, 0, 0, col
                X_OBJADDVERTEX  sz,  sz,  sz, 1, 1, col
                X_OBJADDVERTEX -sz,  sz,  sz, 0, 1, col
                X_OBJNEWGROUP
    X_OBJEND
ENDFUNCTION

FUNCTION RenderBack: num, sz, col
                sz=sz/2
X_OBJSTART num
                // Back Face
                X_OBJADDVERTEX -sz,  sz, -sz, 1, 1, col
                X_OBJADDVERTEX -sz, -sz, -sz, 1, 0, col
                X_OBJADDVERTEX  sz,  sz, -sz, 0, 1, col
                X_OBJADDVERTEX  sz, -sz, -sz, 0, 0, col
                X_OBJNEWGROUP
    X_OBJEND
ENDFUNCTION

FUNCTION RenderTop: num, sz, col
                sz=sz/2
X_OBJSTART num
                // Top Face
                X_OBJADDVERTEX -sz,  sz,  sz, 0, 0, col
                X_OBJADDVERTEX -sz,  sz, -sz, 0, 1, col
                X_OBJADDVERTEX  sz,  sz,  sz, 1, 0, col
                X_OBJADDVERTEX  sz,  sz, -sz, 1, 1, col
                X_OBJNEWGROUP
    X_OBJEND
ENDFUNCTION

FUNCTION RenderBottom: num, sz, col
                sz=sz/2
X_OBJSTART num
                // Bottom Face
                X_OBJADDVERTEX  sz, -sz, -sz, 0, 1, col
                X_OBJADDVERTEX -sz, -sz, -sz, 1, 1, col
                X_OBJADDVERTEX  sz, -sz,  sz, 0, 0, col
                X_OBJADDVERTEX -sz, -sz,  sz, 1, 0, col
                X_OBJNEWGROUP
    X_OBJEND
ENDFUNCTION

FUNCTION RenderRight: num, sz, col
                sz=sz/2
X_OBJSTART num
                // Right face
                X_OBJADDVERTEX  sz,  sz, -sz, 1, 1, col
                X_OBJADDVERTEX  sz, -sz, -sz, 1, 0, col
                X_OBJADDVERTEX  sz,  sz,  sz, 0, 1, col
                X_OBJADDVERTEX  sz, -sz,  sz, 0, 0, col
                X_OBJNEWGROUP
    X_OBJEND
ENDFUNCTION

FUNCTION RenderLeft: num, sz, col
                sz=sz/2
X_OBJSTART num
                // Left Face
                X_OBJADDVERTEX -sz, -sz,  sz, 1, 0, col
                X_OBJADDVERTEX -sz, -sz, -sz, 0, 0, col
                X_OBJADDVERTEX -sz,  sz,  sz, 1, 1, col
                X_OBJADDVERTEX -sz,  sz, -sz, 0, 1, col
                X_OBJNEWGROUP
    X_OBJEND
ENDFUNCTION

See screenshot!
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-02
Looking great!  :good:

I see now you are drawing each visible face of each cube each frame? 
Wouldn't this cause major performance issues? 
Opposite of a chunking system where you are trying to minimize the number of objects rendered.
I think before you were creating the chunk model prior to the main game loop, and only displaying that one chunk object each frame.

And, I think you can simplify your Render() function down to this code:
Code: (glbasic) [Select]
FUNCTION Render:
X_MOVEMENT -CHUNKSIZE/2-CUBESIZE/2, -CHUNKSIZE/2-CUBESIZE/2, -CHUNKSIZE/2-CUBESIZE/2
X_PUSHMATRIX
FOR x = 1 TO CHUNKSIZE
FOR y = 1 TO CHUNKSIZE
FOR z = 1 TO CHUNKSIZE
IF self.cubes[x][y][z].bin = 0 THEN CONTINUE

ALIAS bin AS self.cubes[x][y][z].bin
X_MOVEMENT x, y, z

IF bAND(bin, CUBE_TOP)    > 0 THEN X_DRAWOBJ FACE_TOP, 0 // Draw TOP
IF bAND(bin, CUBE_BOTTOM) > 0 THEN X_DRAWOBJ FACE_BOTTOM, 0 // Draw BOTTOM
IF bAND(bin, CUBE_FRONT)  > 0 THEN X_DRAWOBJ FACE_FRONT, 0 // Draw FRONT
IF bAND(bin, CUBE_BACK)   > 0 THEN X_DRAWOBJ FACE_BACK, 0 // Draw BACK
IF bAND(bin, CUBE_RIGHT)  > 0 THEN X_DRAWOBJ FACE_RIGHT, 0 // Draw RIGHT
IF bAND(bin, CUBE_LEFT)   > 0 THEN X_DRAWOBJ FACE_LEFT, 0 // Draw LEFT
   
NEXT
NEXT
NEXT
X_POPMATRIX
ENDFUNCTION

But, I love it so far!  Great screenshot.
Title: Re: Voxel - Visibility
Post by: Schranz0r on 2013-Oct-02
hmm i thinks its OK if we use frustrum culling, but the big question here is: HOW! :D
 :S
Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-02
Uau! A Borg Assimilation Cube! Great!

Some faces look flipped, is that correct? (maybe my eyes are tricking me)
Title: Re: Voxel - Visibility
Post by: Schranz0r on 2013-Oct-02
the faces are right!!!111one :D
Title: Re: Voxel - Visibility
Post by: mentalthink on 2013-Oct-02
Joder!!! :noggin: this it's really interesting... I think if multiply the cubes a lot of times then you can do another Zbrush , I suppose the CPU will begin to launch flames but for try it  =D =D =D

Out of jokes, but this for make nice games with another style can be a good ppoint for start... a nice thing will be explode any cube in some cube more littles...

Thanks to both for the work... about the Fustrum I leave in someplace I don't know where is, how do all fustrum, chunks, water , physics... a lot of things... I try to search again...

Thanks for the hard work!!!  :booze: :booze:
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-04
I had fun with this for the past day or so (using my code as a base (but stole an idea or two from Schranz0r!). I found a few bugs in my original code postings - oops!).

Only exposed faces are added to the mesh, as expected.

I added an automatic chunking mechanism.
This means that a 16,16,16 map with a chunk size of 8,8,8 will generate 2x2x2 (eight) chunk meshes.
This reduced my 16x16x16 map generation from 10seconds to 1second!.
It seems the more triangles in a mesh, the longer it takes for GLBasic (or OpenGL) to generate and finalize the mesh.
Same total triangles, but as 1 mesh took 10+seconds, but as 8 different meshes, takes just over a second, total.


I included the project files as a zip, instead of posting each file (4 files) contents.
I tried commenting the main Voxel TYPE as best I could, so hopefully it is easy to follow and understand.

To Do:
- Perlin Noise Generator for MineCraft style landscapes
- UpdateVoxel(x,y,z, cubeType) -> To allow dynamic voxel editing.  Will regenerate the affected chunk(s)
- Interface to delete or add a new voxel to the map, and display the new map
- Texture Map: Use an external texture map tool to design the voxel textures, allow multiple voxel types (dirt, grass), auto map the textures to the model
Title: Re: Voxel - Visibility
Post by: Hark0 on 2013-Oct-05
Great work!

What is the limit of cube size?

Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-05
Gave a go, looks and moves about great. :good:
Title: Re: Voxel - Visibility
Post by: Ian Price on 2013-Oct-05
 :good:
Title: Re: Voxel - Visibility
Post by: Schranz0r on 2013-Oct-06
OK... complete rewrite of the code, rendering in realtime with OpenGL (gl.gbas)
Texturemapping added.
More improvements incomming!  :whip:

4x4x4_chunks.png is a screenshot of a "World" with 4x4x4 Chunks each chunk = 16x16x16


Source see attachment!
Anyone interested to make a Minecraftstyle game?!
Title: Re: Voxel - Visibility
Post by: Ian Price on 2013-Oct-07
While I'm no fan of Minecraft, I love to see things like this being done with GLB.

Keep up the excellent work chaps :)
Title: Re: Voxel - Visibility
Post by: Hark0 on 2013-Oct-07
I'm thinking in "voxatron"....  :P
Title: Re: Voxel - Visibility
Post by: Schranz0r on 2013-Oct-07
I'm thinking in "voxatron"....  :P

 :good:
Title: Re: Voxel - Visibility
Post by: mentalthink on 2013-Oct-07
Like Erico says this things are absolutely awesome... again I do the same question, this it's the same techique for do a Zbrush or a Voxel Modeler... I think in a Voxel Modeler you using millions at the same time, this it's possible in GLbasic, I think Using OpenGl, can't be too much problem?¿...
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-08
I was going to stop updating this, as I have no immediate use for it, but doing this is too much fun.

Here's my latest update, which includes a Perlin Noise generator, to create a MineCraft-ish landscape.
I use this to create a height map: anything below is dirt, anything above is air.
(MineCraft's algorithm is much more complex, with random caves, with minerals, etc).

It is much faster this way than completely random dirt/air cubes, as there are a lot less exposed faces.
I simply used a random shade of green for the top (grass), and a random brown for the dirt sides.

The main line that gets the perlin height is this:
Code: (glbasic) [Select]
//x#, y#, maxHeight#, frequency#, amplitude#, persistance#, octaves%
height = noise.GetRandomHeight(x,z, 1, 0.1, 1, 0.15, 3)

I don't know much about the specific perlin input values, but I found that frequency seems to make it spaced out more, and lower looks better.

Here's the site I derived this Perlin Noise TYPE from:
http://ploobs.com.br/?p=1742 (http://ploobs.com.br/?p=1742)

I attached a screeny and the source project.  Have fun.
Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-08
Gasp! this is incredible! :O
We really should put it to good use inside a game.
 
Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-08
Double dragon post!

I also noticed you have smooth shade going on even though it is all made of cubes.
Was that on purpose? Is is controllable?
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-08
The actual colours are random shades of green and brown, but what makes it look so different is that I turned on a spot light.  Just comment out the spot light line (in main loop of VoxelLand.gbas) to go back to solid colours (but doesn't look as good IMO). See first shot for an example.

Or, the 2nd shot has a spot light directly above the level, using this command:
Code: (glbasic) [Select]
X_SPOT_LT 1, RGB(255,255,255),  32, 160, 32, 32,0,32, 100

Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-08
That code is in japonese for me :P

What I meant has to do with X_AUTONORMALS, lights should not bother it.
Mode 1 for cubes and mode 2 for less then 90 degrees connected surfaces.

It all felt like it was rendered in mode 2 with the lights.

Now usually, on a 3d package, we can control that and set groups to smooth or not...and sometimes set a threshold angle, let´s say, smooths only below 59.9 degrees.
In older discussions, I remember while doing the objects inside GLB things are controllable, while importing OBJ or the likes, you can´t.

But that is only aesthetics, is it too hard to mess with the terrain? Let´s say can you explode things and delete cubes out of the map?
A 3d ballistic (monkey) game with 3d winds could be a good project to give this a try.

Excellent work Slydog!
Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-08
Ok, I turned on X_AUTONORMALS (Before generating the terrain), and see how it looks.
I also bumped the world to 128x128, and it still handles it no problem.

I suck at lighting (and modeling!), and always have a hard time getting a 3d world to look awesome.

It should be trivial to create an UpdateVoxel(x, y, z, newCubeType) function.
It would have to recalculate the surrounding chunk array in case they are affected, then regenerate this chunk and the surrounding.  Maybe this is next on my list.

You could create an ExplodeTerrain(x, y, z, radius) function to change all voxels in that radius range to air.  Then add an explosion animation if you want (perhaps using 1x1x1 voxel pixel models). Fun stuff!
Title: Re: Voxel - Visibility
Post by: bigsofty on 2013-Oct-08
Lookin good!  :good:
Title: Re: Voxel - Visibility
Post by: Ian Price on 2013-Oct-08
You know what, as awesome as this is, I can't help but think it would be even better as an updated version of the Geoff Crammond classic The Sentinel -





Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-08
New Update!

Added UpdateVoxel(x, y, z, newCubeType)
- Auto calculates new faces for voxel, plus updates any voxels touching this voxel
- Auto generates updated chunk belonging to this voxel, plus any chunks affected by neighbor face changes

Added an FPS display for testing (just made it up, hope it's semi-accurate).

Test project removes a random voxel each frame (the top most grass voxel for a random x,z location).
This still yields about 20FPS, after regenerating all affected chunks.
I think my FPS calculation is wrong though!

Restructured my code to allow for specific voxel updates without having to regenerate entire map.

The screenshot is the map eroded after about 10 seconds (at 1 voxel deleted per frame).

I think this is as far as I'm going to go with this (except bug fixes!).  I had my fun. 
I have a couple voxel world games ideas in my head - maybe will continue this in the future.
This should give anybody a quick start to use in their own game, if desired.  Or for learning.

Project zip at bottom.
Title: Re: Voxel - Visibility
Post by: WPShadow on 2013-Oct-08
Looks really great!

Now I want to play GL - Craft ^^
Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-09
AWESOME! :good:

It yells 17fps around here but I´m sure everything is moving at 60fps.

What is really funky, I kept looking at it for quite a while and when I starred away real life things were twisting the opposite direction :D :D
Seriously, I got quite a kick from that visual effect.

I can´t understand 3d coding as of yet and most likely nothing from the code :( I will get there someday!

 
Title: Re: Voxel - Visibility
Post by: mentalthink on 2013-Oct-09
The Master Coders.. my fuc.. (love sorry)  =D =D , this it's really interesting to see very vomplex, at least for me... running in GLBasic , when I boutght I never thinked I see this kind of projects... Really Really fun and interesting...

Thanks for sharing the code. the part for hidde faces in models can be very usefull for me... Thanks. :booze: :booze:
Title: Re: Voxel - Visibility
Post by: Hark0 on 2013-Oct-09
Wow!  :O

amazing!
Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-09
Hey Slydog...you are not retiring from this project?
Such marvelous stuff, maybe an user inteface, walking around, anything!

It just looks too good to be truth (but it is, I tried it :))
I bet standard bit old computers can handle 9x that easily? ( I get that figure from the performance here)

Could something gamewise be done about it? Even a 3d balistick explosive pong with lava....heck I´d wish I knew my ways around this up-level of coding!
Title: Re: Voxel - Visibility
Post by: dreamerman on 2013-Oct-09
Very good piece of code :good: Really clear code, easy to read..
The biggest problem is that X_ object generation is so slow, but it's simpler to draw and quite fast.

Note that fps drawing function is wrong :p just change
Code: (glbasic) [Select]
fps = timer / frames to
Code: (glbasic) [Select]
fps = framesSo if you had 20fps earlier truely it was 50fps..

Even more it's working on Android, just add icon.png to folder and compile.. app needed more than 5 minutes to load :D but my chinese single core 1Ghz tablet with Mali400 on bigger map (-> voxelMap.Generate(128, 12, 128,  16, 12, 16)) has ~33fps, of course only small portion of cubes are visible.. Needed to comment lines that randomly delete chunks.

Some time ago I was also working on cube style engine, but mostly to see what rendering method would be faster, each have some pro and cons, and it would be great if you would add vertices and visible sides counting to your code. My project is a total mess, and when I will have some free time to rewrite it I will post it on forum.
Title: Re: Voxel - Visibility
Post by: kanonet on 2013-Oct-09
Very nice code here!
Btw. Slydog your FPS code must be wrong. Fraps says its 60 FPS, your counter says its 17 FPS.
This code is working correctly, just replace your function:
Code: (glbasic) [Select]
FUNCTION DisplayFPS: x%, y%
STATIC frames#, fps#
STATIC time1#, time2#
time1 = GETTIMERALL()
INC frames, 1000
IF time1 > time2
fps = frames/(time1-time2+500)
time2 = time1+500
frames = 0
ENDIF

PRINT "FPS: " + FORMAT$(3, 0, fps), x, y
ENDFUNCTION

Btw. is there a reason why you didnt use GENX_OBJ(), but created your own?
All in all its nice code, but it has much room to get bigger: currently only using color for cube type (texture is a bit limited, since uv are always set to same value for all sides), add automatic handling for chunks in chunks in chunks in... and it would be better (way faster) to render in native Opengl, not GLBasic, but its the best that we have seen so far and a really good base for further development (and considering that it was done such a short time!), I hope you will go on with this project.

EDIT: dreamerman was faster than me :/
Title: Re: Voxel - Visibility
Post by: Kitty Hello on 2013-Oct-09
V11 can disable automatic normal calculation. You can specify them manually then (see online help). That might give some speed boost when creating x_objs. Amazing project!

Somewhere I did something like this but with rounded corners... might be a cool enhancement.

Sent from my GT-N7100 using Tapatalk 4

Title: Re: Voxel - Visibility
Post by: Slydog on 2013-Oct-09
Thanks for the kind words.  Dang, now I have to take this further! 

I fixed the FPS display.  I was showing the frame duration I suppose.  Thanks for the suggested fixes, but I found a very simple algorithm at StackExchange, and converted it to GLBasic (it seems to work):
Code: (glbasic) [Select]
FUNCTION DisplayFPS: x%, y%
STATIC averageFrameDuration# = 0
averageFrameDuration = (averageFrameDuration * 0.9) + (GETTIMER() * 0.1)
PRINT "FPS: " + FORMAT$(3, 0, 1000.0 / averageFrameDuration), x, y
ENDFUNCTION

@kanonet: ha, ya, I rechecked the code to see what you meant about GENX_OBJ().  First, I didn't even remember there was such a command (it doesn't begin with an 'X_'!).  But I may remember when I first created the mesh TYPE (years ago), that it doesn't actually use the returned value from GENX_OBJ() until you add some geometry to the model.  So if I call that command 10 times at the program start, all meshes would all get the same id.  My fix was my 'smart' way of getting around that.  But I took another look, and simply inserted the check (if id<0) in the Generate() function, and that seems to work awesome.  I deleted my 'smart' function and now I'm using GENX_OBJ().

@Kitty: Hmm, interesting idea, didn't even know calculating normals by hand was an option.  Will have to update to use that.  Does a normal have to be normalized (ha, sounds weird)?  Is it a simple vector (0,0,0 origin) that points away from the quad face?  And relative too I hope, so all north facing walls can all use the exact same normal for all four corner vertices?  I could precalculate each face normal during initialization, and use those for the mesh building later.  Will try this soon.  Does 'X_AUTONORMALS 0' speed up model creation since it doesn't need to auto-calculate normals?  I find it still a little slow using '0', but of course the normals are way off.

@dreamerman: Cool, you got this working on Android?

@erico (and others thinking 3d programming is difficult):  That's why I created the TMesh TYPE (and TVertice, TQuad).  It handles all the low level details for me (like above, I didn't even remember the GENX_OBJ() command since I seldom venture into the mesh code).  You just have to keep it straight in your head (or paper) the x, y, and z coordinates of the vertices you need, create some quads (each containing four vertices), and then add those quads to your model (then finally call the .Generate() command to finalize the process and create an actual 3d model).  All done in steps to keep your head sane.  This project is probably a good starting point for dynamic 3d model generation (especially if you use my TYPEs).

I think I will at least do the texture atlas portion next.  I will be using TexturePacker to pack my textures into a sprite sheet (there is a free version, but the full version is only like $25).  I'll need to create code (I'll be using bigtunacan's code as a starting point, thanks) to read the sprite sheet definition file, and TYPEs to handle extracting individual sprites/textures from the sheet.  Then use this to allow you to define your voxel textures using individual files for each face, and reference them by filename in GLBasic (such as 'cube_grass_top', 'cube_dirt_left' or something meaningful).  I've done this in Unity so porting the code shouldn't be difficult.

I attached the updated project with the fps fix, and GENX_OBJ() fix.
Title: Re: Voxel - Visibility
Post by: erico on 2013-Oct-09
Nice, Slydog! I will check the newer version later today.
I´m sure to book mark this page and project for when I get in 3d on GLB. :good:

You mentioned textures, so here I wonder...Since it is all cubes, there could be a fake occlusion shadow effect/shader going on by using the bumbmap channel.
That would mean a bump map atlas that gets attached to quads depending on the neighbor blocks.

It could be done blending a black and white degradee to the texture, but here I think using the bumpmap might be easier and faster, Mentalthink mentioned something similar to that a long time ago.

Just throwing some ideas on the pot. ;)
Title: Re: Voxel - Visibility
Post by: kanonet on 2013-Oct-10
Nice looking FPS code, but I prefer GETTIMERALL over GETTIMER besides this, my function should be faster in execution speed.
You are right, GENX_OBJ can not get used in row without creating a mesh in between calls, but thats easy to work around and its still saver to use this instead manual choosing a slot. So got decision to use it!

Normals need to be normalized (ok I dont know if X_OBJADDVERTEX_NORMAL does it automatically), but since in our case all normals are same direction like the world axes, this is easy to achieve, normals simply will be things like (0,1,0) etc which is normalized. Of cause all normals will be the same for all faces that look in the same direction, so we only need 6 different normals.
BTW normals need to be normalized cause for some strange reason GLB does not use glEnable(GL_NORMALIZE), which it should, cause if you scale your mesh ATM your normals get scaled too, so they are not normalized anymore, so you get wrong lighting. I would consider this a bug and suggested to fix it long time ago, when I published my lightfixes, but nothing happened yet. But this does not matter for this project here and it can easily get fixed in your other projects by one single native opengl call.

I dont think your mesh type is a really help for someone new to 3D, for me it looks like it overcomplicates things - but maybe thats just cause I already know how to do stuff with normal GLB commands and are used to them. BTW for a 3D newbie I would suggest to ignore generating meshs, but simply load .ddd objects, Should be an easier start.

BTW there is a bug in your last version: you use chunksize (4,12,4); since your world hight is 12 too, you only have one chunk in height. If you now change chunksize to (4,4,4), so you have 3 chunks in height, your mesh gets messed up. This problem did not happen in your last version (I just downloaded it again to confirm this!), so I think it must be caused by some of your recent changes.
BTW if your (worldsize/chunksize) is not an even number, a bit part of the world gets not rendered - I guess thats intended, I just wanted to mention it in case its not. I would prefer it, if in this case the world gets bigger to fill a full chunk and the new parts of the chunk get filled with 'air blocks'. This could especially be needed if you introduce chunks in chunks in chunks etc. (I think this later feature is necessary, maybe I will add it on one of the next weekends).
Title: Re: Voxel - Visibility
Post by: WPShadow on 2013-Oct-10
hey,

I think all the time about the following concept of the usage of voxel:

Shouldn't it be possible to build objects with the voxel engine? For example a house. With walls and something else. On the outside is the wall.

Now what would happen if you shoot a bullet on the wall? several voxels would be destroyed --> so what will happen that moment to the invisible voxels behind them?


Title: Re: Voxel - Visibility
Post by: Slydog on 2020-Jul-20
Wow, this is almost seven years old!
JohnnyB noticed my zips are corrupted.
I can confirm, it downloads but the files are corrupted when unzipped.

I can't find the original files on my Dropbox anymore.
Does anyone else have a copy kicking around they can re-upload?
(Ha, I know there's only a slight chance, but I thought I would ask!)

Although, the thought of dusting off my copy of GLBasic and redoing this does sound intriguing . . .  :P
Title: Re: Voxel - Visibility
Post by: dreamerman on 2020-Jul-20
As it was in my area of interest I kept it in my archive, not sure if that's latest version that You have uploaded but here it is ;)
Something could be modified, but it should be easy to track and change after digging in all those posts.
Title: Re: Voxel - Visibility
Post by: erico on 2020-Jul-21
Yep, I noticed last forum "acting" got the files and pictures messed up. I wonder if Gernot can do something about that but it has been a while so it is probably not possible.
This is a wonderful project, up to this day I get people asking about voxels with GLBasic.

Get back at it Slydog!

Title: Re: Voxel - Visibility
Post by: JohnnyB on 2020-Jul-23
Great stuff. Now it would be good to be able to wrap individual textures around the meshes. Is this wise, when it comes to performance?
Title: Re: Voxel - Visibility
Post by: dreamerman on 2020-Jul-26
No, that isn't advised, generally best solution is to use as low texture count as possible, just by packing all separate files into atlas sheets, same goes for 2d and such 3d graphic. Consider that You would have 10 different block types, so during rendering (depending on block position and so on) current texture could be changed hundrets of times, that's not good. It's different for 3d racing game where is one texture for world/track and other for car, as it isn't changed so often while rendering. There are also texture arrays, but for that You would need to use inline OpenGL directly from what I remember. So simplest solution is just to put as many textures/sprites into one large texture - atlas.

Not sure what are limits to texture sizes now but 3Dfx cards had 256x256 limit, Riva TNT2/first Geforces had 2048x2048, iPhone 3g had 1024x1024 limit, newer phones have higher at it should be at least 2048x2048, quick look at it looks that Unity and Android OS support's max 4096x4096 so this should be the limit. If You would need more, then texture arrays would be solution, but this is already huge. For some minecraft style project You can use 64x64 textures for cubes in one atlas and have separate atlas for UI stuff and so on.
Title: Re: Voxel - Visibility
Post by: erico on 2020-Jul-26
Sure shot, a single big texture within the atlas approach should be the fastest.
Title: Re: Voxel - Visibility
Post by: Schranz0r on 2020-Jul-27
Hmmm, would be nice to do it the modern OpenGL way with shaders...  ;)
Maybe i'll give it a shot this week!

And a textureatlas should be the fastes way to do.
Title: Re: Voxel - Visibility
Post by: Slydog on 2020-Jul-27
The '_mesh.gbas' allows for texture maps using the 'QuadAddV4()' function.
Code: (glbasic) [Select]
FUNCTION QuadAddV4%: v1 AS TVertice, v2 AS TVertice, v3 AS TVertice, v4 AS TVertice, uv1 AS TUv, uv2 AS TUv
You pass the texture coordinates using the uv1 and uv2 parameters when adding a new Quad to a mesh.
The TYPE 'TUv' expects two floats representing the x,y position in the texture, normalized from 0.0 to 1.0.
uv1 is the top, left corner, and uv2 is the bottom, right corner in the texture. (If I remember correctly, it may be bottom,left to top,right or something).

You would modify the 'Mesh_QuadAdd()' function from '_voxel.gbas' to detect the face type, and include that face's uv coordinates in the 'quad_offset' variable.
Code: (glbasic) [Select]
quad_offset.SetUv(uv1, uv2)(You actually don't need to use the above 'QuadAddV4()' function in this case.)