Tweaking Chunk Storage

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Ouch, sorry to hear about that coffee incident, Panserbjoern :(

I've got a couple drives laying around here myself that are damaged, now archived in the "by hanging on to this I hope one day they'll magically be recoverable again for no reason" box
 

dei

Java Priest
Contributor
Design
Art
What happens when you connect it through a usb-adapter when the os is already running, (dmesg)? With most usb-controllers the system shouldn't crash, worst thing that can happen is that the usb-connector is fried. I never had a drive gone unreadable when spilling something over my laptop, they most have an extra metal coating around electronics, so they are nearly waterproof. Putting it into the freezer for some hours will probably not be that rewarding like with rotational HDDs but when nothing else helps, why not try it with SSDs too? (make sure you pack it in an airtight sack to avoid more damage from molten ice)

As Laptop I can recommend you the Asus Zenbook ux31, very portable lightweight, and faaast boot-times (around 10 seconds with my ubuntu), although you 'only' have a 15'' Monitor. But having to carry only a thing as big as a paper notebook and being able to connect a big screen the missing 2'' are negligible. Else especially for ubuntu I would recommend you a HP, always had good drivers and acpi-support with these, even with a touchscreen display.
 

Panserbjoern

Member
Contributor
Architecture
dei, i have tried using my usb adapter from an icybox. It does't recognize the drive and just keeps blinking ferociously... Dmesg shoes nothing.

Thanks for your recommendations, though, i will give it a look.
 

manu3d

Active Member
Contributor
Architecture
Hi everybody. Pardon the intrusion in a long dormant thread.

I'm assuming the Tera[Dense|Sparse]Arrays developed by Panserbjoern are in place and working well. What's the current size of a chunk these days then?

Now, as I went through the discussion I've been wondering a few things.

1) did you guys have a look at OpenVDB, of which you can find a quick PDF presentation here? To summarize it is a voxel-related data structure that is built to be customized depending on the needs of the specific application. It uses a tree of chunks which can be set to be more or less branching, resulting in different performance profiles. It is also nicely generic as it deals only with "interesting vs non-interesting" voxels, the definition of "interesting" left to the application. Finally it has some built-in compression.

2) even if OpenVDB is not quite interesting as a whole, I've been wondering if the underlying idea of having a hierarchy of (statically sized) "superchunks"->chunks->voxels could be useful. I.e. in the discussion about height limit, some concern was raised about having to look all the way up to 0,10000,0 to see if something was blocking the sun. Well, the algorithm wouldn't have to go through all the 10000 blocks if it can easily find that most "superchunks" are air. I.e. assuming a 32 x 64 x 32 chunk and a 64 x 16 x 64 superchunk, one needs to go through 10 superchunks to figure out that all 10000 blocks are air.

3) it seems to me that one of the most limiting factor to the whole discussion is the propagation of (sun?)light algorithm. Is there a wiki page that explains in layman terms how it currently works? What does it currently achieve? Am I correct in saying it fakes vertically cast shadows and let both shadows and light "bleed" into near blocks, sort of creating a computationally inexpensive radiosity? Wouldn't it make more sense to completely delegate sunlight calculations to the client while the server only stores light information information due to dynamically placed point sources? (I'm assuming it -doesn't- make sense, I'm just wondering why).
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Hey manu3d :)

Good timing - Immortius recently started work on vertically stacked chunks, so this area is in a bit of flux right now, including in particular the sunlight algorithm. He can probably provide the best details and there's code in a branch on GitHub

Haven't heard of OpenVDB before, but maybe one of our specialists have. Certainly looks like something that might be of interest to them, like begla if he wasn't knee-deep in Lords of the Fallen dev atm :D
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
As for the sunlight on the client only, getting to know if sunlight hits the block might be useful for some mods. For example MC uses it to check if plants can grow.
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
On OpenVDB - it isn't a java project so it would require a fair bit of work to use, plus depending on the usage pattern will likely lose a lot of efficiency in the java<->native communication. It also deals with a different sort of voxel data from a brief look at it (we're voxel only in so far as having a 3D grid of values, not in the divisible sense), although that doesn't mean it wouldn't be useful. But unless someone is willing to spend the hard yards either porting or creating a native wrapper for it, essentially irrelevant.

Anyhow, at the moment I'm doing chunk size optimization, vertical chunking and reworking the sunlight algorithm - plus rework to world generation. It looks like the most optimal chunk size will be 32 x 64 x 32 - this achieves a decent balance between rendering cost and chunk load cost. Bigger chunks are better for rendering, but cost more to load (primarily due to entity system integration costs and anything else that has to be done on the main thread - will keep reviewing this).

Our lighting algorithms are all cellular automata based (propagation through adjacent cells) and designed to limit the scope of maximum propagation from a change at a single block to a chunk and its immediately surrounding chunks. Like Marcin says, it is assumed there will be gameplay reasons to have lighting data available, so it is created and maintained on both server and each client in a net game. Lighting data is not serialized, nor sent over the wire, since it is derivable from block state assuming all adjacent chunks are loaded. So to that extent it is delegated to the client, just also done on the server as well.

The sunlight algorithm I'm adding "regenerates" over unblocked distance, so sunlight effectively resets over the distance of a chunk if not re-blocked. This negates the question of whether sunlight is blocked over a vast distance, which is sensible because it allows for pseudo-shadow attenuation - it should work nicely for floating islands. It is problematic if you dig a vast vertical shaft though, so will need to be reinforced with world generation data indicating when sunlight should regenerate.

This is ignoring the sunlight shadow casting system, which is purely graphical and based on rendering a depth buffer. It is also ignoring non-block-based lights (so thrown torches), which are also purely graphical at the moment. These could be incorporated into the physics system to allow light levels at each location to be queried.
 

manu3d

Active Member
Contributor
Architecture
On OpenVDB: mostly I was wondering if the way it stores data would be useful, i.e. the hierarchical nature of the storage. How to manage it (porting/wrapping/entirely new API) would be a secondary decision. Are you saying its usefulness can't be decided unless somebody implements it and benchmarks it? Is it not possible to make an educated guess on, say, the usefulness/performance of having chunks and at least one layer of superchunks? Superchunks might even be useful as low-resolution data for distant landscape rendering.

Thank you for the overview of the various issues with chunk size and light. Indeed I had forgotten about the gameplay side of lighting. Slightly OT: is the lighting level stored in each block -not- affected by the time of the day? Is the time of the day only considered by the various systems as necessary, and used to calculate a multiplier on the light level stored in the block?
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
On OpenVDB: mostly I was wondering if the way it stores data would be useful, i.e. the hierarchical nature of the storage. How to manage it (porting/wrapping/entirely new API) would be a secondary decision. Are you saying its usefulness can't be decided unless somebody implements it and benchmarks it? Is it not possible to make an educated guess on, say, the usefulness/performance of having chunks and at least one layer of superchunks? Superchunks might even be useful as low-resolution data for distant landscape rendering.
I'm saying it isn't useful as long as it cannot be used. :p My previous experience with octrees is that adding hierarchy adds unacceptable cost to data access and update, so I would definitely want to see benchmarks. A lot of processes, such as chunk mesh generation, heavily access block locations so any increased cost to access can really reduce performance. There is a reasonable risk that any new algorithm will prove unsuitable, so it isn't something I'm likely to pursue in the presence of features to be worked on which are certain to be useful. If you are willing to spend some time exploring this it would be nice though. :)

On superchunks specifically, you will need to explain what you have in mind - what information they provide, where that information come from and how it is updated? If it is something like the occurrence count of each type of block in each chunk, I can see some use, but not sure how you would populate without generating every chunk in the superchunk. There may be overlap with the world metadata approach I'm going to start working on shortly, although that is less in terms of chunks and more an abstract representation of the world. It will be used primarily for generation of chunks, but could also be used for maps and distant rendering - although the question would be how to update it in response to changes. Because the metadata would be the source for generation, it will contain all the biome/surface height/feature information, but no information relating to blocks as such.

Thank you for the overview of the various issues with chunk size and light. Indeed I had forgotten about the gameplay side of lighting. Slightly OT: is the lighting level stored in each block -not- affected by the time of the day? Is the time of the day only considered by the various systems as necessary, and used to calculate a multiplier on the light level stored in the block?
We store two light values per block: "sunlight" and "light". When rendering, light is constant but sunlight is scaled (and colored) by time of day. But the stored values are not altered for time.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
When I think "super chunk" it makes me think of large servers and segregating distant data. Like two players on different continents - seems like in that case they wouldn't have to share the vast majority of entity data. Still some global stuff like chat, but at that scale you could probably start using multiple server nodes for performance.

That's more of a stray theoretical thought out loud than anything we need anytime soon though
 

manu3d

Active Member
Contributor
Architecture
Thank you Immortius for your reply. I completely understand the need to implement and benchmark any new way of doing things before proper conclusions can be drawn. Given how deep into hardcore optimization this topic is I don't think I'll be able to help in any reasonably short time.

Concerning superchunks/hierarchical storage: I hope I can write a specific post about it over the next few days. I must delve deeper into OpenVDB's workings for it. OpenVDB's way of doing things certainly seems to offer memory savings (i.e. compressing homogeneous volumes such as air-only, water-only, stone-only). They might also help with high or even infinitely high worlds by helping find which chunk needs to be rendered and ignoring or flagging up homogeneous volumes for quicker handling. Octree tend to be used as dynamic structures and I can imagine that's a big performance impact. OpenVDB's structures, in terms of tree depth and size of the nodes are configured at compile time and this should make them a little more performance-friendly. Unfortunately, as i was reading on OpenVDB's a bit more in-depth, I realised how in a sense Terasology is pretty much one of the worst case scenarios for any kind of voxel-oriented storage: it is dense/heterogeneous from ground-level down and sparse/uniform from ground level up. In this context I suspect that some kind of solution keeping in full consideration these two aspects of its particular reality will be needed to best handle both ends of the spectrum and the relatively narrow-inbetween. If this has to be a layer-oriented solution (i.e. dense storage below level 128 and sparse storage above) or a more hierarchical one such as the OpenVDB approach, I do not know.

Cervator: the kind of separate continents you mention to me are really about having multi-world capability! With it one can do multiple dimensions, multiple continents and multiple planets!
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
That article is quite interesting, Josharias . I'm intending to change the storage/network format of chunks to run length encoded as part of my current work anyway, and the interval tree approach sounds very interesting (the top level virtualized hash-map is already in place).

manu3d On multidimension support, I have thoughts on this and it is in my todo list (like a lot of things), but haven't started on it at this point. Essentially it is about making a number of systems more generic and less singleton-esque - so rather than having a single world with a its generators, having multiple worlds with generators each, and driving this through the entity system. Each world would have an entity with components configuring generation and other settings, and LocationComponent would incorporate a reference to the world the entity is located in. Probably more important to get the generator system improved first though.
 

manu3d

Active Member
Contributor
Architecture
Just went through VDB: High-Resolution Sparse Volumes with Dynamic Topology (22 pages) to best understand the inner workings of OpenVDB and write a summary for posterity.

For the interested readers, the sections relevant to our discussion are:

1.2: Contributions and characteristics of VDB (half page)
2: The VDB data structure (6 pages)
3: VDB access algorithms (4 pages)
B: (Appendix) Multithreading and Vectorization (half page)

VDB (OpenVDB is an open-source implementation) is a storage solution characterized, among other things, by a tree of nodes whose depth and branching factors are defined a compile time. I.e. the default tree (seen in benchmarks as best compromise between various efficiency parameters) has a Root Node which contains a (small) list/hashmap of children nodes called Internal Nodes, each containing in turn 32^3 children nodes (also called Internal Nodes), each containing a further 16^3 children called Leaf Nodes, each containing 8^3 voxels. As such, the tree has five levels (from root to voxels) and a single Internal Node immediate child of the root node is a cube (32x16x8)=4096 voxels per side (or 68 Billion voxels). The default tree configuration provides cubic nodes but custom configurations allow for individually chosen dimensions along the three axis, the only restriction being they must be powers of 2. This restriction allows for much of the bitwise magic detailed in the paper, allowing for example to pinpoint the memory offset of node (at any level in the tree) containing a set of global x,y,z coordinates by using only three bitwise & operations, one per axis.

To recap the tree structure: Root Node -> N Internal Nodes -> 32^3 Internal nodes -> 16^3 Leaf Nodes -> 8^3 voxels. The author, by the way, finds a notable analogy between the empirically obtained (32/16/8)^3 sizes (best for balanced performance) with the relative sizes of modern CPU's L3/L2/L1 caches. He hints there might be a sweet performance spot with those numbers given current hardware.

An interesting characteristic of VDB is the concept of Tile. A tile is a child node full of identical voxels. I.e. if a Leaf Node (say, 8x8x8 voxels) is full of identical voxel it is not instantiated, or it is pruned as soon as it becomes homogeneous or at another convenient time. A tile object is used in its place, containing a single reference to the voxel. As tiles can be children of any Internal Node in the tree, a tile of the default tree configuration described above could be taking the place of anywhere between 8^3=512 blocks (when replacing a Leaf node) and 32^3=32768 blocks (when replacing an internal node child of the root node). This greatly reduces memory consumption both in RAM and during serialization. Also, the bitwise algorithms mentioned above remain valid as they find which node contains a set of xyz coordinates. If the node is a tile instead of a proper node with children, so be it: the tree traversal stops there and returns the voxel stored in the tile.

Because the tree is height balanced by its statically defined, compile-time configuration, random access to voxels is, in the worst case scenario, constant time or O(1). Obviously if a set of coordinates points to a tile somewhere earlier in the tree, it is faster than that. The paper also describes caching mechanisms on the basis that random access is actually rarely truly random. I.e. a player will interact by and large only with blocks that are near him and most likely only with blocks he or she can see. Caching previous tree traversals to reach a voxel allows for reverse traversals from that voxel to nearby ones, the cache in most case limiting the traversals to the first common ancestor node rather than requiring ascending all the way to the root node.

Bit masks are another attractive feature for this project's intent and purposes, I suspect. Every node has a bit mask describing which child node is active. The definition of "active" is application-specific. One potential use is to flag as active all nodes that neighbor air, water or other transparent blocks as a subset of them is what gets rendered. Special blocks that need to remain active even when hidden can also use this feature. I would expect this mechanism to speed up visibility testing as one needs to iterate only on the bitmask rather than the content of a whole node. I imagine additional bitmasks could also be used for other purposes.

Sequential and stencil access is probably where VDB mostly shines. The combined use of contiguous memory, caching, tiles and bitmasks makes iteration fast, especially in sparse, heterogeneous volumes or even in dense, relatively homogeneous volumes. The system also prescribes an out-of-core offset on a per-node basis, so that if a node needs to be loaded from disk, its file offset is readily available.

Finally, a few considerations from me.

The reason I wrote this summary is not to advocate the implementation or adoption of VDB as a whole. More likely, we could use some of its principles. I.e. I doubt its default tree structure, characterized by cube-shaped nodes would be appropriate. In the case of a minecraft-like, vanilla world the individual nodes might be more appropriately biased toward square, flatter boxes instead of cubes, to reflect the horizontal nature of most landscape. I also doubt a full five levels of tree hierarchy is necessary for this project. Perhaps four levels (root/internal/leaf/voxels) would be enough, the root node being dense, array-based (VDB's root node is sparse, list/hashmap-based).

However, the concept of tiles replacing homogeneous volumes whenever possible seems quite relevant to this thread and perhaps easily applicable.

One thing VDB does -not- provide out of the box is multi-resolution, i.e to support low-resolution, vast(er) landscapes visible in the distance. I imagine however that it would be easy to store for this purpose some additional data at leaf level and above, so that while nearby individual blocks are rendered as usual, boxes the size of a leaf node (i.e. 16^3) or even bigger are rendered in the distance.

That's all for now. Looking forward to somebody a couple of years from now digging this out and implementing something out! ;)
 
Top