Level Radius
Home -->
Programming Projects -->
Fractal Block Engine -->
Coordinate Systems
When Most Chunks are Added and Removed from the Active Chunk Tree
In this page we will describe when chunks get added to
and removed from the active chunk tree.
By the distance between two chunks (on the same level)
we always mean the L_infinity distance.
So, the distance from chunk at VCP (0,0,0) to the chunk at VCP (1,2,3) is 3.
Each level has a radius R (when the viewer changes level, these level radii may change).
Chunks that are distance ≤ R to the center chunk should be added to the main chunk tree.
Chunks that are ≥ R+2 to the center chunk should be removed.
What happens to chunks that are exactly R+1 to the center chunk is more involved.
We will sometimes talk about the "block type" of a chunk.
That is the type of the block that occupies the same exact space as the chunk.
The Problem with Removing all Chunks that are ≥ R+1 Away: Thrashing
Consider the level of the viewer, where the level radius is R.
Suppose we had a system where chunks on this level are
added if they are ≤ R chunks from the center
and are removed if they are ≥ R+1 from the center chunk.
Then if the viewer is right on the edge of his viewer chunk and
quickly moves back and forth across the boundary,
then this will cause "thrashing".
The same chunks will be quickly created and then destroyed again and again.
To avoid this problem, chunks should usually be created only when they are ≤ R
from the center chunk, and they should be usually destroyed only when ≥ R+2
from the center chunk.
Like a thermostat that turns on at 60 degrees and turns
off at 62 degrees.
In the system described in this page,
it IS STILL possible for some kind of thrashing to occur,
but it is quite unlikely that the user would ever
find themselves in that situation.
The Problem With a Level Radius of Zero
For a level of radius 0, we CANNOT remove all chunks
that are ≥ 1 away from the center.
If we did, the player would not be able to leave that center chunk!
Let us dig deeper.
We are assuming that each level radius is ≤ 14.
If this is not the case, the description in this page should be changed slightly.
We are going to treat levels with radius 0 differently from levels with radius ≥ 1.
The idea is the majority of the levels in the chunk tree will have radius 0
and we want a maximum of 8 chunks on those levels (to save memory).
Most of the levels with radius 0 will have only 1 or 2 chunks on them.
Important: when a chunk is created,
the procedural chunk generation code
for that chunk is allowed access to the block types of the chunks in the 5x5x5
surrounding region of the chunk.
So if a level has radius R, then to create chunks on that level,
we need access to the block types of chunks
that are ≤ R+2 away from the center chunk.
So if we want to create a chunk C on level L+1, then
all blocks within the 5x5x5 surrounding region of C
must be inside chunks that exist within level L.
This leads us to the next section.
The "Envelope" of a Level
Let's say that given a chunk C with VCP (x,y,z)
and given a nonnegative integer R,
the "ball of radius R centered at C"
is the region of chunks with VCPS from
(x-R,y-R,z-R) at the left back down
to (x+R,y+R,z+R) at the right front up.
Consider a level with level radius R.
The envelope radius
of the level is either
3 if R is 0, or it is R+2 if R is > 0.
That is, the envelope radius is the max of 3 and R+2.
The envelope
of the level is the ball centered
at the center chunk whose radius is the envelope radius.
The idea is that for any chunk to be created on a level
(assuming the viewer does not move),
the only chunks in the level whose block type will need
to be queried will be inside the envelope.
So consider level L > 0.
On the next coarsest level (level L-1), only chunks which intersect
the envelope of level L will need to be created for
the required block information to create chunks on level L.
Because we are assuming the level radius of level L is ≤ 14,
then on level L-1 only chunks that are ≤ 1 away from the center chunk
need to be created to provide this needed block information.
Now the level radius of level L-1 might be 0,
and that gives us the only situation where we would create a chunk
that is strictly more than the level radius away from the center chunk.
Also note in this same situation
that the envelope radius of level L-1 is 3.
Summary: When we Add a Chunk
Let us be specific: there are only 2 ways for chunks
to be added to level L of the active chunk tree: one normal and one strange.
- The normal way:
when a chunk is ≤ R away from the center chunk of the level
(where R is the level radius).
- The strange way:
When R = 0 and the chunk is exactly 1 away from the center chunk
and the chunk intersects the envelope of the next level (level L+1).
Summary: When we Remove a Chunk
Let us be specific: there are only 2 ways for chunks
to be removed from level L of the main chunk tree:
- The normal way:
when a chunk is >= R+2 away from the center chunk of the level
(where R is the level radius).
- The strange way:
when R = 0 and the chunk is exactly 1 away from the center chunk
and the chunk DOES NOT intersect the envelope of the next level (level L+1).
Setting Level Radii in Fractal Block World
You can set the radius of each level before the program starts
by modifying Input/Scripts/program_startup.txt and changing
the environment variables that start with "engine.exploration.level_radii."
The radius of the viewer level is "engine.exploration.level_radii.0".
The radius of viewer level - 1 is "engine.exploration.level_radii.", etc."
Making these radii too small trivializes speed runs in
which there are monsters. So we propose that a valid speed run
needs to have radii of values at least 3,3,2,1,0,0,0,0...
These are the default radii values for the 2020 version of the game.
Programming
Given a level, sometimes we recompute the list of
"good vcps" (vcp = viewer centric position)
and "bad vcps".
Good vcps are places on the level where we should create chunks
(if they are not there already), and bad vcps are places on the level
where chunks should be collapsed into blocks
(if they have not been already).
Note that some vcps may be neither good nor bad.
Given a level, when should we recompute the lists
of that level's good and bad vcps?
Consider level L.
The following are the only times when we need to recompute
the lists of good and bad vcps of level L:
- 1) When level L is shifted.
That is, when the location of the center chunk of level L changes.
- 2) When the radius of level L-1 changes.
- 3) When the radius of level L changes.
- 4) When the radius of level L+1 changes.
This is overkill, but it is easy to remember.
Clearing the Depth Buffer Issue
Note that in this engine, we render each level
starting from the coarsest and going to the finest.
After rendering a level, we clear the depth buffer.
So, if we render something from level L+1
behind something from level L, this will look wrong.
So, when expanding blocks into chunks, we should
do this in a certain order.
We first want to expand the block whose VCP
has the smallest norm (in the taxi cab metric).
A similar comment applies to when we want to collapse
chunks into blocks, but this is not as much of an issue.
This issue is discussed more
here.