Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualSelenaut

Posted 28 November 2012 - 11:56 AM

Since I'm going to be having the view act similarly to Dwarf Fortress, kind of like bird's-eye, moving the player and moving the camera are essentially the same thing. The reason I'd like to rotate the land around the player is to prevent confusion at the wrapping edges.

So, to recap so far: Squares don't make spheres; I'm going to need a LOT more help trying to figure out how to even begin wrapping something like this; and 2D objects projected to 2D planes is nigh impossible.

Hm.

I have been thinking on and off about this all day; perhaps I could create two circles and wrap those, but the problem is loss of precision near the equator, and much more noise towards the poles. Is it possible to create an equidistant grid of sorts on a circle?

Also:

I think the cleanest thing to do for planet-wide terrain generation in a game is to impose any mesh you want on the sphere (I would start with a cube map)...

The provlem with making a cube UV is the wrapping mechanics of all of the edges. Also, I'd have to generate each face independently, and stitch them together, since the resulting UV shape isn't rectangular.

and then use 3D noise to generate elevation.

What do mean by 3D Perlin noise? I'm completely familiar with the concept, but I'm confused as to how I would use it in this circumstance.

For example, go look at the earth's atlas. When you said that wrapping around from the south pole gets you to the north pole, that's wrong.

I know this. That's why I'm having my problem. The land I'm generating looks like this. As you can see, it wraps in both the x and y direction; this may solve any confusion as to what exactly I meant by wrapping. If any of you are familiar with Java (I'm assuming so), here's the code for generating this:
import java.util.Random;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.*;
import javax.imageio.ImageIO;
public class Perlin {
    static int p = 8;
    static int size = (int)Math.pow(2,p)*4; //Multiply this by any power of 2 to get a good size image; you may be able to use other numbers, but I wouldn't reccomend it
    static int h = 0;
    public static void main(String[] args) throws IOException {
	    Random rand = new Random();
	    BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
	    WritableRaster raster = image.getRaster();
	    int[][] height = new int[size][size];
	    int a = 0, b = 0, c = 0, d = 0, highest = 0, lowest = -1;
	    for(int i = p-1; i > 0; i--){
		    int range = (int)Math.pow(2,i);
		    int arraySize = size/range;
		    int[][] current = new int[arraySize][arraySize];
		    for(int pointx = 0; pointx < arraySize; pointx++){
			    for(int pointy = 0; pointy < arraySize; pointy++){
				    current[pointx][pointy] = rand.nextInt(range); //Getting interpolation points; array gets more precise but less influential with each iteration
			    }
		    }
		    for(int x = 0; x < size; x++){
			    for(int y = 0; y < size; y++){
				    int left = (x/range)%(size/range); //Getting corners; automatically wraps both horizontally and vertically using the modulus method
				    int right = (x/range + 1)%(size/range);
				    int up = (y/range)%(size/range);
				    int down = (y/range + 1)%(size/range);
				    a = current[left][up]; //Setting corners
				    b = current[right][up];
				    c = current[left][down];
				    d = current[right][down];
				    h = (int)cosineInterpolate(cosineInterpolate(a, b, ((x%range)*1.0)/range), cosineInterpolate(c, d, ((x%range)*1.0)/range), ((y%range)*1.0)/range); //interpolates between the closest boundaries by interpolating horizontally on the top and bottom, then interpolating vertically
				    height[x][y] += h;
			    }
		    }
		    for(int x = 0; x < size; x++){ //Used to correct the contrast
			    for(int y = 0; y < size; y++){
				    if(height[x][y] > highest){
					    highest = height[x][y];
				    }
				    if(height[x][y] < lowest || lowest < 0){
					    lowest = height[x][y];
				    }
			    }
		    }
	    }
	    highest -= lowest; //Used to correct the contrast
	    for(int x = 0; x < size; x++){
		    for(int y = 0; y < size; y++){
			    height[x][y] -= lowest; //Used to correct the contrast
		    }
	    }
	    lowest -= lowest; //Used to correct the contrast
	    for(int x = 0; x < size; x++){
		    for(int y = 0; y < size; y++){
			    int n = (int)(((height[x][y]*1.0)/highest)*255); //Correcting the contrast
			    int[] green = {0, n, 0};
			    int[] blue = {0, 0, n};
			    int[] yellow = {n, n, 0};
			    if(height[x][y] > 128){
				    raster.setPixel(x, y, green);
			    }
			    else if(height[x][y] < 128){
				    raster.setPixel(x, y, blue);
			    }
			    else{
				    raster.setPixel(x, y, yellow);
			    }
		    }
	    }
	    File file = new File("perlinTest.png");
	    ImageIO.write(image, "png", file);
    }
    public static double cosineInterpolate(double a, double b, double x){ //Interpolates between the two specified points at a fraction x from 0-1
double ft = x * Math.PI;
double f = (1 - Math.cos(ft)) * 0.5;
return  a*(1-f) + b*f;
    }
}

Run that yourself, see if that gives you any ideas; I'll keep working on how I want to wrap it.

Thanks guys,

Selenaut

#2Selenaut

Posted 28 November 2012 - 11:56 AM

Since I'm going to be having the view act similarly to Dwarf Fortress, kind of like bird's-eye, moving the player and moving the camera are essentially the same thing. The reason I'd like to rotate the land around the player is to prevent confusion at the wrapping edges.

So, to recap so far: Squares don't make spheres; I'm going to need a LOT more help trying to figure out how to even begin wrapping something like this; and 2D objects projected to 2D planes is nigh impossible.

Hm.

I have been thinking on and off about this all day; perhaps I could create two circles and wrap those, but the problem is loss of precision near the equator, and much more noise towards the poles. Is it possible to create an equidistant grid of sorts on a circle?

Also:

I think the cleanest thing to do for planet-wide terrain generation in a game is to impose any mesh you want on the sphere (I would start with a cube map)...

The provlem with making a cube UV is the wrapping mechanics of all of the edges. Also, I'd have to generate each face independently, and stitch them together, since the resulting UV shape isn't rectangular.

and then use 3D noise to generate elevation.

What do mean by 3D Perlin noise? I'm completely familiar with the concept, but I'm confused as to how I would use it in this circumstance.

For example, go look at the earth's atlas. When you said that wrapping around from the south pole gets you to the north pole, that's wrong.

I know this. That's why I'm having my problem. The land I'm generating looks like this. As you can see, it wraps in both the x and y direction; this may solve any confusion as to what exactly I meant by wrapping. If any of you are familiar with Java (I'm assuming so), here's the code for generating this:
import java.util.Random;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.*;
import javax.imageio.ImageIO;
public class Perlin {
    static int p = 8;
    static int size = (int)Math.pow(2,p)*4; //Multiply this by any power of 2 to get a good size image; you may be able to use other numbers, but I wouldn't reccomend it
    static int h = 0;
    public static void main(String[] args) throws IOException {
	    Random rand = new Random();
	    BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
	    WritableRaster raster = image.getRaster();
	    int[][] height = new int[size][size];
	    int a = 0, b = 0, c = 0, d = 0, highest = 0, lowest = -1;
	    for(int i = p-1; i > 0; i--){
		    int range = (int)Math.pow(2,i);
		    int arraySize = size/range;
		    int[][] current = new int[arraySize][arraySize];
		    for(int pointx = 0; pointx < arraySize; pointx++){
			    for(int pointy = 0; pointy < arraySize; pointy++){
				    current[pointx][pointy] = rand.nextInt(range); //Getting interpolation points; array gets more precise but less influential with each iteration
			    }
		    }
		    for(int x = 0; x < size; x++){
			    for(int y = 0; y < size; y++){
				    int left = (x/range)%(size/range); //Getting corners; automatically wraps both horizontally and vertically using the modulus method
				    int right = (x/range + 1)%(size/range);
				    int up = (y/range)%(size/range);
				    int down = (y/range + 1)%(size/range);
				    a = current[left][up]; //Setting corners
				    b = current[right][up];
				    c = current[left][down];
				    d = current[right][down];
				    h = (int)cosineInterpolate(cosineInterpolate(a, b, ((x%range)*1.0)/range), cosineInterpolate(c, d, ((x%range)*1.0)/range), ((y%range)*1.0)/range); //interpolates between the closest boundaries by interpolating horizontally on the top and bottom, then interpolating vertically
				    height[x][y] += h;
			    }
		    }
		    for(int x = 0; x < size; x++){ //Used to correct the contrast
			    for(int y = 0; y < size; y++){
				    if(height[x][y] > highest){
					    highest = height[x][y];
				    }
				    if(height[x][y] < lowest || lowest < 0){
					    lowest = height[x][y];
				    }
			    }
		    }
	    }
	    highest -= lowest; //Used to correct the contrast
	    for(int x = 0; x < size; x++){
		    for(int y = 0; y < size; y++){
			    height[x][y] -= lowest; //Used to correct the contrast
		    }
	    }
	    lowest -= lowest; //Used to correct the contrast
	    for(int x = 0; x < size; x++){
		    for(int y = 0; y < size; y++){
			    int n = (int)(((height[x][y]*1.0)/highest)*255); //Correcting the contrast
			    int[] green = {0, n, 0};
			    int[] blue = {0, 0, n};
			    int[] yellow = {n, n, 0};
			    if(height[x][y] > 128){
				    raster.setPixel(x, y, green);
			    }
			    else if(height[x][y] < 128){
				    raster.setPixel(x, y, blue);
			    }
			    else{
				    raster.setPixel(x, y, yellow);
			    }
		    }
	    }
	    File file = new File("perlinTest.png");
	    ImageIO.write(image, "png", file);
    }
    public static double cosineInterpolate(double a, double b, double x){ //Interpolates between the two specified points at a fraction x from 0-1
double ft = x * Math.PI;
double f = (1 - Math.cos(ft)) * 0.5;
return  a*(1-f) + b*f;
    }
}

Run that yourself, see if that gives you any ideas; I'll keep working on how I want to wrap it.

Thanks guys,

Selenaut

#1Selenaut

Posted 28 November 2012 - 11:55 AM

Since I'm going to be having the view act similarly to Dwarf Fortress, kind of like bird's-eye, moving the player and moving the camera are essentially the same thing. The reason I'd like to rotate the land around the player is to prevent confusion at the wrapping edges.

So, to recap so far: Squares don't make spheres; I'm going to need a LOT more help trying to figure out how to even begin wrapping something like this; and 2D objects projected to 2D planes is nigh impossible.

Hm.

I have been thinking on and off about this all day; perhaps I could create two circles and wrap those, but the problem is loss of precision near the equator, and much more noise towards the poles. Is it possible to create an equidistant grid of sorts on a circle?

Also:

I think the cleanest thing to do for planet-wide terrain generation in a game is to impose any mesh you want on the sphere (I would start with a cube map)...

The provlem with making a cube UV is the wrapping mechanics of all of the edges. Also, I'd have to generate each face independently, and stitch them together, since the resulting UV shape isn't rectangular.

and then use 3D noise to generate elevation.

What do mean by 3D Perlin noise? I'm completely familiar with the concept, but I'm confused as to how I would use it in this circumstance.

For example, go look at the earth's atlas. When you said that wrapping around from the south pole gets you to the north pole, that's wrong.

I know this. That's why I'm having my problem. The land I'm generating looks like this. As you can see, it wraps in both the x and y direction; this may solve any confusion as to what exactly I meant by wrapping. If any of you are familiar with Java (I'm assuming so), here's the code for generating this:
package perlin;
import java.util.Random;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.*;
import javax.imageio.ImageIO;
public class Perlin {
    static int p = 8;
    static int size = (int)Math.pow(2,p)*4; //Multiply this by any power of 2 to get a good size image; you may be able to use other numbers, but I wouldn't reccomend it
    static int h = 0;
    public static void main(String[] args) throws IOException {
	    Random rand = new Random();
	    BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
	    WritableRaster raster = image.getRaster();
	    int[][] height = new int[size][size];
	    int a = 0, b = 0, c = 0, d = 0, highest = 0, lowest = -1;
	    for(int i = p-1; i > 0; i--){
		    int range = (int)Math.pow(2,i);
		    int arraySize = size/range;
		    int[][] current = new int[arraySize][arraySize];
		    for(int pointx = 0; pointx < arraySize; pointx++){
			    for(int pointy = 0; pointy < arraySize; pointy++){
				    current[pointx][pointy] = rand.nextInt(range); //Getting interpolation points; array gets more precise but less influential with each iteration
			    }
		    }
		    for(int x = 0; x < size; x++){
			    for(int y = 0; y < size; y++){
				    int left = (x/range)%(size/range); //Getting corners; automatically wraps both horizontally and vertically using the modulus method
				    int right = (x/range + 1)%(size/range);
				    int up = (y/range)%(size/range);
				    int down = (y/range + 1)%(size/range);
				    a = current[left][up]; //Setting corners
				    b = current[right][up];
				    c = current[left][down];
				    d = current[right][down];
				    h = (int)cosineInterpolate(cosineInterpolate(a, b, ((x%range)*1.0)/range), cosineInterpolate(c, d, ((x%range)*1.0)/range), ((y%range)*1.0)/range); //interpolates between the closest boundaries by interpolating horizontally on the top and bottom, then interpolating vertically
				    height[x][y] += h;
			    }
		    }
		    for(int x = 0; x < size; x++){ //Used to correct the contrast
			    for(int y = 0; y < size; y++){
				    if(height[x][y] > highest){
					    highest = height[x][y];
				    }
				    if(height[x][y] < lowest || lowest < 0){
					    lowest = height[x][y];
				    }
			    }
		    }
	    }
	    highest -= lowest; //Used to correct the contrast
	    for(int x = 0; x < size; x++){
		    for(int y = 0; y < size; y++){
			    height[x][y] -= lowest; //Used to correct the contrast
		    }
	    }
	    lowest -= lowest; //Used to correct the contrast
	    for(int x = 0; x < size; x++){
		    for(int y = 0; y < size; y++){
			    int n = (int)(((height[x][y]*1.0)/highest)*255); //Correcting the contrast
			    int[] green = {0, n, 0};
			    int[] blue = {0, 0, n};
			    int[] yellow = {n, n, 0};
			    if(height[x][y] > 128){
				    raster.setPixel(x, y, green);
			    }
			    else if(height[x][y] < 128){
				    raster.setPixel(x, y, blue);
			    }
			    else{
				    raster.setPixel(x, y, yellow);
			    }
		    }
	    }
	    File file = new File("perlinTest.png");
	    ImageIO.write(image, "png", file);
    }
    public static double cosineInterpolate(double a, double b, double x){ //Interpolates between the two specified points at a fraction x from 0-1
double ft = x * Math.PI;
double f = (1 - Math.cos(ft)) * 0.5;
return  a*(1-f) + b*f;
    }
}

Run that yourself, see if that gives you any ideas; I'll keep working on how I want to wrap it.

Thanks guys,

Selenaut

PARTNERS