Fertile Radius
Home -->
Programming Projects -->
Fractal Block Engine -->
Fertile Radius
What is the Fertile Radius?
If you have not already, read
this page
about the level radius.
Recall that every level has a radius R
(its level radius).
Basically, chunks that are <= R from the center are added
to the active chunk tree,
chunks there are >= R+2 away from the center
are removed from the active chunk tree,
and we don't add or remove chunks that are
exactly R+1 away from the center.
Here when we talk about distance, we mean
the "L infinity" norm (the "max norm").
In addition to a level radius, each level has a
fertile radius.
Chunks that are within the fertile radius from the center
contain all sorts of entities and can be interacted
with normally.
On the other hand, chunks that are outside the
fertile radius only contain blocks.
Their main purpose is to allow a larger rendering radius,
without causing more monsters to load which
would change gameplay.
Good values for the fertile radius
The fertile radius of a level should always be less than or
equal to the level radius,
with the exception that we require (for safety) that the
fertile radius always be at least 1.
We recommend a level radius of 4
and a fertile radius of 3
(for the finest level).
Note that making the fertile radius lower
would (probably) make speed runs easier,
and is perhaps cheating.
Determining when a chunk is fertile
Let F be the fertile radius of the current level.
When a chunk is first created, we let D be the L infinity distance
of the chunk from the center chunk of that level.
- If D <= F we set the chunk to be fertile.
- If D >= F+1 we set the chunk to be non-fertile.
We update whether or not a chunk is fertile whenever the
viewer centric position (VCP) of the chunk changes.
When this happens, let D be the L infinity distance
of the chunk from the center chunk of that level.
- If D <= F we set the chunk to be fertile.
- If D >= F+2 we set the chunk to be non-fertile.
- If D = F+1, the chunk is in "fertile limbo"
and we do not change whether or not it is fertile,
although if it is fertile then we perform
"Fertile Limbo Percolation"
(see below).
The reason for the strange D <= F and D >= F+2
conditions is because we do not want the player to be
able to quickly walk back and forth causing a chunk
to oscillate between being fertile and non-fertile.
This would be abuse of the game.
A word of advice
For anyone making their own engine like this,
we highly recommend figuring out how to
render the world without having to clear the
depth buffer mid render.
Clearing the depth buffer causes much
complexity, some of which is described in this page.
Fractal Block World, in its current form,
clears the depth buffer mid render.
Fertile Limbo Percolation
A chunk is in fertile limbo precisely when is is F+1
(in terms of the L infinity norm)
away from the center chunk, where F is the fertile radius.
When such a chunk is made to be fertile, we go to all
closer (with respect to the L1 norm) chunks that are
also in fertile limbo and we make them fertile.
Note here we are using the L1 norm instead of the
L infinity norm.
The reason for this procedure is that
if L is a line segment from the camera to
a point in a fertile chunk, then all other points
in L must also be in fertile chunks.
Here we are only talking about chunks
on the same level.
That is, we do not want a chunk that is fertile to
be rendered behind a chunk that is non-fertile.
This would cause a problem with the way we are using
the depth buffer.
If the reader has a system where they do not need to
clear the depth buffer mid render, then this
"Fertile Limbo Percolation" procedure does not need
to be performed at all.
Fertile Limbo Percolation is a recursive procedure.
The Revised Population Procedure
Recall that when a chunk is first created, it is
a "proto chunk" (an empty shell, a chunk that has not
been "populated" with any game data).
A request is made to the procedural world generation system,
and that system creates the data to populate the chunk.
This "populate data" is passed to the chunk and it is
populated, making it no longer a proto chunk.
Here is how we revise this procedure
to accommodate the fertile radius.
The procedural world generation system still generates
all the populate data in one object.
However only the block data is used to populate the chunk
(if the chunk is non-fertile).
The chunk holds onto the populate data
(although it can delete the block data from
the populate data object)
for the entire life of the chunk.
Once the chunk becomes fertile, the chunk takes
the populate data object and uses it to complete
the population procedure.
If the chunk goes from being fertile to non-fertile,
all non-block data is removed from the chunk itself but
the chunk holds onto the populate data object
in case it becomes fertile again later on.
What about moving entities?
When a moving entity passes into a chunk C that is non-fertile,
it is actually passed to the parent of C.
This cases a serious problem, because up until this point we have been
saying that each level is rendered, and then the depth buffer is cleared.
So if a rocket passes over the ground of a non-fertile chunk,
then the ground would be drawn on top of the rocket, which is wrong.
That is, if the non-fertile chunk is on level L, then when the rocket
enters the chunk it would be passed to the parent chunk,
on level L-1.
So the rocket would be rendered on level L-1, the depth buffer
would be cleared, then the non fertile chunk on level L would be rendered
on top of the rocket.
So, we need to revise the way we clear the depth buffer.
See the next section about revising the rendering procedure.
The Revised Rendering Procedure
Here is the old rendering procedure:
- Render all non-alpha parts of chunks on a level
(writing to the depth buffer).
- Render all alpha parts of chunks on that same level
(NOT writing to the depth buffer).
- Clear the depth buffer.
- Repeat the procedure on the next finest level.
Here is the new rendering procedure.
Note that non fertile chunks do not have any alpha
(transparent) components for rendering.
- Let L be the coarsest level that needs to be rendered.
- Render all non-fertile chunks on level L
(NOT writing to the depth buffer).
- Clear the depth buffer.
- Render all non-alpha parts of fertile chunks on level L.
- Render all non-fertile chunks on level L+1.
- Render all alpha parts of fertile chunks on level L
(NOT writing to the depth buffer).
- Clear the depth buffer.
- Render all non-alpha parts of fertile chunks on level L+1.
- Render all non-fertile chunks on level L+2.
- Render all alpha parts of fertile chunks on level L+1
(NOT writing to the depth buffer).
- Clear the depth buffer.
- ...
Again, if the reader has a system where they do not need to
clear the depth buffer in the middle of rendering,
then this procedure is greatly simplified.