My (different ?) approach on Voxels

Hi Guys,

First of all I want to say some words about myself and why I’m here. I’m working for some years with java and would say I’m an experienced Java programmer by now, sure there is always room for improvement :slight_smile: just recently I started to look into 3d programming with a small hobby project,.The goal is to create a world editor for a Voxel game called blockscape which is written in C and has an open file format.
I started to write direct openGL code with lwjgl and learned alot about the openGL basics and maths some nice results for the basics like viewing one chunk (32x32x32) or to view a worldmap of all chunks.

As I started to scale up the hassle with alot of of common issues began with alot of common things and because I don’t want to program an engine from scrath I looked around and I found jMonkey :smiley:

So I quickly migrated to jMmonkey and must say I love it.

Ok enough talk back to the topic about voxels :slight_smile:

I will try to show my approach (however I am still at an early stage):

I am using a a tree Structure with 27 Nodes resembling the 3D space of the Cube only the bottom level has the actual chunks in it which I loaded from the game file.
This way my structure is able to scale into infinity if I unload branches into a DB or on disk cause the node can easily be identified.

Here a a shot of some rendered chunks, you can see the boarders of each chunk with the green lines

And this is an earlier version with a bigger scale of the Tree structure and a Level Of Detail that renders a chunk as Block if it has content

As you can see I’m currently have trouble with the textures :slight_smile:

Which leads to the next Level of detail, rendering the actual blocks.

At the moment I create 8 Vertices for each block without any texture coordinates and write them directly into a custom Mesh.
In the process of writing the vertices to the mesh my custom Mesh checks if the vertex already exists if so it shifts the indices and skips the vertex.
This way I currently get 1 Mesh for each Chunk. Which also could be adjusted according to a LOD system like hollow solid blocks and stuff like that, I could also compress the mesh more if I delete the “vertices in the middle”.

Now the Problem of course is that the whole Mesh only has 1 material and I even can’t work with the texture atlas which I did in my old program.
Also I currently don’t see a solution of how I can achieve correct texture Coords on the mesh (thats why the textures all are so bugy)

If I use 24 vertices per Voxel I get correct texCoords, but this also means I have a 3 times bigger buffer + the size of tex Coords which I want to omit.

Thats why I currently try to texture the world using noise funclions inside the fragment shader… which is realy difficult.
Another approach could be that I create a seperate “Texture Coord Mesh” or use some kind of 3dTextureMap.

Not sure if anyone has done sth like this before but well I like to experiment :slight_smile:

So what is your opinion should I stick to my plan ? does it sound reasonable ? or do you see some fatal errors ?

I even saw some posts about Voxel engine Libraries like SimpleBloxelWorld and BlockZ would you recommend them for my use case ?
I am a little afraid that they don’t scale that well (Blockscape uses a pretty high Block resolution) and I could not change stuff on the “engine”

Good to see you seem to get along with the engine :slight_smile: The solution for your problem probably is a texture atlas and texture coordinates, if you have trouble with that you should work on that I guess :wink: You can’t avoid the additional data as even if you use a selfmade shader with multiple textures you will have to get the information about what to put where into the GPU somehow.

a) box worlds are not made of cubes. They are made of quads between solid and empty space.

b) you already need 4 vertexes per face anyway for normals. A cube would need 24 vertexes just because of that. However, on average you save about 75% of your vertexes by not drawing the faces inside solid matter.

If you search the forum you can find a few projects that have already been down these paths.

Well I thought so…
But still not give up experimenting playing around with triangle fans now cause you only see 3 faces max of one block at a time.

Thanks for your feedback I will keep you updated

@Heiko said: Well I thought so.... But still not give up experimenting playing around with triangle fans now cause you only see 3 faces max of one block at a time.

Thanks for your feedback I will keep you updated

In a block world, for most of the blocks you see no faces at all. The large majority of the rest of the blocks, you only see one face.

I’m not exactly sure what you are saying with the 3 faces thing but it sounds 1000x more complicated than just building the proper mesh in the first place.

@pspeed said: In a block world, for most of the blocks you see no faces at all. The large majority of the rest of the blocks, you only see one face.

I’m not exactly sure what you are saying with the 3 faces thing but it sounds 1000x more complicated than just building the proper mesh in the first place.

Nah I think in the same direction. But I think as I am writing a world editor and not a game my requirements are a little different than a regular game.
Which means that on highest LOD I want to also see the Blocks (as a mesh of all blocks with the same Material) inside a Rock and not only the surface.
I also don’t necessarily need lighting.

My routine for surface only mesh generation which I am testing at the moment is the following:
For each Block

  1. test if there are directly adjacent blocks, if inside other blocks skip block
  2. find the outside corner
  3. create a TriangleFan centered on that corner and draw the faces of the block which are not occupied

I know Im unconventional :slight_smile:

What do you think is a better practice should I add the buffer data directly to a mesh with Mesh.setBuffer(VertexBuffer.Type.Position …

or should I use SimpleBatchNode and GeometryBatchFactory.optimize ?

I still don’t get that Batch Factory. Is there a documentation somewhere ? only found some samples of how to use it but not when it is best to use it.
Cause I experienced that it is faster to extract/create the buffers directly instead of creating e.g. a BoxGeometry attaching it to the SimpleBatchNode and ( when finished adding all geometry) calling GeometryBatchFactory.optimize. I guess the BoxGeometry creation eats the performance.

I think you should use buffers instead of attaching Box to a Node and optimizing it, since the latter would produce many unneeded faces.
For building chunks, here’s another way (if not mentioned already):
For each Block
____For each Face (6 of them: top, bottom, left, right, front, back)
________If the face faces air (empty block), create the face (square).
Hopefully this is on topic, since I’m not fully sure what’s being talked about.

@seann999 said: I think you should use buffers instead of attaching Box to a Node and optimizing it, since the latter would produce many unneeded faces. For building chunks, here's another way (if not mentioned already): For each Block ____For each Face (6 of them: top, bottom, left, right, front, back) ________If the face faces air (empty block), create the face (square). Hopefully this is on topic, since I'm not fully sure what's being talked about.

Yes this is absolutly on topic. Drawing the faces was another option which I have but everyone does it that way :smiley:
And I am trying out different approaches before I fallback to the “common” way.

My trinagle fan code currently has one flaw. Once I combined the blocks into one Mesh and try to draw triangle fans.
The created Mesh uses the 1. Vertex from the first block as origin for every Block (thats how triangle fans work)
I need to shift the Data somehow after each Fan …

If this does not work I will fall back and draw triangle strips for the surface faces.
And if that fails I draw regular faces :slight_smile:

Thanks for your input

Hi again.

I had some time to play around and have found a solution which Im happy with at the moment.

I process the voxel world (which i loaded from a file of the original game) per chunk 32x32x32 and not per block.
For each chunk I scan the including voxels for visible faces and create a “Surface Triangle strip” for the complete chunk face.
Resulting into 6 triangle strip meshes which I batch together. For different materials I use custom uv texture coordinates in my texture atlas (not the jme one)

here is a shot of my current scene showing around 30 chunks sized 32x32x32 (triangle count is doubled because I have backface culling of at the moment)

As my input data grows and I only have 500mb free ram at the moment (16GB is already ordered :D) I will next work on implementing a java object serialization with the KRYO (http://code.google.com/p/kryo/) framework. As I basicaly only want a simple Key Value Map I figured out that this is probably better then using Hypersql DB.

And I also realized that I am writing in the wrong Forum :smiley: this is engine development discussion not regular development discussion.

I will probably create a new Thread in the user code forums.

a) SpiderMonkey (jme-networking) already has a serializer that is similar to other network-based serializers… though I haven’t looked at KRYO’s serialization. You could also just use Java’s serialization which is probably fine in this case. If you are using it to store things on disk then you probably want something more robust than transient protocols like network serializers.

b) hsqldb is super good at things like key/value maps and will allow you to scale beyond what can fit in memory… but I don’t know what your keys and values are.

@pspeed said: a) SpiderMonkey (jme-networking) already has a serializer that is similar to other network-based serializers... though I haven't looked at KRYO's serialization. You could also just use Java's serialization which is probably fine in this case. If you are using it to store things on disk then you probably want something more robust than transient protocols like network serializers.

b) hsqldb is super good at things like key/value maps and will allow you to scale beyond what can fit in memory… but I don’t know what your keys and values are.

I was thinking alot about using a DB or not why I settled for files is that I want to make the complete state (not only 3d nodes from jme also data objects) of the application savable. And this could easily be done with Kryo.

And why Kryo and not “regular” serialization is performance and file size. Kryo saves in a very efficient way and is easier to use for my specific case, here are some benchmarks:

I am already working with binary formats from the core game blockscape from where I import the binary file into my Editor.
Here is another good articel on binary file IO and serialization in Java

@Heiko said: I was thinking alot about using a DB or not why I settled for files is that I want to make the complete state (not only 3d nodes from jme also data objects) of the application savable. And this could easily be done with Kryo.

And why Kryo and not “regular” serialization is performance and file size. Kryo saves in a very efficient way and is easier to use for my specific case, here are some benchmarks:

I am already working with binary formats from the core game blockscape from where I import the binary file into my Editor.
Here is another good articel on binary file IO and serialization in Java
Mechanical Sympathy: Native C/C++ Like Performance For Java Object Serialisation

Kryo must use something similar to the network serialization already built into JME (http://hub.jmonkeyengine.org/javadoc/com/jme3/network/serializing/Serializer.html). The reduced size comes at a cost: the format totally breaks with even the smallest changes to the stored classes. Java’s serialization at least accounts for this and the extra overhead is minimal… and you can always zip it when sending it to disk. GZIP completely eats up all of the redundant strings in the headers and stuff.

For custom data formats, it’s better to roll your own I think and keep a version in the file so that you can adapt. Maybe Kryo does that… but if so then it’s kind wasting bandwidth for a network API.

Sorry forgot to mention that I already have a custom binary dataformat from the main game (Blockscape written in C++) for which I build the Editor.
Kryo worked realy well without any further work I serialized everything and was able to load 1000 Chunks @ 580MB Data it took kryo sth around 2000ms reeealy fast.
If I understand it correctly it is not using regular FileIO it uses sth like direct memory mapping.

Maybe I will test the same job with the other Serializer to get a Benchmark if I have the time.

Here is a screenshot of a Map a User of the Community has build:


Blockscape uses a very high Block resolution (1 MC block has 16x16 Blockscape Blocks)

And this is how it actualy looks in the Maingame:

Next I will work on a Background loading mechanism using:
https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:multithreading

and @Forum Moderator: could you maybe move this thread to the User Code & Projects Forum
Thanks

1 Like

Nice looking little town :slight_smile: