We handle any number of overlapping terrain types anywhere in the world down to the texel level. We define the world in a series of geo areas, which are control points bounding an area with splines in between them.
Distance patches are made by creating dynamic textures by collapsing the texture splat stack using java2d to create a unique texture for that distance patch at a specified density.
For the level 0 patches we render the textures using alpha blending
Any arbitrary selected piece of the terrain can become a geo area, and you can overlap and layer them. We have thousands of these areas and the order of their layering is extremely important. The engine can answer
at anytime the question "what geo areas are at location x,y and what are the percentage of each area. You might be standing on a beach, just as it is fading out to grass. This can answer that we are 20 percent beach, 80 percent grass. These percentages can add up to more than 100 percent. You might be 100 percent inside a mystical valley, 100 percent on a sacred hill
and 100 percent inside a fairy circle. So from a rendering point of view maybe that spot is 100 percent fairy circle and 0 percent anything else, but from a sound point of view you might have 3 combined sounds.
All areas fall into basic categories, each with a
base priority over the other. Areas of the same category have to define their priorities relative to each other, but that reduces the basic problem to layers which are in the same category and overlap.
As a reminder every area can have sounds, ground tetxures, atmosphere changes, fogging, particle system effects and more assigned to it.
Here are the basic categories, starting at the bottom to the top:
- public static final float LAYER_PLANET = 100f;
This is the basic single layer that covers the entire world. This is here
because we need a starting base. I would assume we would never “see” this
layer.
– public static final float LAYER_LANDMASS_SHELF = 200f;
This is the basic category which forms the base of islands and contients.
Mostly this would be sand.
– public static final float LAYER_LANDMASS = 300f;
This is the basic category for the whole continent. I see this as a full
area inside the LANDMASS_SHELF and forms the basic material it is made out
of. So I would see this as either dirt, volcanic ash, coral. This would
also be used as the base for the seabed, since “underwater” is also a
landmass.
– public static final float LAYER_CLIMATE = 400f;
The basic category managing major climates like desert, tundra, tropical,
arid, etc. I see this as areas which carve up the landmass into basic
sections. This can also be layered, but priorities have to be managed. If
you make a big desert area and then add a bunch of oasis then the oasis
would be have a priority of 400-499 or so.
– public static final float LAYER_AREA = 500f;
An area is the basic way the worldbuilder can make a bunch of interesting
terrain transitions. This is where you add fertile valleys, or change the
tree types / densities of areas. Most of the priority juggling by the the
world engineer will be at this level.
– public static final float LAYER_WORNAWAY = 600f;
This category is for “worn away” places in the world. The best example
would be around towns, mines and other places where the grass and vegetation
has been worn away. This layer would not override stone, but would instead
override soft material like grass.
– public static final float LAYER_PATHS = 700f;
Paths are really worn away areas, but this forces them above them in
priority. This also allows paths to always be detectable by the engine so
we can do path following. Visually this would also replace rock, but only
replace soft material.
– public static final float LAYER_ROADS = 800f;
Roads are like roads, but have a higher priority. These would be paved in
some fashion (rocks, cobblestone, etc. This would override rocky textures
and would override any paths which it crosses.
– public static final float LAYER_EFFECT = 1000f;
This would be for visual or non visual areas (may optionally not include
ground texturing) for which we assign special effects. We can assign
special effects to any area, but this category can be used to set up
dynamic areas for spell effects, or special sounds, etc. The server could
send me a message telling me to create an effect area bounded by the control
points and then assign visual or sound effects. An example could be an area
based ward with a shimmering boundry curtin, or a forest fire area which can
increase or shrink dynamically.
– public status final float LAYER_POLITICAL = 1100f;
Invisible areas denoting land ownership, good/evil concentrations, etc.
This is mostly for the server.
When we go to calculate the splat maps for a patch, we acquire a list of all geo areas within that quad. We then sort them by layer according to the algorithm above. The bottommost layer that is visible is used as the base map, and all the others are alpha blended in. The algorithm for calculating the proper alpha blend (considering that there are alphas on top) is a real pain. We have something called a terrainbrush, and each terrian brush can actually be two + textures, for example blending rock (for steep) and grass for for flat. This is then merged with perhaps 3 other terrain brushes for 3 overlapping terrain areas. But it is very possible that the same texture could be used in 2 of those 3 layers. It makes no sense to render the same texture more than once, so we intelligently adjust the alpha map so that the union of those alpha maps for each texture are used. But we also dont want to render one pass texels that will just be overwritten by a higher level, so we often make those transparent so that the renderer can not rasterize those texels.
THis all took a lot of work and there is no “quick” fix to do it right.
Here is some more info on areas:
Each area can have weather associated with it. generally weather changes will
be attached to the LAYER_PLANET, but by having the weather by area based it is
possible to have a spell affect the weather in an area, or to have a storm
which moves.
There is a new resource called atmospheres. It controls like 20 different
elements relating to the sky and weather. It is designed to be able to take
two such definitions and interpolate between all the values to provide smooth
transitions. These resources (like all) are named. So you can have
a “Overcast Day”, “Sunny Day”, “Lightning Storm”, “Rainstorm”, etc. So you
could create an area in the world which was clouded in perpetual clouds, or
constantly snowed. Now I should say that you cannot observe these changes from
a distance. In other words you cannot see a storm approaching on the hoizon,
or see a rain soaked region from a blue sky area. What happens is as you enter
a region and you are in the “transition” boundry for that area, it will adjust
all the attributes and intensify them as you go deeper into the area. The same
is true of ambient sounds. You are walking along and you start to enter
the “black forest”. as you start out entering you are maybe 5 percent into the
boundry area. The “black forest” sounds (like moaning wind) would be at 5
percent volume. As you go deeper into the transition area the sound increases
more until it is at 100 percent. This same “environment” envelop surrounds the
edge of the area and is used to optionally override sounds, weather and
environment.
With the exception of most of the terrain texturing, all these elements can be
adjust by the server if desired. So if the server wants to change the global
weather it could send me a message atell me to change the atmosphere resource
on the LAYER_PLANET to “Rainstorm”. Alternatively it could also create a new
LAYER_EFFECT, create a roughly circular or bloblike area, assign it
the “Rainstorm” resource and then send me updates to move that resource around
the world. This would in-effect cause a moving storm. Another option could be
a spell that caused a lightning storm. This spell could swiftly transition the
environment to the new weather at supernatural speed, throw a few lighning
bolts and then dissipate as fast as it came.