Biomes

This is getting exciting. Now the terrain adapter class contains a method to add textures based on index. The terrain material uses nine different textures, and now there’s a method in the adapter to do this:



[java]

public void setTerrainTexture(int idx, Texture colorTex, Texture normalTex, float scale);

[/java]



It is very convenient, because you don’t have to access the material, write the texture names etc. If there’s no normal map I just use “null” for normalTex, and the method skips it.



There’s also a class named “TerrainTextureParams” that works with the adapter, and makes it easy to add textures. It’s a bean type object that lets you set and get the textures and scale etc. without having to get into the material stuff.



If/when there’s an editor plugin for this, everything will be gettable/settable from within the property bars of biomes etc., without having to get into the terrain materials and poke around. That’s the idea.

When it comes to the world generator, the elevation stuff some people use isn’t gonna be good enough. There’s too much variation within each zone to make it work that way. What I’m talking about here is dividing the world up into height ranges, and distribute the textures depending on that. It might work on a grand scale, but not on a small scale.



The system can’t be too complex and biologically geologically correct either, of course. There are 12 texture slots in the terrain material, and using more then just 4-5 I think is sort of wasteful and over the top. Especially when using normal maps along with each different texture.



When this project begins, I think I’m gonna use only one default zone. Later there will be many, and most likely they will be divided up into height zones. The default zone will have many sub-zones that can be of any type, and use any texture.



I’ve been thinking about the sub-zone structure as well. By just mixing sub-zones arbitrarily you may end up with 3-4 different zone types on one single terrain, so that’s not good. If these types are supposed to have both regular and slope textures (different textures depending on terrain slope), it will be many textures at once. On top of that there might be road textures and other stuff as well.



I’m gonna start with using a “base sub-zone” for each high-level zone. A default texture + a default slope texture. In technical terms, that means the zone will not be created simply by taking a bunch of different sub-zones and mix them, but it’ll be made up of a base sub-zone (the most common one), then the others are added to it.



There should also be “block-awareness” in the distribution algorithm. Zones shouldn’t just be mixed over large areas using a smooth noise or something, then that mix is mixed with another noise etc. The areas should be divided up into blocks that have tiles in them, and the noise should be low-res and based on that grid. It should be binary (either it’s there or not, no in-betweens), and then smoothed out.



Gonna add some pictures later…





The test sub-zone btw. will have a grassy texture, and a stony/dirty slope texture. There will be a few other sub zones, like a lake/river zone near and under water, a swamp, a forest and some rocky hills.

I’ve prepared the system for the terrain generator now. I think I’m gonna use two map types in addition to heightmaps - rougness and humidity maps. At least initially.



These maps will be generated based on the heightmaps and a few parameters. The heightmaps can be generated procedurally as well, by terramonkey, but I haven’t implemented that yet. The map generator takes a heightmap as an argument. Heightmaps are used for elevation and slope data.



The humiditymaps will first be generated from height data only - meaning everything below water-level gets a humidity value of 1, then it gradually gets lower depending on the height (and normalization based on general humidity settings etc). The system is still to primitive to warrant the use of a texture, it’ll just run a height check in the generation code. The principle is the same as if there was a texture tho.



Roughness maps are basically a measure of how rough the ground is. Rocky areas has got a high rougness value, and soft muddy areas has got a low roughness value. This is also dependant on height, but will also use some sort of noise to make the environment a bit more diverse.



This will make it easier to spread out terrain types, as they will all have preferences. Here are some examples.



Grassy plains wants medium humidity and roughness.



Deserts, or those cracked earth looking areas (like abandoned riverbeds) wants low humidity and low roughness.



Barren rocky areas (like wastelands) wants high roughness and low humidity.



Swamps wants low roughness and high humidity.



This is far less advanced to use then it sounds, because the settings in each biotope are just preferences. Assume that a spot has humidity x and roughness y. All biotopes are checked against these values, and the one with values closest to x and y will be used. If you have extreme wetness all over the map but only one biotope, and it prefers dry lands, that biotope will still be used everywhere because there’s nothing else that can compete. Setting up a basic terrain will be easy.



The distributions will automatically become smooth btw, as long as the heightmap and other maps are smooth. There will be some sort of blending pass also for the finest detail. Maybe just a gaussian blur.



I’ll have example shots pretty soon.

Have you been looking into the terrain/world generator L3DT (L3DT - Large 3D Terrain Generator). You might get some inspiration to the world generation stuff there :slight_smile:

No I haven’t. It looks good tho.



The slope stuff has been implemented now. Here’s a first screen.



http://www.jamtlandoutdoors.se/images/dist/slope_texturing.png



The angle stuff needs to be fixed. Tried cheating a little at first, but I sample terrain normals to find out what the slope is now. It works like in height based terrain material.



This is from the raw alphamap btw, meaning there is no blending yet. Gonna get more into the texture stuff when there’s a getPixel method.



This is not that big of a deal, but the good thing is it works with the system now. This means any terrain type can use multiple textures etc. Here’s the code i used to set this up. Notice I never access the terrain material directly.



[java]

// Setup forester.

ecoManager = EcoManager.getInstance();

ecoManager.initialize(rootNode, terrain, this);



// Wind variable. Used for swaying grass animation.

ecoManager.setWind(new Vector2f(1,1));



// Create the biotopes (sub-zones).

LandBiotope grassland = ecoManager.createLandBiotope(“Grasslands”);



Texture grassGroundTex = assetManager.loadTexture(“Textures/Terrain/splat/grass_512.png”);

grassGroundTex.setWrap(WrapMode.Repeat);



Texture mt = assetManager.loadTexture(“Textures/Terrain/splat/dirt_512.png”);

mt.setWrap(WrapMode.Repeat);





grassland.setTextureData(grassGroundTex, null, 0, grassScale, 0);

grassland.setTextureData(mt, null, 1, rockScale, 1);

grassland.getGeoData().setMaxSlope(50);





// Since the terrain is a pre-made object (pre-generated heightmaps)

// I need to initialize it after all the biotopes has been added.

ecoManager.generateTerrain();

ecoManager.initTerrain();

[/java]



The last two lines are because I create the terrain and set up lod outside of the EcoManager. It’s mostly because I haven’t fully merged yet. When heightmaps are generated as well, there will be no need for those lines, only perhaps a generateTerrain() call with the terrain indices in the grid as argument or something.

The “setTextureData()” stuff is also possible to make easier. Here’s how it works now:



The first param is the texture.



The second is the normal map (not using any here).



The third is the index of the texture, as in which terrain texture slot to add it to (DiffuseMap_x). There’s no need for this. It can and should be sorted out by the system.



The fourth param is scale, which I think needs to remain.



The fifth param is the layer index. It’s just a way to add multiple textures to one terrain type. Layer 0 is the grass, and layer 1 is the slope texture in this case. The numbers could be removed and there could be an enum instead (Usage.Slopes) etc. I just use 0 for regular and 1 for slopes atm.



The method could be reduced to this: “setTextureData(Texture colorTex, Texture normalTex, float texScale, Usage usage)”. Usage could be regular ground texture, slopes, etc. (there may be more options later).

Blended the alpha maps now. Made some extreme hills and tried it out.



http://jamtlandoutdoors.se/images/dist2/procedural_alphamaps_blended.png



Seems like its working now. Time to move on to multiple terrain types.



Got the terrain heightmap generator started now as well. It is based on the terrain grid noise lib, and works pretty much exactly like it does in terraingrid.



The generator has a few simple parameters. First you set up a unit. By default, the unit is 1, so 1 jME unit is 1 meter. You can set any value. Gonna add imperial units as well.



You then choose the height scale and water level. Height scale determines the scale of all terrain. All height values are multiplied by the height scale. Water level is set as a fraction of 1 (like 0.3 means sea level is at 30% of the terrain height).



Finally you set tilesize and the amount of tiles in X and in Z.



Example:



I want to create a 6 x 4 km terrain (about 4 x 2.5 miles). I leave 1 unit as 1 meter (about 3 feet). I choose to use 1024x1024 tiles, with 4 in the z dir and 6 in the x dir.



I want this to be a fairly flat area, without mountains in it, so I set the heightscale to 50 (m). This means the terrain will be at most 50 meters high. I also want no sea, so i choose to have sea level at 0.





The generator dumps the heightmaps as grayscale images. It also dumps the alpha maps. This makes it possible to create large areas of terrain to use as a “canvas”, then load them into the editor and modify. If you want a town somewhere just modify that tile locally (flatten the housing area or w/e, add some roads and stuff).

Very nice.

If you’re interested, I just finished a Perlin Noise terrain Heightmap generator.

I can provide the code if you wish.

No thanks there is one in jme already.





I have finished the ground roughness maps now. Roughness becomes higher with elevation, as usual, but not uniformly. There has to be rough spots spread out at all heights.



The general shape of the terrain is the typical one - smooth-to-rough depending on height. The roughness maps are derived from these heightmaps and an independent noise. That noise is then modified by the base heightmap, to ensure that higher areas always get a high roughness value. I’m currently using a simple function for this (adding the heightmap to the roughness map, using a weight and an offset and some stuff).



I’m experimenting with slightly different high octave noises depending on roughness, but I don’t think it will be added initially. It’s a pretty simple function - two different tilable high-frequency noises that are added on top of the base heightmap. They are blended using the roughness map. If this is implemented later, I will remove the upper few octaves from the base map and replace them with those. It’s not so important at lower heights tho, it’s mostly just to add different textures at this point (gravel instead of grass/mud).



The roughness maps are stored along with the heightmap. I think they can be useful for all kinds of geological stuff, like spreading out minerals for example. There could be a mineral map for iron and copper and stuff, and that map is multiplied with the rougness map to ensure minerals are only found in areas where the ground is rough (where there are rocks/mountains). Or the other way around for other mineral types.



In fact, such a system could easilly be associated with biotopes, just like grass and trees are. You make a type of mineral, and a type of deposit associated with that mineral. The deposits are then added to biotopes and the rougness maps are used as density maps to spread them out.



Gonna put some new images up very soon, and maybe a video.

Finally the base terrain is done. The system automatically generates a multi-fractal type heightfield now, divided up into tiles. Then the alpha maps are generated and stored with the heightmaps. They can be used to texture terrains and as density maps for grass and trees.



Now its time to do some serious refactoring of image code, on account of the new Image stuff (it’s not that much code tho, just density maps and alpha maps).



http://www.jamtlandoutdoors.se/images/dist2/musgrave_terrain.png

3 Likes

The same videos i posted in the media thread. Gonna try a different approach.



http://www.youtube.com/watch?v=wT1uLm7lyKI



http://www.youtube.com/watch?v=sVF81b35mSM
1 Like

Wow, this is simply awesome. I actually think your method of paging the terrain the same way as the grass makes sense… it looks really good! Maybe that’s the way forward?



Could you please upload your demo project to the downloads so we can test this? Unless I am missing something there’s source code there but no examples of using the refactored system :frowning:

1 Like

@monkeychops

I can’t upload sorry, still working on porting the grass/trees to the new system. I guess I could upload terrain part only, but it’s not completely fixed yet. It’s not that far ahead tho. I plan on release BioMonkey 1.0 (which would be forester 2.0) in early october (1 year anniversary), but there’ll be a couple of previews before that.



I have made a lot of changes to the grass and trees too, but they’re mostly internal. The parameters (density multiplier, mesh type etc.) are still the same. Data is handled more efficiently now. Much more efficiently. Heightmaps are floats, as usual, but I managed to pack most of the other terrain and grass/tree data into a 2d byte array. Basically all the data needed “internally” to plant grass/trees and generate terrain textures is packed in this array. No buffers, no arraylists, nothing.



The maps and everything will be exportable to use with any terrain stuff later tho. That’s the whole idea actually. You should be able to generate a terrain (i.e. heightmaps and alpha maps etc), then export and build scenes in scene composer or w/e.

1 Like

A short vid showing how the biomes work atm.



http://www.youtube.com/watch?v=G8gYU51PSI0

I think it would be nice to fade in a texture based on distance from the camera, so far away you only see the color and closer to the camera the texture is showing. This way you can a detailed texture and alleviate the obvious tiling of textures.



This is looking so great, keep up the good work!

The steeper the side the faster it should go to rock instead of dirt - rather than or as well as using noise to do that.

Here I’m using several more layers. Basically there’s a green layer with some brownish patches near the bottom, then there’s cliffs with some grayish/yellowish stuff on it, then there is cliffs with some snow spread out sporadically, and finally a layer of only snow at the top. 7 different terrain types in total. The time this takes to generate, as opposed to using 4 terrain types (like in the video), is insignificant.



http://www.jamtlandoutdoors.se/images/dist2/several_layers.png

Linked the high level stuff with the terrain pages now. It’s possible to get data such as height and zone info from methods in the world class.



http://www.jamtlandoutdoors.se/images/dist2/show_terrain_data.png

And now the humidity and roughness maps have been implemented as well. The system works in several steps:


  1. A heightmap is generated for each terrain tile. The size and scale etc. depends on some settings in the biomonkey world class.



    (I just converted the arrays and printed. Hence the scaling fail at the mountain top…)



    http://www.jamtlandoutdoors.se/images/dist2/heightmap.png


  2. All heightmaps are scanned, multiplied by a terrain height modifier, and the min and max values of the entire world are found. This is in order to scale everything properly.


  3. A slope map is generated. It contains the magnitude of the maximum slope (in radians) at each point. It contains no direction or anything atm, just the magnitude.



    Note how this map is much more detailed then the heightmap, because even small height differences are registered and has an output between 0 and PI/2. Humidity and roughness are also limited to low values (0,1). The heightmap on the other hand, unscaled, has values that are spread out over a much, much larger range. The un-compressed values is what the slope map is working on btw, not the 0,1 normalized heights.



    http://www.jamtlandoutdoors.se/images/dist2/slopes.png


  4. A roughness map is generated. This map is used to determine how “coarse” the ground is. Cliffs has a high value, mud has a low value. Roughness is generated from an independent noise, which is modified by the heightmap. The higher it gets, the more mountains and stuff, which are mostly rock.



    In this example I’m using a lot of mountains, which makes the map almost 100% rough in most places. I might tone this down later, considering there might be soft grassy spots in mountains as well.



    Updated to include slope as a factor as well. Steep areas are more likely to be rough now. We’re only dealing with the top layer of soil after all…



    http://www.jamtlandoutdoors.se/images/dist2/roughness.png


  5. Finally the humidity map is generated. It is based on all the other three maps.


  • The higher the point is, the less humid it will be.


  • The more the ground is sloping at the point, the less humid it will be (because rain and stuff falls off).


  • The more coarse the point is, the less humid it will be (water is filtered through, doesn’t stay near the surface).



    http://www.jamtlandoutdoors.se/images/dist2/humidity.png



    This is no exact science, but it works pretty well. Biotopes can later be added that requires a certain range of humidity, elevation and roughness. Even plants can be added that way. I’ve seen that used. In fact, my system already has the “survival of the fittest” spreading i’ve seen used in biometric tools etc. Zones aren’t just picked, but for every point, the elevation, roughness and humidity preferences for each zone is checked. The zone that is “most fit” (i.e. whos preferences lies closest to the values) is picked.



    Also, the humidity, slopes and roughness stuff is nothing the user has to be concerned with if he doesn’t want to. It’s all generated automatically with default values, and doesn’t have to “do anything”. In fact I’m gonna make it possible to enable/disable it later.



    I’ll post a new video soon showing how it works, and how the hooks can be used (super easy). It can be used to determine pretty much anything.



    For example:



    The wetness in an area could affect the decay of certain items, or the potency of certain spells etc (in a fantasy adventure game). Maybe an interesting tactical element. Height and slope is of course also useful to alter values like chance to hit etc. (fighting uphill/downhill).



    The humidity map can be passed to shaders, to modify fog values. The densities are between 0 and 1, and in combination with a height-based fog system it would create nice looking fog. The fog would be semi-volumetric.



    Not just plants and trees but animals, and even tribes of peoples can be spread out according to these values. Some only live in dry, hilly areas etc. This could be because the environment make them stronger in some respect, like with the spell casting example.
1 Like

Pretty cool stuff with all the maps :slight_smile: Do you use terrain normals to check slope? I’m currently using a sloppy diff between neighbouring height values but it has some ugly corner cases.



I’m trying to learn to write netbeans/jME-plugins, currently experimenting with the platform but as a tutorial I’m thinking about a plug-in that takes a float-array and size (width == height) and draws the normalized float array as a grey scale image (exactly like your images). Would that be a useful addition to this? Maybe like some sort of “debug” output panel to see the generated maps in some way.

The plugin I have right now is kind of hacky but works, the array generation is driven from a javascript. This is mainly so that I can write some javascript and tweak algorithms and values without recompile. Just press draw and the image is (eventually) drawn.

I’m thinking that I could maybe use beanshell instead which parses java fine. So you could sort of have a quick script-turnaround and when it looks good you just compile as usual.