Jme-World-Pager

Jme-World-Pager


Download

compile 'com.jayfella:jme-world-pager:1.0'

As part of the world-generation theme I’m working on, I’ve released the first part - the world pager.

The library builds an infinite world around a Vector3f location using the noise settings you input. It comes with a demonstration using my FastNoise library.

The pager is fully multi-threaded and comes with a HeightMapMesh that calculates edge normals for seamless terrain.

Below is an example of how to run the example in the screenshot below. (Also available here)

package com.jayfella.jme.worldpager;

import com.jayfella.jme.worldpager.world.AbstractWorldState;
import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.water.WaterFilter;

public class Main extends SimpleApplication {

    public static void main(String... args) {
        Main main = new Main();
        main.start();
    }

    private AbstractWorldState world;

    @Override
    public void simpleInitApp() {

        // set the sky to a nice blue
        viewPort.setBackgroundColor(new ColorRGBA(0.5f, 0.6f, 0.7f, 1.0f));

        // move about a bit quicker.
        flyCam.setMoveSpeed(100);

        // add some light
        DirectionalLight directionalLight = new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal());
        rootNode.addLight(directionalLight);

        rootNode.addLight(new AmbientLight(ColorRGBA.White.mult(0.2f)));

        // create our world.
        String worldName = "TestWorld";
        int seed = 123;
        int nThreads = 3;

        world = new BasicWorldState(worldName, seed, nThreads);
        stateManager.attach(world);


        // an an ocean.
        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
        WaterFilter waterFilter = new WaterFilter(rootNode, directionalLight.getDirection());
        waterFilter.setWaterHeight(8);
        fpp.addFilter(waterFilter);
        viewPort.addProcessor(fpp);
    }

    @Override
    public void simpleUpdate(float tpf) {
        super.simpleUpdate(tpf);

        world.setFollower(cam.getLocation());
    }

}

The “how to” of it is in the file below. It shows where the noise is generated, how a grid is added and how to set the cell size for each chunk of terrain, how to set the view distance, etc.

https://github.com/jayfella/jme-world-pager/blob/master/src/main/java/com/jayfella/jme/worldpager/BasicWorldState.java

As this is developed over the next few weeks I’ll be adding vegetation and collision systems - so you can create the worlds you may have seen in my tech demo videos.

As always, the source code is available on github.

https://github.com/jayfella/jme-world-pager

18 Likes

That’s looking awesome. I’m liking the shoreline & water details.

I was working on similar about a year or two ago on a larger/distant scale (i.e. orbital/space distances). I’ve been considering reviving/rebuilding that project and OSing the improved version. Seeing this, I wonder if they could be integrated so it switches to world-pager once altitude gets low enough. In some ways it’d simplify things at the macro scale since I could drop the Bullet stuff. I was using background threads to dynamically initialize collision shape chunks w/Bullet at the bottom layer of the quadtree… :crazy_face: which works well enough, but I’d rather try a simpler approach which is a little less resource intensive.

Are your plans for this to stay mostly “grounded” and just polish that up nicely (blend more ground textures, reduce popping, lod, etc.), or were you going to have it support seamless transitions to space eventually?

i think the transitioning from a sphere to a flat land is more difficult than it seems in my head. I’ll say “probably not” but there’s no reason why - it makes meshes from noise - it can be done. A six sided sphere and all that story. I can’t see why it wouldn’t work.

I think it helps if you’re making that game, too. I’ve never really focused a lot on space, though a lot of other people have.

Yeah, no doubt that one’s tough, but I’m just dumb enough to consider making an attempt at it. :rofl:

My old project (which I think I want to rebuild at least partially) was exactly what you describe - a 6 sided cube blown up into a sphere. I should try and get a decent video that doesn’t compress it to crap for a change…

1 Like

This project looks awesome! The opening of the store brought my attention back to this. :slight_smile:

I’d love to use it in my project, and I have a couple of questions regarding extremely large worlds. My project allows practically infinite worlds - the world is split into “zones” 2x2x2 km on a side and objects are placed within the zones. Each zone is a normal “scene” in jME terms, with coordinates in 32-bit floating point - so an object’s “global” coordinates are [zone coordinate]:[floating point intra-zone coordinate]. Once you hit the edge of a zone, the floating point coordinates reset to the local coordinate system of the next zone to preserve accuracy. Zone coordinates are stored as longs, and range from +/- Long.MAX_VALUE, making the total possible world size Long.MAX_VALUE * 4 km.

Obviously, you don’t have to go very far from the global origin until anything done in 32-bit floating point starts to break down pretty badly unless it’s re-centered around the zone’s local coordinate system.

This is the part I’m wondering about. Can I “re-center” this generation origin point within each consecutive zone and maintain seamless world generation across zones?

1 Like

I see what you’re saying. You want to “conveyor belt” the world and in essence stay at zero. In this instance, add the world to a node and move that node, giving the world pager the negated position.

So when “you” move forward, the node moves in the opposite direction ( * -1 or .negate()), and you feed the pager the opposite of that.

Yes, although my question is more along the lines of dealing with generating terrain at extremely large global offsets - will the noise remain stable and “well-behaved” if it’s fed a very large offset (for example, an offset of magnitude 187877234 from center)?

let me give it a whirl.

Thanks! :smiley:

I’m not even sure if what I’m talking about works well with classic noise algorithms - I’m thinking something like this might require the ability to set boundary conditions at the edges (similar to DE/PDE solvers). Not sure how that would work out mathematically, although it seems like it should be possible - each noise value would have a requirement on the values of its neighbors, but it seems like there should be a way to reformulate typical noise algorithms to do this.

Well I set the Z position of the noise generator to 1878772323232324f and it appeared to generate a noise texture just fine, so I presume the noise generation for terrain would be the same.

The noise generator isn’t my inception, it’s actually a direct port of this. I decided on this one because it appears to create almost all the noise one would want.

1 Like

Thanks! :smiley:

I’ll proceed with a test on my project and see how it goes. Thanks for sharing this open source - really looking forward to working with this.

Hi, I think that the GitHub link may be broken on here and the JME Store. Can somebody link the right ones?

1 Like

i belive this might be it:

1 Like

There are at least 2 other surviving forks: