Store Biome Per Block

shartte

New Member
Contributor
Architecture
Hello everyone,

i will try to present my proposed change to store biome information per-block with the other chunk data (block ids, etc.).

The problem I am trying to solve: Through profiling, I found that 95%+ of the time spent in generating a chunk mesh is spent in calculating the temperature/humidity of a block for giving foliage and other blocks a hue.

Proposed Solution: Since there is most likely a correlation between temperature/humidity and biome, I'd like to determine the biome for every block when the world is being generated and store that information with the rest of the chunk. In the rendering stage, the humidity/temperature of the biome is then used for rendering.

To do this, I introduced the concept of a Biome in the engine (interface), which has to provide temperature and humidity values, as well as an ID and a human readable name. Largely this concept is stolen from the AnotherWorld BiomeRegistry. The change set also includes the necessary changes to bring the Core and AnotherWorld biomes into the Biome class hierarchy provided by the engine. In a chunk, Biomes are stored as 16-bit integers. The mapping between Biome IDs (assumed to be module + ":" + biomeId) and those "short ids" is managed by the BiomeManager and stored to the save manifest. The change also includes the necessary changes to transmit the biome data to the client in a networked environment, as well as transmitting "BiomeUpdateEvents" to clients. The F3 debug overlay also now shows the biome the player is standing on. The Biome auto discovery requires a module to provide an implementation of "BiomeRegistrator", which then is called back with an instanceof a "BiomeRegistry". The module then uses this biome registry to register the biomes it provides. I made the move away from auto-discovering Biome classes, since Core defines its Biome in an enumeration. I also conflated the Biomes in AnotherWorld into a single class and simply instantiated it for each Biome and then registered the instances (as can be seen in the AnotherWorldBiomes class).

In the medium to long term, it'd make more sense to encode fixed biome colors rather than colors deduced from humidity and temperature. For example one could devise a Wasteland biome with dark brown foliage colors, which shares the same humidity and temperature as a desert, which still has green cacti.

Biomes are stored per-block instead of per-block-column (as for example in Minecraft), since this would allow deep underground caverns, dungeons, or sky islands to be a separate biome from the overworld.

In the future, Biome could have more gameplay implications and may be used by modules to attach gameplay behaviour to areas generated by the World Generator, all while not directly depending on the world generation itself.
For example:
- spawn entities or structures only in certain biomes
- allow terraforming the world with advanced technology or magic (effectively changing the biome of surrounding blocks)
- allow wildly magical areas through world-generation (think purple grass) without having to provide different grass blocks (to look nice, this requires biome color interpolation)

You can find the source code here:
https://github.com/shartte/Terasology/tree/biome-per-block
https://github.com/shartte/GrowingFlora/tree/biome-per-block
https://github.com/shartte/AnotherWorld/tree/biome-per-block
https://github.com/shartte/WoodAndStone/tree/biome-per-block

I uploaded a ZIP Dist here: http://www.hartte.de/ts/Terasology.zip
If you'd like to check out the performance improvements without having to compile it yourself.

This thread is intended to serve as a discussion for the merits of this change. There are certainly several alternatives, which could also be discussed here.

Regards
Sebastian
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
Hi, is it still going to be that the biome is defined by the environment (humidity, temperature, height, etc), rather than the way it was in Core, where biome was based on perlin and temperature and humidity depended on it?
 

shartte

New Member
Contributor
Architecture
Hi, is it still going to be that the biome is defined by the environment (humidity, temperature, height, etc), rather than the way it was in Core, where biome was based on perlin and temperature and humidity depended on it?
Hi,

I didn't change how the Biome is actually computed. I am rasterizing the BiomeFacet provided by the WorldGenerator into the Block grid. So what Biome goes where is still dictated by the Worldgen.

Regards
Sebastian
 

Josharias

Conjurer of Grimoires
Contributor
World
SpecOps
Originally I was not too excited about making it more like minecraft by depending on the biome concept. However, I have warmed up to it mostly for the reason of minimizing exploitation. IMHO it is bad if the clients are able to use the world seed to generate data they should not necessarily have. In a public multiplayer setting, it should be the option of the game master/server owner to provide such information that could potentially ruin the competitiveness.
In addition to minimizing exploitation, it solves the immediate need of supporting world data that takes a long time to compute (like Throughout the Ages) while not killing general performance. The trade off for performance comes at the cost of not having as precise transitions between foliage hue. But foliage hue is not an important part of my personal taste.

I would vote for this.
 

msteiger

Active Member
Contributor
World
Architecture
Logistics
Thanks for the thought and effort, @shartte.

Please don't get me wrong, I'm just throwing some thoughts into the discussion.

About the hum/temp performance: it was pretty fast until the recent refactoring. So I think that it's probably just a bug. The PerlinNoise which is currently used not only for the height map, but also for hum/temp. This could be replaced with SimplexNoise which is a bit faster and also to track down the bug.

If Biome is defined per block, what's the advantage over using the block/block family/block color directly?
Some time ago, @Immortius mentioned that we could get rid of biomes entirely and I tend to agree. Also, I think that humidity and temperature should be internal aspects of some(!) world gens and not visible to the outside world.
For example, in PolyWorld, there's also DistanceToRiver and DistanceToOcean which help defining the right block type, but noone should need to know. Facets are supposed to provide some
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
I agree, we should remove the need for the client for having any extra information about the world, over what they actually need. If the seed is "leaking" to the client due to grass hue, we should consider introducing 16 types of grass (with different hues) and populate the world with correct block wherever needed based on temp/humidity as calculated on the server.

Biome could probably stay, but only as a concept, as it allows to easily define and group some world-gen behaviors, for example - some trees will only generate at certain height over see and temperature, etc.
 

shartte

New Member
Contributor
Architecture
Regarding the use of biomes: I see biomes as a macroscopic view of the world's topography. If you look at a typical game world from the birds eye perspective, you'd usually see a bunch of areas with homogenous properties (i.e. a swamp, an ancient forest, an oasis in a desert, the desert surrounding the oasis, etc.). What kinds of areas can exist, and how they are placed, is up to the World Generator.

What effect an area has on the gameplay is probably yet to be defined. Apart from gameplay itself, biomes can serve to provide interesting places with distinct visuals. The distinction between biomes is in my opinion still useful because aspects such as fog-level and water/foliage-tint can differ substantial between the visual styles of two biomes that share the same placement rules. To give an example from Biomes 'o Plenty:
A cherry tree forest (http://i.imgur.com/zfbsW5w.png) and a redwood forest (http://i.imgur.com/kJuSdVk.png) could be placed in the same environment by the world generator. To make the visual styles distinct however (Only grass and water tint are relevant here, since foliage is actually using different blocks), the style has to depend on the "biome" chosen by the world generator, and not the input-variables used by the world generator to determine the biome (as those could be the same for two distinctly different areas).

In my opinion, the current humidity/temperature hue system should be replaced with distinct biome-dependant coloring. To make the best of this, the engine would have to support automatically interpolating such colors at the border of biomes to achieve better visuals. I acknowledge this isn't necessarily realistic, but from the perspective of a game, I think it makes sense. The engine would only expose that there's a concept of "biome" (or world-gen "area") that can be queried very efficiently per-block.

Possible future use-cases:
  • Underground dungeons could get their own "biome" (again... misnomer) that causes water puddles to be color differently or cause a slight fog.
  • Passive spawning systems could use the "biome" to determine what should spawn where. I hate the lack of variety that Minecraft has for example. It just spawns Zombies and Skeletons everywhere.
  • Without actually knowing about temperature, other visual effects could be supported by biomes (i.e. heat-wave shader for desert-type areas, frost-bite for ice plains, etc.). The engine would not necessarily have to know about any biome to achieve this, the world-gen could hook arbitrary compositor effects into the biomes it registers.
Using separate blocks for each biome could probably work, but has some downsides I think:
  • Interpolation still has to be performed, but it's easier to interpolate between two colors instead of two blocks that could have wildly different properties.
  • How would that work for water?
  • It makes creating new biomes a lot more complicated since long-grass blocks, grass, foliage and water would need to be duplicated, even for just slightly different visual styles
  • A user's inventory would probably explode from all the different (probably unstackable) blocks ;)
You are correct though. This needs further thought.
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
I'd request however having as little limitations (requirements to have a biome) in the core engine world-releated interfaces, as possible. I'd like to still be able to create a world were atmospheric conditions are defined by the humidity/temperature/height/etc (like it is in real world) rather than a biome "label" arbitrarily set by the WorldGenerator.

As for user's inventory "exploding" with different blocks, you are assuming that the different types of grass blocks will be dropping different blocks. IMO they all should drop the same "dirt" block, if anything at all.
 

shartte

New Member
Contributor
Architecture
Hm, I don't think it would limit you in that. You could make a world generator that simply uses the "DEFAULT" biome and doesn't care about biomes otherwise.
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
It would however limit the storage, where you'd be storing extra information per block. Which potentially might end up being A LOT of data. Each chunk is 32x32x64, so if just 1 byte is used, that's 65kB just to have a grass/foliage hue.
 

shartte

New Member
Contributor
Architecture
It would however limit the storage, where you'd be storing extra information per block. Which potentially might end up being A LOT of data. Each chunk is 32x32x64, so if just 1 byte is used, that's 65kB just to have a grass/foliage hue.
I also thought about this. Since the areas are probably quite big and *should* be somewhat contiguous, the biome data will largely have the same value within a chunk, other than for chunks that lie on the border of a biome. For storage on disk, GZip should already take care of this. For transfers to network clients, the RLE compression should also reduce this significantly. I agree that the in-memory cost is higher (roughly 128kb per chunk I'd guess). But I don't see how this can be avoided. If you cache temperature/humidity data, which would be an alternative solution to the current performance issue, you'd still have more data in-memory than with the biome data.
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
As was expressed above, the fact that temperature/humidity is taking so long to calculate at the moment (if it is indeed) is probably a bug, as currently it uses a noise function to calculate it. In AnotherWorld, a factor of height (y) is taken into account in addition to the noise function.

Lets not use a cannon (storing temperature/humidity per block) to fix a performance bug.
 

Marcin Sciesinski

Code ALL the Ages!
Contributor
World
Architecture
I talked with shartte on chat a bit and we've came to an agreement:
- each block will have a biome_id stored and transferred to clients,
- this biome_id will be populated by WorldGenerator during chunk generation and might be updated by mods,
- WorldProvider (or *Core) will have a method returning Biome (interface) on a per block basis (x,y,z), this requires that server and clients share biome_id->Biome mappings,
- Biome interface will contain methods for getting grass/water/foliage hue and biomeId, however mods could add additional meaning to the biome via a biome_id->[value] mapping.

This will allow effectively removing WorldGenerator from the client.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
So at first I was a little skeptical too, but the biome-per-block idea is growing on me. Especially after I started connecting it to one of the oldest design threads - on additional block metadata. Back then that was about secondary resource counters (like liquid/gas deposits inside solid blocks), aquifers, pressure counters, etc. But I'm realizing doing biome this way would leave plenty of space for that potential, making it probably more interesting underground.

Example use case: Caves. With something like the "air vein" ore generator you could update the biome data (after initial world gen seeds it) to flag the caves as a cave biome. The tricky scenario that came up on IRC was what happens when a player digs into a cave - if it is a tiny hole it probably shouldn't change much, but if you excavate the entirety of the cave roof it isn't much of a cave anymore. Block breaking events could check for biome impact and make adjustments as needed.

As a bonus you could tie things to some biome states like caves being automatically indoors. Which then could help make growth simulators and other things faster as they could just check the maintained biome rather than do a "sunlight present?" calculation. Then if needed check ambient light levels further.

And really you could use this for tracking aquifers and other interesting things too ... :)
 

Esereja

Active Member
Contributor
How about we have "tags" for chunks to decide biome in it. It would mean less data and we could save more data about given chunk. like "underground, underwater, cave, dungeon" which could be used to decide things like what monsters spawn there, what atmosphere soundtrack to play and so on.
 

shartte

New Member
Contributor
Architecture
The biome is per-block because otherwise, biome boundaries could only be on 32x32x64 cubes, which leads to a very artificial feel.
 

Esereja

Active Member
Contributor
good point, Tough I think we will still need good way to find surrounding environment, more specific than biome. But biome info will be very helpful(i am thinking monster spawning and environmental sounds)
 

Florian

Active Member
Contributor
Architecture
When I first read this thread I found it quite confincing. However thinking about it a bit more I don't think we
should introduce biomes per block.

One of your arguments for biomes per block is, that you can then
- spawn entities or structures only in certain biomes
The world generator has all knowledge about the chunk it generates. It can place structures and entities based on more complex
conditions then just biomes. It could even generate some "extra dangerous caves". It could place some special blocks in
that extra dangerous cave that marks it as dangerous and will once destroyed make it a normal cave. e.g. some evil black spines
or a "spawner block" like in minecraft if it has to be.


One of your further arguments for biomes per block is:
- allow terraforming the world with advanced technology or magic (effectively changing the biome of surrounding blocks)
Effects of magic or advanced technology needs to be implemented explicitly. I see now reason why it should not simply
create a variant of another block on the fly instead of modifying the biome.

First the idea of multiple color variations of one of the same block seems troublesome. You list:

Interpolation still has to be performed, but it's easier to interpolate between two colors instead of two blocks that could have wildly different properties.
How would that work for water?
It makes creating new biomes a lot more complicated since long-grass blocks, grass, foliage and water would need to be duplicated, even for just slightly different visual styles
A user's inventory would probably explode from all the different (probably unstackable) blocks
I think probably the most important issue you list: We would need to define a lot of blocks which is a lot of work for little gain.

That may be true now but it should be changed. I think it should be possible to define parameterized blocks. For example:
* A tall grass block could have a biome color component, a height component, and a wind influence component.
* A stair case block, that has a orientation component.

The game engine would not generate a block id until the first instance of a certain block is created.
So on a server with someone who makes art with colored wool there could be thousands of differnt colored wool blocks
which each have their own id, but on another server there might be just a single wool block that is white or none at all.

The second most import issue from your list is probably the overfilling of the inventory: I agree that it would be bad
if the player ends up with a ton of different grass blocks. When a grass block is destroyed, it could become a pickup item
that stacks. I would also expect that I can stack staircase blocks independent of the rotation the placed block had before.

Also I think we are much more flexible if we allow modules to add custom components/attributes to blocks.
For example someone could add a electrified boolean attribute to an air block. When you add an attribute
a default should be provided. So in case of electrified it would be false.

If another independent module adds than a danger component, you could have a dangerous electrified block.

I think with the concept of BlockComponents you would also get what you want plus much more.
 
Top