Implementation Shattered Planes

#1
Name: Shattered Planes
Summary: A worldgenerator which aims to produce unique and surreal terrain features.
Current Goal: Playability and new unique biomes.
Curator: Cpt. Crispy Crunchy
Location: https://github.com/Terasology/ShatteredPlanes

Todo list:
  1. Add ores and use the Caves module on default.
  2. Add plants and special trees to the skyislands.
  3. Make the rift bottom more interesting.
  4. Think of new terrain features.
Features:
-Core Biomes
-Rifts and Canyons
-Skyislands which serve as bridges between the shattered planes

Recent Changes:
-Added mountains
-Added caves

-Fixed border bug thus now allowing filtering techniques to be used without ugly edges on borders.
-Added biome support and thus bringing deserts, plants, forest etc into the world


Slightly outdated picture (missing biomes)

Hey guys,
I just started working with the world generation code (and Terasology in general) and got some canyon like world, which I wanted to share :). If there is interest I'll refine this prototype to get a better canyon look (more realistic river, better block theme, more details etc.).
You can see the code here:

https://github.com/Terasology/ShatteredPlanes





'm open for critic and ideas :)
 
Last edited:

manu3d

Pixel Forge Artisan
Contributor
Architecture
#2
Looks like some very good progress.

I guess perhaps it could use one or two more octaves of noise, at the right frequencies, to break a little what looks a bit too curvy.

I also wonder if it's possible to bias the shapes a little. Right now what you have here are relatively "chubby" mountains: short and roundish on top. Looking at Grand Canyon images, the top is most eroded and relatively sharp, while the bottom is characterized by erosion deposits having relatively shallow slopes. I wonder if it would be possible to have both varying some kind of bias parameter. So in some geographical area the bottom of the canyon would be like you show here, while in some others canyons would display sharper peaks and gentler lower slopes.
 
#3
Good ideas!
I think I'll give that a try with a "contrast" function (has someone implemented that yet?). I'm thinking of gaussian with an amplitude which rises with the height to get that sharp peaks (gaussian(radius)*surfaceheight*constant or something alike). The constant here could function as that bias parameter you mentioned :).
Another try would be to alternate between two noise functions (one to get that cliffs and plateaus then apply one to get an erosion layer similar to the base of the prototype above and then repeat).
Also I'm thinking of some kind of sedimentary layers.

I hope I'll find time for that the next days.
 
Last edited:
#4
Hey, here's a quick update of my work and a little help request.
I'm quiet satisfied with the filtering approach. In the end it has gotten a little complicated but a contrast filter + a smoothing filter (which creates a pretty nice erosion effect) did the job. Now it's about tweaking the parameters
aaaaaaaaand getting block information from adjacent regions. That is the part where I would greatly appreciate some help, as I have no idea where to get the reference from nearby regions. The problem is that ugly edgy borders emerge without it as the filter will modify a block based on it's surrounding blocks. I implemented it with a variable radius in which block information will be considered. However, that's where and out of bounds for region error is likely to emerge. My first cheap workaround to test if the filtering method yields practical results was to just stop modifying the blocks once the radius hits the region border. That's why I got such lines of unmodified terrain as seen here:



Above is an example of the smoothing filter. In the right the borders are most visible.



Here is and example of the contrast filter to create sharp peaks. After that the smoothing filter will be added to add a more natural feel. However, the filter suffers from the same border problem.

Once this bug is eliminated I'll upload the algorithms I devised and explain them if there's interest :).
 
#6
Thanks @oniatus! :)
I read that tutorial and this part in particular more than once, however no immediate solution occured to me. I'm still a bit confused with the details with regions and borders an such (although I read the source code of those.. I might have to dig deeper into worldbuilder classes..). Now the problem with the tutorial solution is that they use a new facet for which they can modify the border as they wish. However, I'm working with the surfaceheightfacet. I tried to copy it into a new surfaceheightfacet for which I extended the borders by the radius of my filter selection. But I still get weird out of bounds error for the facet.getWorld(..) :(.
Maybe my code helps:
Code:
...This is the process method

        facet = region.getRegionFacet(SurfaceHeightFacet.class);
        worldRegion=facet.getWorldRegion();
        Border3D border = region.getBorderForFacet(SurfaceHeightFacet.class);
        border.extendBy(0,0,radius);
        tempRegion = new SurfaceHeightFacet(region.getRegion(), border);
        tempRegion.set(facet.getInternal());

        worldRegionExtended=tempRegion.getWorldRegion();

        // loop through every position on our 2d array
        for (int wz = worldRegion.minY(); wz <= worldRegion.maxY(); wz++) {
            for (int wx = worldRegion.minX(); wx <= worldRegion.maxX(); wx++) {
                Vector2i position=new Vector2i(wx,wz);
                float yOrigin = facet.getWorld(position);

                if(yOrigin>0 && yOrigin>=this.region.minY() && yOrigin<=this.region.maxY()) {
                    Vector2i[] selection = selector(position);
up to the last line everything works

..The selector method:

ArrayList<Vector2i> positions = new ArrayList<Vector2i>();
//circular selector
for(int r=1;r<=radius;r++) {
for (int i = 0; i < 360; i=i+5) {
        Vector2i temp=new Vector2i(o.x() + Math.round((float) Math.cos(i)*r), o.y() + Math.round((float) Math.sin(i)*r)); 
         if(!positions.contains(temp) && worldRegionExtended.contains(temp.x,temp.y)){
                  float height=tempRegion.getWorld(temp); 
                        if(height>=region.minY() && height<=region.maxY()){
                                positions.add(temp);}
                           }
         }           
}
..
tempRegion.getWorld(temp) seems to be the foul apple here.
 

Cervator

Project Lead and Community Wizard
Contributor
Design
Logistics
SpecOps
#7
Pinging @msteiger @Skaldarnar and @Josharias for further questions there, they can likely help :)

Nice work @Cpt. Crispy Crunchy ! Would you like to put that world in a regular module repo under the Terasology org on GitHub? We can make a repo for you, build it in our Jenkins, and ship it with the game :)
 
#8
Wow thanks @Cervator ! :) It would be an honour to see it in an official module :) :) !
Although I'd like to wait with that until everything is clean of bugs :).

I had an other idea concerning a fix. However, for that to work I'd need a reference to WorldImpl inside my FacetProvider, which doesn't seem possible straightaway for me :(..

*Edit* Nvm, found a method for that, it should be fixed soon :)
*Edit2* Hm, seems I would have to split the world builder into two steps/classes for that to work. I suppose thats not the proper way :/
The overall idea was to expand the region3i and then get the region with world.getWorldData(region3i),
then get the expanded facet for that region.
 
Last edited:

Josharias

Conjurer of Grimoires
Contributor
World
SpecOps
#9
Looks like you have figured it out (looking at your github). I agree that conceptually borders on facets are tricky at best. Using the annotation to request a larger region of dependent facet data using borders is the key (as you have found):
Code:
@Requires(@Facet(value = SurfaceHeightFacet.class, border = @FacetBorder(sides = 4)))

In addition to not going out of bounds of the facet when in a facet producer, one needs to be careful in the rasterizer not to go out of bounds of the data available (I have been there, done that, too many times).


I noticed in github you have a call to Facet.setWorld(...) in BoulderRasterizer, this seems like an odd place to be setting facet data, is it intentional?
Code:
surfaceHeightFacet.setWorld(position.x,position.z,position.y);
 
#10
Thanks for your help and for reading my code @Josharias :).
The unusual placement of this setWorld() was back from an very early experimental stage of my work, but yes it was intended. I did some weird stuff which made that necessary.
Unfortunately, the code was pretty old (no filters were implemented at all). The new working code is now online and changed quite a lot. I couldn't take the time yet to find nice parameters for everything but it works now reliably and I invite everyone to play around with the filters, as they can be used on every terrain, needing only the surfaceheightfacet and my "cheat" setup for the worldgenerator class.
I'm sure the one who designed those classes would get brain cancer if he would see what I have done to solve the border problem. I'm still fascinated that it worked out :D :
Code:
WorldBuilder worldBuilder=new WorldBuilder(worldGeneratorPluginLibrary)
                .addProvider(new SurfaceProvider())
                .addProvider(new BaseProvider())
                .addProvider(new SeaLevelProvider(0))
                .addProvider(new BoulderProvider());
        //The seed value isn't supposed to be set here, however for the prebuild one has to be defined.
        worldBuilder.setSeed(491385982348l);
        World world=worldBuilder.build();

        worldBuilder.addProvider(new GaussFilter(2f,0.3f,2,1, world));
        worldBuilder.addProvider(new SmoothingFilter(1f,1f,4,1,world));
        //WARNING!: The filters are not yet optimized and will slow terrain generation significantly down!!!
        //worldBuilder.addProvider(new GaussFilter(1f,0.4f,5,1,world));
        //worldBuilder.addProvider(new SmoothingFilter(1f,0.4f,2,1,world));
        worldBuilder.addRasterizer(new CanyonWorldRasterizer());
        return worldBuilder;
here I get a world reference and pass it to the filter, which then can get the bigger region:

Code:
        Region3i region3iExtended=region.getRegion().expand(radius);
        Region regionExtended = world.getWorldData(region3iExtended);
        SurfaceHeightFacet facetExtended = regionExtended.getFacet(SurfaceHeightFacet.class);
        Rect2i worldRegionExtended=facetExtended.getWorldRegion();
This will also ensure the extended facet has the proper content in it.
I should take the time and get a solution proper with borders done though. I have grown quite an aversion against them now :D.

In case you're wondering; the mode variable will later define if the filter is applied as batch or dynamically
 
Last edited:

Cervator

Project Lead and Community Wizard
Contributor
Design
Logistics
SpecOps
#11
You don't need to be "done" to work in an official repo, we don't add the module to the actual stable lineup until you OK it :)

But that way you can get builds out of Jenkins and users can download the module from in-game (if they so dare). Later we'll add it to the lineup and it'll come bundled with the game.

Just need the name you'd like for the module :) If it is meant to be a general purpose canyon generator "Canyons" is probably fine.
 

Josharias

Conjurer of Grimoires
Contributor
World
SpecOps
#12
Heyo @Cpt. Crispy Crunchy, I took a brief look at your latest commit. I can see why it felt strange to you.

The idea with the WorldBuilder is that it prepares everything before actually getting a seed and such from the UI. By not *actually* building the world, the UI can change all the configuration around and throw away results the user doesnt want.

In your filter classes, you can request a border from the surface facet. That will instruct the generator to make the surface facet bigger for you. Then you do not have to attempt to get an expanded region of data from the world by yourself, and can just use the data present in the GeneratingRegion. So in your filter classes, do something like:
Code:
@Updates(@Facet(value = SurfaceHeightFacet.class, border = @FacetBorder(sides = 4)))
And then instead of passing in the world variable and calling world.getWorldData(...), you can use
region.getRegionFacet(SurfaceHeightFacet.class) to get the data already created with the borders you need.

Hopefully this made sense, its the end of the brain time for me.
 
#13
Hey,

@Cervator ok well then, sticking only to canyons would be a bit boring. Let's called it "shattered planes" as it will motivate me to create more psychadelic terrain and implement biomes and such :D. I do much appreciate it! :)

@Josharias Sorry for being a bit slow minded with borders, thanks for clarifying it for me :). I'll probably upload your solution this evening.

However, things will slow down now a bit as I decided in the last moment to write a proposal for GSOC for agent based land simulation :D .
I will post the core ideas after the deadline in the forum so stay tuned as I'm quite excited about your thoughts on them :).
 
#14
Uff, I tried the border thing @Josharias with
Code:
@Updates(@Facet(value = SurfaceHeightFacet.class, border = @FacetBorder(sides = 4)))
then grabbing the surfaceheightfacet with
region.getRegionFacet(SurfaceHeightFacet.class)
getting the worldregion with:
worldRegionExtended=facet.getWorldRegion();
and getting the inner region where changes actually happen by
Rect2i worldRegion=worldRegionExtended.expand(-radius,-radius);
I also ensure that the radius is less than the expanded border sides.
Unfortunately, the borders don't seem to overlap with one another, creating the same effect as visible in the pictures I posted before.
I can't quite explain this. To my understanding the surfaceregion should be expanded to reach into the horizontal adjacent regions by 4. Then each surfaceregion should have an overlap of 8 units to one another. How could they got tiled without any overlap? :(
Or does this normally work and I have to search for the error elsewhere?

However, this boosted performance significantly over my last solution with the world reference. So I can't really rely on my old solution. So I really hope this works out.
 

Cervator

Project Lead and Community Wizard
Contributor
Design
Logistics
SpecOps
#17
#18
@Cervator Nice thanks! :)

uploaded my current versions to it. Now I only have to get rid of that annoying bug before I can continue.
Although I have some ideas where I want to go with it now. :)
I want to do something similar like the concept in No Man's Sky with more and more abstract and crazier terrains the farer away you get from spawn.
And maybe in the distant future making it more dangerous albeit more rewarding to get farther away.