Creating editable terrain advice

Hello,

I am new to using JME and have been doing a lot of reading into the basics, and specifically terrain and custom meshes. What I am looking to do is re-create something like this:

image

My first thought was having a water texture covering the whole map at 0,0,0 and then using a terrain that uses a heightmap to have the slope and then leading to the grass… however the terrain also has to be editable (only be able to add to it) which then leads me to custom meshes? Then how would I go about the slope? Make a custom vertex? How do I get the textures to join?

Just looking for some direction.

Plan to spend some time playing with simple custom meshes until you understand normals, texture coordinates, etc…

Make lots of throw-away test code. Learn a lot. Then come back to the problem with fresh eyes.

One place to start are the custom mesh tutorials. That will at least lead you to more specific questions.

So, I’ve had a play around and i’ve been able to create my own custom mesh (with squares) and I have code set up that can generate a grid of the squares, however I want to create an irregular island shape. Say…

This.

I don’t see it very practical to create shapes that match this. I’m not sure if custom meshes is the way to go? I need the terrain to be able to be added to. For example, if they were to place an object on the water’s edge, the island would expand by 1 block.

If you just need to change the heightmap (hills, lakes etc.) then you just need to edit the heightmap.

Grass, on the other hand, is a different can of worms…

Research terrain generation algorythms. Perlin noise is what’s called “organic noise” in that instead of it giving random numbers that are vastly different (which would result in a very spikey terrain), it slowly moves from one to another in more of a curve.

Using two-dimensional perlin (or any organic noise such as simplex) noise, you would query the algorythm in an x,z pattern, and use the resulting number as the height.

Using your custom mesh generator, give each vertex the x,z co-ordinates you gave the algorythm, and set the Y co-ordinate to the given result.

e.g.

float height = perlinGen.getNoise(x, z);
Vector3f vertex = new Vector3f(x, height, z);

You can then create meshes side-by-side that will match perfectly (cough normals at edges cough).

For caves, the fastest way I have come across is posterization. Use another instance of the noise generator with a different seed (or even offset the coordinates sufficiently so that it “fakes” it) and blend the results together.

For completeness, I’ve posted this before somehere, but I find it’s short but precise description is exactly what you would like to know.

Thanks for your reply, I appreciate it and I learned a few useful things! However, the island I am creating is completely flat (with no lakes/rivers/etc) apart from the edges that drop into the water. See the image above.

I’ve looked into using a circular mask over the noise, however that also leads me to having breaks in the island itself. I have done quite a bit of searching, but can’t find anything that quite suits my needs.

Will you generate your island all at once?

The nice thing about noise based algorithms is that you can (generally) go to any part of the world and generate just that section from scratch.

However, if you are going to be generating your land all at once then there are other fractal subdivision algorithms that can work better/differently.

For example, take a quad… divide each side in half and displace it randomly against that side’s normal. Now you have an odd 8 sided figure. Do it to each of those sides… and again… and again… eventually you will have something that looks island shaped.

Adding to it can be done similarly by slicing into the ring, adding some long sides and subdividing them the same way.

1 Like

Yeah there are loads of ways. A simple way is to use the dist function of the vector class. If you have a 33x33 piece of land, use the distance from the center (16,16) and normalize it to reduce the noise.

// pseudo code.
int size = 33; // the size of your mesh in vertices.
Vector2f center = new Vector2f(16, 16);

for (int x = 0; x < size; x++) {
    for (int z = 0; z < size; z++) {

        Vector2f vertex = new Vector2f(x, z);

        float dist = FastMath.abs(vertex.distance(size));
        dist = 1.0f - (size.x / dist); // normalize the result.

        float noise = noiseGen.getNoise(x, z) * dist;

        Vector3f vertexPos = new Vector2f(x, noise, z);

    }
}

Hopefully you can “see” the code, but the dist function makes a “circle” from the center and reduces the noise depending on how far it is. You can apply some kind of sine function to it for a smoother effect.

// after normalization
float angle = dist * FastMath.HALF_PI;
angle += FastMath.HALF_PI;
float newDist = FastMath.sin(angle);

or something… It’s still early over here. I need more caffeine.

@Jayfella

Using this method, I seem to get a (still) square, yet mildly bumpy island. It should be flat with a mild slope around the edges.

I hope I implemented it correctly:

for (int z = 0; z < size; z++) {
        for (int x = 0; x < size; x++) {
            Vector2f vertex = new Vector2f(x, z);

            //0,0 is the midpoint
            float dist = FastMath.abs(vertex.distance(new Vector2f(0, 0)));
            dist = 1.0f - (50 / dist); // normalize the result.

            // after normalization
            float angle = dist * FastMath.HALF_PI;
            angle += FastMath.HALF_PI;
            float newDist = FastMath.sin(angle);

            float noise = (float) noiseGen.eval(x, z) * newDist;

            islandData.vertices[vertexIndex] = new Vector3f(topX + x, noise, topZ - z);
            islandData.texture[vertexIndex] = new Vector2f(x / (float) size, z / (float) size);

            //Only add triangles where appropriate
            if (x < size - 1 && z < size - 1) {
                islandData.addTriangle(vertexIndex, vertexIndex + size + 1, vertexIndex + size);
                islandData.addTriangle(vertexIndex + size + 1, vertexIndex, vertexIndex + 1);
            }

            vertexIndex++;
        }
    }

You want a 2D effect, though, right?

…so you should use a 2D algorithm like I described.

Even if you want bumps on that, it’s the best place to start if you want to guarantee a single contiguous land mass.

Paul talks sense. But to answer your question, the noise gives a normalized output. You must multiply it with a desired height to get some altitude. Multiplying the X and z plane by say .1 of the coordinate will reduce change and stretch the noise out, and multiplying height gives depth of change to your mesh.

Cool, so I’ve been doing a bit more searching, and I found this: https://www.redblobgames.com/maps/terrain-from-noise/

Seems to show what I am looking for.

The only issue now is making the island bigger (more vertices), as if I make it too big I get an OutOfMemory exception. Going from there, I would have to add some sort of character, split the island into chunks, then only render the chunks that the character can view. Right?

Any JME resources on that?

Sure. There are others too…

And to make a nice world…