Procedural Terrain on a Planet

I am hoping to create a space-orientated sandbox game. Now I do have a rather interesting question. How do I make a procedural terrain generated on a planet (sphere) which a person can fly down to. At the moment, space-to-planet transitions don’t bother me, and I don’t mind if the terrain is seen from space, I can add Terrain LOD’s and what-not later. I am asking, at the moment is. How would I go about procedurally generating terrain (using perlin noise). Then somehow wrapping this around a sphere? I can’t use the six-side cube trick method, because my game will be multiplayer, so other people will need to see the planet, etc. Plus you need to be able to fly down into the planet.

So, ideas, suggestions? Anything is greatly appreciated.

I found this answer quite a while back. It involves the LibNoise port:

http://forum.unity3d.com/threads/68764-LibNoise-Ported-to-Unity

OK, first, the difference between Mathf.PerlinNoise to LibNoise:

Mathf.PerlinNoise:
2d noise
ranges from 0 to 1

LibNoise:
3d noise
ranges from -1 to 1

Now, how to make a planet:

Start with a cube Each side of a cube is flat, right. However, it is made of points in 3d space. You can spheriphy these points. (point.normalized * radius)

Now you have the basics of a sphere, but with the gridding of a cube. For every 3d point on the sphere where the cube matches, get a 3d Perlin Noise using LibNoise. Then simply add this to the equation. (point.normalized * (radius + noise(point * size) * depthOfNoise))

1 Like

Hey hey. I’m working on a proceduraly generated space sim also, and although I’m not tackling the issue of terrain generation there’s still likely some stuff on my blog which you might find useful. In particular you might want to read the stuff about quad sphere generation and mapping which could be used as a starting point for your terrain generation. Check it out here:

http://forbiddenfunction.com/main/?cat=11

or take a look in my sig.

Very cool background generator, it’s basically a shader which creates the background, or is it true texture maps?

Cheers. Its a little of both. I pre-generate a bunch of high resolution noise maps containing many octaves and pack them into the channels of a bunch of textures in a offline process. This is done offline since it takes a long time to generate. Then in game when a new spacebox is required, I generate some low res low octave noises on the fly which only take a tiny fraction of the time to generate and use these as various blending and mixing factors for the shader which then turns the pre-generated high res noises into space scapes. Doing it this way I get high quality results and a different space-scape each time re-using the same high res noise maps over and over with a generation time of under a second.

I will have to tinker with it and probably pick ur brain on the blog… lol

I got my old 4D Simplex Noise Library I got way back. I found it more efficient and more effective than Perlin when I used it in a 3D cube-environment scenario. It also has seamless capability which, I think will help. Hopefully its good for what I am hoping to achieve.

Ok, so how would I got about this? Do I have the cube already, and modify the mesh or something? Or do I destroy the mesh, rebuild it, then re-render the object. I think the former is what you mean, and the latter would be more difficult. How would I go about modifying the cubes mesh to achieve what you described?

Edit:

I did, come up with this:

vertices = vertices.normalized * (50 + noise.Noise(vertices_.normalized * 100));
1) dont add the spherify to the vertices. :wink:_

2) As I thought, you need the 3d position of the noise in spherical proportion. (* 100 would be the scale of the noise, you may want to start smaller, like 1.0 or less)

This thread is just what the doctor ordered. I’d contribute but all the useful bits have already been said. I’ll just sit here and watch for important information. :slight_smile:

woops, sorry. Its more like this:

var pos =vertices[i].normalized * 100;
var noise : IModule = new Billow(); // or whatever noise you want to use

vertices[i] = vertices[i].normalized * (50 + noise.GetValue(pos.x, pos.y, pos.z));

All the noise’s extend IModule. so if you check it, it only has one method: GetValue(x,y,z)

Remember to put the libnoise into your Plugins folder so that JS can see it correctly.

Ok, this is what I got:

You are using a cube with 24 points… They are all in the corners. So making it into a sphere will only make it a cube.

Go into Max, or whatever 3d program and make a cube with 32 length, width and height segments. This will give you far more points to “spherify”

Indeed, you need to increase the subdivisions of your cube. One other thing though, although simply normalising all the verts of your cube will result in a sphere, you’ll find that doing it this way will result in a higher density of verts on your sphere where the cubes corners used to be and they’ll be more spread out else where. This will results in an uneven texture resolution distribution and texture warping.

Another way to do it that will result in a more even vertex distribution is to use the mapping which can be found here:

1 Like

So… in thoery… if you use a rotational value of 45 + x/numPoints * 90, you will get a number between 45 and 135 based on a angle of the number of points that you get. Calculate your Y angle and X angle and apply them thusly:

			var s = (45 + x/numPoints * 90);
			var t = (45 + y/numPoints * 90);
			
			var r = Quaternion.Euler(s,t,0);
			var p = r * Vector3.up * radius;

Would essentially do the same thing as whatever the math is on that page… LOL, sorry I am not a good math transcriptionist.

Ok, I have done two versions, a 32-vert and a 64-vert. I.e higher resolution, lower resolution.

The code generated hemispheres, so I instantiated the original, parented it, then flipped it to fit underneath. For some reason, the two hemisphere connecting create a strange mesh tearing sort of thing at the equator.

I may have to play around with the noise, I am not 100% happy with it at the moment, but it’s coming along.

Here’s a screenshot:
(32 Vert is on the left, 64 Vert is on the right)

863902--32244--$Screenshot.jpg

Yes, I noticed that the mesh is more dense at the poles, whilst less dense at the equator.

So how exactly do I go about implementing this?

This is the full code I have at the moment:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LibNoise.Unity;
using LibNoise.Unity.Generator;
using LibNoise.Unity.Operator;

public class TerrainGenerator : MonoBehaviour {
	
	public int resolution = 512;
	public int octaves = 5;
	public bool seamless = true;
	public float frequency = 0.3f;
	public float amplitude = 5.0f;
	private Perlin noise;
	
	void Start () {
		if (gameObject.name.EndsWith("_Orig")) {
			noise = new Perlin();
			Mesh mesh = GetComponent<MeshFilter>().mesh;
	        Vector3[] vertices = mesh.vertices;
			
			var i=0;
			
			
	        while (i < vertices.Length) {
				Vector3 pos = vertices[i].normalized * 200;
				vertices[i] = vertices[i].normalized * (float)(100 + noise.GetValue(pos.x, pos.y, pos.z) * 2);
				i++;
	        }
	        mesh.vertices = vertices;
			mesh.RecalculateNormals(); 
			mesh.RecalculateBounds();
		
			Transform Hemisphere = Instantiate(transform) as Transform;
			Hemisphere.parent = transform;
			Hemisphere.Rotate(new Vector3(0, 180, 180));
		}
	}
}

The planet is coming a long nicely, any suggestions or things that should be changed/added?

EDIT:

Is there anyway to make it create a full sphere? I was just wondering, because applying a texture to fit over the whole thing would be hard (since its broken into two hemispheres). Plus trying to do shading, or whatever.

Ok, so I have interpreted the math of the cube to sphere mapping article.
Thanks voidstar <3

This is the math I got:

float sx = pos.x * Mathf.Sqrt(1.0f - pos.y * pos.y * 0.5f - pos.z * pos.z * 0.5f + pos.y * pos.y * pos.z * pos.z / 3.0f);
float sy = pos.y * Mathf.Sqrt(1.0f - pos.z * pos.z * 0.5f - pos.x * pos.x * 0.5f + pos.z * pos.z * pos.x * pos.x / 3.0f);
float sz = pos.z * Mathf.Sqrt(1.0f - pos.x * pos.x * 0.5f - pos.y * pos.y * 0.5f + pos.x * pos.x * pos.y * pos.y / 3.0f);
Vector3 p = new Vector3(sx,sy,sz);

Now, currently, this is my code altogether at the moment:

			Debug.Log(vertices[1].normalized);
			Debug.Log(vertices[1]);
			
	        while (i < vertices.Length) {
				Vector3 pos = vertices[i];
				
				float sx = pos.x * Mathf.Sqrt(1.0f - pos.y * pos.y * 0.5f - pos.z * pos.z * 0.5f + pos.y * pos.y * pos.z * pos.z / 3.0f);
				float sy = pos.y * Mathf.Sqrt(1.0f - pos.z * pos.z * 0.5f - pos.x * pos.x * 0.5f + pos.z * pos.z * pos.x * pos.x / 3.0f);
				float sz = pos.z * Mathf.Sqrt(1.0f - pos.x * pos.x * 0.5f - pos.y * pos.y * 0.5f + pos.x * pos.x * pos.y * pos.y / 3.0f);
				Vector3 p = new Vector3(sx,sy,sz);
				
				vertices[i] = vertices[i] + p * 50;
				i++;
	        }
	        mesh.vertices = vertices;
			mesh.RecalculateNormals(); 
			mesh.RecalculateBounds();

Now for some reason, this is doing nothing. The cube does not make any noticeable changes, besides the change in size due to my * 50.

I have noticed something very strange.

Debug.Log(vertices[1].normalized);
Debug.Log(vertices[1]);

I added these in to do some debugging. The normalized vertices return a value (0, -0.7, 0.0) while the vertices just ALWAYS return (0.0,0.0,0.0).

Is this supposed to be happening? Or is something wrong.

EDIT:
Apparently it has something to do with my models. I am exporting from 3DsMax 2009. Using a .max file. But Unity doesn’t recognize any of the vertex positions correctly. They all appear as vector.zero.

HOWEVER

If I export into .obj the vertex positions are recognized. Except the normalized method causes the cube to deform into a sort of two-sided paper-like plane thing.

And the sphere mapping (even vertex distribution) - using the code above - doesn’t do anything to the cube.

I’ll attach my model file. (Both .max and .obj)

867743–32375–$PlanetCube64.rar (261 KB)

Any ideas on whats wrong?

OK, after more than a few hours or tinkering I finally figured it out. now mind you, I am not using a premade cube, I am generating one. (see the attachment)

OK, here is the deal. lets say you are making a cube with 8 segments per side. That is 6 sides, 8 segments each and 9x9 verts to make it. You do this by generating a cube. X, Y and Z are made up when you describe the direction of the side. Forward is positive Z, and X and Y are controlled by the grid creator, Up is positive Y and X and Z are controlled by the grid. (and so on)

Now, I did everything at 1 unit scale, so all of my values ranged from -0.5 to 0.5. So what I ended up with was a neat grid in each location of my cube.

If you want to create your own mesh… here is where you then start:

OK, Spherifying is this exact formula:

point = point.normalized

Thats it. It makes a Unit Sphere (a sphere 2 units across)

To make it into a radius… simply multiply it times the radius you need.

To make it “noisey” first, get the noise value based on two aspects. First, is the original point (point.normalized) and multiply that by the noiseScale. Now, simply multiply it times the noiseAmount and add the radius.

fin = radius + noise(x * noiseScale,y * noiseScale,z * noiseScale) * noiseAmount

Noise scale refers to the unit noise scale you are gathering from the modifier The bigger the number, the smaller the noise. Noise amount refers to the amount of noise that will appear on the surface.

OK, now here is where we have our trouble. The final result of a “normal” cube with segments is that the edges are compressed because there is nothing there to absorb the deformation from the spherification process. So the middle points, are closer to the sphere than the outer points. And so, move less. The ourter points are compressed to match the sphere.

Now, the mathematical formula that has been provided here, does not work. As a matter of fact it is a spherification formula. You actually have more than a few factors that go into modding out. I wound up tinkering with many different formulas, trying to use Sin or Cos to gather up the nodes, none of it worked. What I eventually did was to go back to an old standby. An AnimationCurve! This handy little gadget allows you to play with numbers and convert them into a curved representation of themselves. In this case, I had a series of numbers that were from -0.5 to 0.5, so all I had to do was to use my AnimationCurve and get a new X or Y that would stretch certain parts out, making them more compatible with my needs.

The AnimationCurve that I used is attached. :wink:

And no, the previous method that I suggested, never worked. :frowning:

So, as you can see by the attachments, it is rather flexible. I am sure it could be made better though. :wink:



The code I interpreted from that math, does infact work. However, to get it to work, it requires that the vertex’s be in certain positions.

I.e -1.0 to 1.0

I ended up creating a mesh in unity, as my high-res 32 subdivided mesh would become too trivial to make it manually in code. I mean who wants to assign 6936 verts manually :smile:

I did it in Blender, and got fantastic results. I positioned it perfectly so the vertex positions are scaled to 1. Putting them in positions of -1.0 to 1.0.

I incorporated a function to switch between the Normalized method and the mathematical method.
I have found that the normalized version has more noise, than that of the mathematical method.

I’ve been playing around with noise types, and my favorite so far is RiggedMultifractal.

Here are two screenshots, comparing the EXACT same parameters but one uses the Normalized method, and one doesn’t.

Normalized Method:

869587--32461--$Screenshot2.jpg

Non-Normalized Method:

869587--32462--$Screenshot1.jpg

I personally think the latter looks nice.
Opinions?

“non-normalized” is this just adjusting the vertex x,y,z according to noise?

Well, it isnt really that hard to generate grids and triangles and stuff like that.

Yay demo:

http://lod3dx.net/Unity/Planetoid.html

Also, check into anything you can find about Spore’s planet creation… good read.