Jump to content

  • Log In with Google      Sign In   
  • Create Account

Island Generation -- Problem with Duplicates


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
17 replies to this topic

#1 Riztro   Members   -  Reputation: 240

Like
0Likes
Like

Posted 27 December 2012 - 12:09 PM

Hello all,

 

I have been working for the past few days on a perlin noise island generator (using libnoise). What I do is generate a terrain, and then apply an island mask to it.  I have added a seed to the island generation portion but I am getting similiar results each time even with a seed. Can someone help me so that I can generate a truely random island each time? Here is what I am currently getting (seeds in parenthesis):

 

(1233212)

vwxr8o.jpg

 

(999555857)

 

2434x9w.jpg

 

So, as you can see, the maps are very similar. I really don't know why. If needed, here is my code: 

(Steps I take)

1st Generate terrain

2nd Generate island mask

3rd Apply island mask to terrain

4th Draw the terrain

 

//Little program to generate test map with only 0 and 1 tile

#include <iostream>
#include <libnoise/noise.h>
#include "noiseutils.h"
#include <stdlib.h>
#include <string>

using namespace std;
using namespace noise;

int main()
{

   module::Perlin myModule;

   utils::NoiseMap heightMap;
   utils::NoiseMapBuilderPlane heightMapBuilder;
   heightMapBuilder.SetSourceModule (myModule);
   heightMapBuilder.SetDestNoiseMap (heightMap);
   heightMapBuilder.SetDestSize (512, 512);
   heightMapBuilder.SetBounds (2.0, 6.0, 1.0, 5.0);
   heightMapBuilder.Build ();

   
   string seed;
   int iseed;
   //Add support for character conversion to ints and clip string to 8 numbers
   cout << "Please enter a seed: ";
   getline(cin,seed);

   cout << seed << endl;
   iseed = atoi(seed.c_str());
   cout << iseed << endl;

   float islandMap[512][512];

   enum directions {LEFT = 0, UP, RIGHT, DOWN, NONE};

   for(int count = 0; count < 1; count++)
   {

      //Initialize values for a new map
      for (int i = 0; i < 512; i++) 
      {
         for (int j = 0; j < 512; j++) 
         {
            islandMap[j][i] = 0;
         }
      }


      //Choose a random location, travel in random directions
      int xRand = 0,yRand=0;
      int xPos = 0,yPos=0;

      srand((iseed*57)/(iseed*17));
      cout << iseed;

      xRand= rand()%512;
      yRand= rand()%512;

      xPos = xRand;
      yPos = yRand;

      islandMap[xRand][yRand] = 1;
      directions direction = NONE;

      srand((int)((iseed*iseed)/57));
      for (int i = 0; i < 10000000; i++) 
      {
         if(xPos == 511 || xPos == 0)
         {
            xPos = rand()%512;
            islandMap[xPos][yPos] +=1;
         }   

         if(yPos == 511 || yPos == 0)
         {
            yPos = rand()%512;
            islandMap[xPos][yPos] +=1;
         }

         int oldValue;

         oldValue = islandMap[xPos][yPos];

         int temp;
         temp = rand()%4;
         direction = (directions)temp;
         if(direction == LEFT)
         {
            xPos-=1;
         }
         else if(direction == UP)
            yPos-=1;
         else if(direction == RIGHT)
            xPos+=1;
         else if(direction == DOWN)
            yPos+=1;

         if(oldValue >= islandMap[xPos][yPos])
         {
            islandMap[xPos][yPos] +=1;
         }


      }

      //find max value for normalizing
      int max = 0;
      int min = 0;
      for (int i = 0; i < 512; i++) 
      {
         for (int j = 0; j < 512; j++) 
         {
            if(max < islandMap[i][j])
               max = islandMap[i][j];

            //cout << islandMap[i][j] << " ";

            if(min > islandMap[i][j])
               min = islandMap[i][j];
         }
      }
               

      //Multiply values of original by new maps generated
      for (int i = 0; i < 512; i++) 
      {
         for (int j = 0; j < 512; j++) 
         {
            float islandValue = (islandMap[i][j] - min) / (max-min);
            //cout << islandValue;
            float mapValue = (heightMap.GetValue(i,j) + 1) / (1+1);
            float newValue = (-1 + (2/1)*(islandValue*mapValue));
            heightMap.SetValue(i,j, newValue);
         }
      }
   }

   utils::RendererImage renderer;
   utils::Image image;
   renderer.SetSourceNoiseMap (heightMap);
   renderer.SetDestImage (image);
   renderer.ClearGradient ();
   renderer.AddGradientPoint (-1.0000, utils::Color (  0,   0, 255, 255)); // shallow
   renderer.AddGradientPoint (-0.9701, utils::Color (  0,   0, 255, 255)); // shallow
   renderer.AddGradientPoint (-0.9700, utils::Color (  0, 128, 255, 255)); // shore
   renderer.AddGradientPoint (-0.9690, utils::Color (  0, 128, 255, 255)); // shore
   renderer.AddGradientPoint (-0.9689, utils::Color (240, 240,  64, 255)); // sand
   renderer.AddGradientPoint (-0.9601, utils::Color (240, 240,  64, 255)); // sand
   renderer.AddGradientPoint (-0.9600, utils::Color ( 32, 160,   0, 255)); // grass
   renderer.AddGradientPoint (-0.4991, utils::Color ( 32, 160,   0, 255)); // grass
   renderer.AddGradientPoint (-0.4990, utils::Color ( 0, 0,   0, 255)); // pines
   renderer.AddGradientPoint (-0.4987, utils::Color ( 0, 0,   0, 255)); // pines
   renderer.AddGradientPoint (-0.3986, utils::Color (96, 63,   0, 255)); // dirt
   renderer.AddGradientPoint ( 0.0000, utils::Color (96, 63,   0, 255)); // dirt
   renderer.AddGradientPoint ( 0.0001, utils::Color (128, 128, 128, 255)); // rock
   renderer.AddGradientPoint ( 1.0000, utils::Color (128, 128, 128, 255)); // rock
   renderer.EnableLight ();
   renderer.SetLightContrast (3.0);
   renderer.SetLightBrightness (2.0);
   renderer.Render ();

   utils::WriterBMP writer;
   writer.SetSourceImage (image);
   writer.SetDestFilename ("tutorial.bmp");
   writer.WriteDestFile ();

   return 0;
}

 

Thankyou for your help in advance!! :D

 



Sponsor:

#2 SuperVGA   Members   -  Reputation: 1118

Like
5Likes
Like

Posted 27 December 2012 - 12:46 PM

Your seed is always the same... Always 57/17.
-What is the reason behind it, I wonder?

I'm actually puzzeld about your maps being the slightest different.
You're calling srand all time. -You should only be calling it once (it keeps the following numbers the same for every time it's invoked with the same seed. The behaviours you're experiencing is familiar to when i did it years ago.

#3 FLeBlanc   Crossbones+   -  Reputation: 3117

Like
4Likes
Like

Posted 27 December 2012 - 12:53 PM

To elaborate on SuperVGA, this line is the line that is fishy:

 

 

srand((iseed*57)/(iseed*17));

 

 

The iseed in the numerator is cancelled by the iseed in the denominator, causing the seed to always be 57/17, or 3, when the island mask is generated.


Edited by FLeBlanc, 27 December 2012 - 12:53 PM.


#4 Paradigm Shifter   Crossbones+   -  Reputation: 5433

Like
1Likes
Like

Posted 27 December 2012 - 01:01 PM

57/17 isn't 3, 51/17 is. Depends how big the seed is, and if it overflows or not. Calling srand more than once is dodgy anyway, in this circumstance. The bitmaps aren't the same though, they look slightly different. Only call srand more than once to repeat a previous random sequence.
"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#5 Blind Radish   Members   -  Reputation: 355

Like
1Likes
Like

Posted 27 December 2012 - 01:24 PM

I'd rebuild it, piece by piece.  That's obviously terrible advice, but its honestly what I would do.


Although I didn't look at your code, you might try this:
You might want to generate a constant perlin noise and a random location, instead of a random perlin noise and a constant location.

Also try adjusting the map maximums to some number which is coprime to the number you're using right now.  Avoid Mersenne numbers.  If that doesn't work, try again with a number coprime to both of those.  You might be generating a specific repeating pattern or something.  Well, no, the map would be offset I suppose.

Not sure.  Simplify and try to generate more basic structures.  Try to make those diverse.  Then add more depth.

Change each number one by one dude.  It's either a specific algorithm or a specific constant that's throwing you off.



#6 Bacterius   Crossbones+   -  Reputation: 9266

Like
0Likes
Like

Posted 27 December 2012 - 05:44 PM

57/17 isn't 3, 51/17 is. Depends how big the seed is, and if it overflows or not. Calling srand more than once is dodgy anyway, in this circumstance. The bitmaps aren't the same though, they look slightly different. Only call srand more than once to repeat a previous random sequence.

Actually, 57/17 = 3 here, since we're talking about integers and thus integer division. But well-spotted for the overflow - that's really the only reason why the maps are different. Don't know what the rationale behind those numbers was, though.


The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis


#7 MarkS   Prime Members   -  Reputation: 886

Like
1Likes
Like

Posted 27 December 2012 - 05:59 PM

I just got done playing with his code. I took out the multiple calls to srand (now a single call: srand(iseed);), the do nothing for loop and various other oddities ((2 / 1) ?). It now creates very regular terrains. The generated terrains show a very strong rotational symmetry. Each 1/4 of the image is nearly an exact copy of each other, rotated 90°. 

 

I think the entire algorithm needs to be rewritten.


Edited by MarkS, 27 December 2012 - 06:00 PM.


#8 TrickyLogic   Members   -  Reputation: 171

Like
3Likes
Like

Posted 27 December 2012 - 07:41 PM

The algorithm used looks like the same from: http://breinygames.blogspot.nl/2012/06/generating-terrain-using-perlin-noise.html

 

Just playing around a little (I did change some code so I could more easily read it), here is what I came up with:

//Little program to generate test map with only 0 and 1 tile

#include <iostream>
#include <noise/noise.h>
#include "noiseutils.h"
#include <stdlib.h>
#include <string>
#include <sstream>

using namespace std;
using namespace noise;

template <typename T> string tostring (T v) {
    ostringstream ss;
    ss << v;
    return ss.str();
}

void generate_island(int iseed) {
    module::Perlin myModule;

    myModule.SetSeed (iseed);
    utils::NoiseMap heightMap;
    utils::NoiseMapBuilderPlane heightMapBuilder;
    heightMapBuilder.SetSourceModule(myModule);
    heightMapBuilder.SetDestNoiseMap(heightMap);
    heightMapBuilder.SetDestSize(512, 512);
    heightMapBuilder.SetBounds(2.0, 6.0, 1.0, 5.0);
    heightMapBuilder.Build();

    float islandMap[512][512];
    srand(iseed);

    for (int count = 0; count < 1; count++ ){
        //Initialize values for a new map
        for (int i = 0; i < 512; i++) {
            for (int j = 0; j < 512; j++) {
                islandMap[j][i] = 0;
            }
        }

        //Choose a random location, travel in random directions
        int x = 0, y = 0;
        float previous = 0;

        for (int i = 0; i < 1000000; i++) {
            if(y == 511 || y == 0 || x == 511 || x == 0) {
                x = rand() % 512;
                y = rand() % 512;
            }   

            if(previous >= islandMap[x][y]) {
                islandMap[x][y] += 1;
            }

            previous = islandMap[x][y];

            switch(rand() % 4) {
                case 0:
                    x -= 1;
                    break;
                case 1:
                    y -= 1;
                    break;
                case 2:
                    x += 1;
                    break;
                case 3:
                    y += 1;
                    break;
                default:
                    break;
            }
        }

        //find max value for normalizing
        for (int i = 0; i < 512; i++) {
            for (int j = 0; j < 512; j++) {
                islandMap[i][j] = islandMap[i][j] * 2 - 1;
            }
        }

        int max = 0;
        int min = 0;
        for (int i = 0; i < 512; i++) {
            for (int j = 0; j < 512; j++) {
                if(max < islandMap[i][j]) {
                    max = islandMap[i][j];
                }

                if(min > islandMap[i][j]) {
                    min = islandMap[i][j];
                }
            }
        }

        //Multiply values of original by new maps generated
        for (int i = 0; i < 512; i++) {
            for (int j = 0; j < 512; j++) {
                float islandValue = (islandMap[i][j] - min) / (max - min);
                float mapValue = (heightMap.GetValue(i, j) + 1) / 2;
                float newValue = 2 * islandValue * mapValue - 1;
                heightMap.SetValue(i, j, newValue);
            }
        }
    }

    utils::RendererImage renderer;
    utils::Image image;
    renderer.SetSourceNoiseMap (heightMap);
    renderer.SetDestImage (image);
    renderer.ClearGradient ();
    renderer.AddGradientPoint (-1.0000, utils::Color (  0,   0, 255, 255)); // shallow
    renderer.AddGradientPoint (-0.9701, utils::Color (  0,   0, 255, 255)); // shallow
    renderer.AddGradientPoint (-0.9700, utils::Color (  0, 128, 255, 255)); // shore
    renderer.AddGradientPoint (-0.9690, utils::Color (  0, 128, 255, 255)); // shore
    renderer.AddGradientPoint (-0.9689, utils::Color (240, 240,  64, 255)); // sand
    renderer.AddGradientPoint (-0.9601, utils::Color (240, 240,  64, 255)); // sand
    renderer.AddGradientPoint (-0.9600, utils::Color ( 32, 160,   0, 255)); // grass
    renderer.AddGradientPoint (-0.4991, utils::Color ( 32, 160,   0, 255)); // grass
    renderer.AddGradientPoint (-0.4990, utils::Color ( 0, 0,   0, 255)); // pines
    renderer.AddGradientPoint (-0.4987, utils::Color ( 0, 0,   0, 255)); // pines
    renderer.AddGradientPoint (-0.3986, utils::Color (96, 63,   0, 255)); // dirt
    renderer.AddGradientPoint ( 0.0000, utils::Color (96, 63,   0, 255)); // dirt
    renderer.AddGradientPoint ( 0.0001, utils::Color (128, 128, 128, 255)); // rock
    renderer.AddGradientPoint ( 1.0000, utils::Color (128, 128, 128, 255)); // rock
    renderer.EnableLight ();
    renderer.SetLightContrast (3.0);
    renderer.SetLightBrightness (2.0);
    renderer.Render ();

    utils::WriterBMP writer;
    writer.SetSourceImage (image);
    writer.SetDestFilename ("tutorial" + tostring(iseed) + ".bmp");
    writer.WriteDestFile ();
}

int main() {
    for(int i=0; i<10; ++i){
        generate_island(i);
    }
    return 0;
}

 

 

 

Attached Thumbnails

  • tutorial0.png
  • tutorial1.png


#9 Riztro   Members   -  Reputation: 240

Like
0Likes
Like

Posted 27 December 2012 - 07:49 PM

Your seed is always the same... Always 57/17.
-What is the reason behind it, I wonder?

I'm actually puzzeld about your maps being the slightest different.
You're calling srand all time. -You should only be calling it once (it keeps the following numbers the same for every time it's invoked with the same seed. The behaviours you're experiencing is familiar to when i did it years ago.
To elaborate on SuperVGA, this line is the line that is fishy:

 

 

srand((iseed*57)/(iseed*17));

 

 

The iseed in the numerator is cancelled by the iseed in the denominator, causing the seed to always be 57/17, or 3, when the island mask is generated.

 

Thankyou for pointing that out! biggrin.png I have fixed that but now I am still getting similar maps.. :/. I am sure changing that helps though biggrin.png

 

I'd rebuild it, piece by piece.  That's obviously terrible advice, but its honestly what I would do.


Although I didn't look at your code, you might try this:
You might want to generate a constant perlin noise and a random location, instead of a random perlin noise and a constant location.

Also try adjusting the map maximums to some number which is coprime to the number you're using right now.  Avoid Mersenne numbers.  If that doesn't work, try again with a number coprime to both of those.  You might be generating a specific repeating pattern or something.  Well, no, the map would be offset I suppose.

Not sure.  Simplify and try to generate more basic structures.  Try to make those diverse.  Then add more depth.

Change each number one by one dude.  It's either a specific algorithm or a specific constant that's throwing you off.

I got lost at your third paragraph :/ Can you please elaborate on the thing that I should also try adjusting smile.png

 

I just got done playing with his code. I took out the multiple calls to srand (now a single call: srand(iseed);), the do nothing for loop and various other oddities ((2 / 1) ?). It now creates very regular terrains. The generated terrains show a very strong rotational symmetry. Each 1/4 of the image is nearly an exact copy of each other, rotated 90°. 

 

I think the entire algorithm needs to be rewritten.

Sorry yeah the (2/1) thing gets the numbers into the range of -1 and 1. The 1 in that equation is the max number in the set of numbers. And what algorithm needs to be rewritten, the island masking one? :/ Because if that is so, I have no clue what to do. I just followed what this guy said he did on his blog.

 

The algorithm used looks like the same from: http://breinygames.blogspot.nl/2012/06/generating-terrain-using-perlin-noise.html

 

Just playing around a little (I did change some code so I could more easily read it), here is what I came up with:


 

//Little program to generate test map with only 0 and 1 tile

#include <iostream>
#include <noise/noise.h>
#include "noiseutils.h"
#include <stdlib.h>
#include <string>
#include <sstream>

using namespace std;
using namespace noise;

template <typename T> string tostring (T v) {
    ostringstream ss;
    ss << v;
    return ss.str();
}

void generate_island(int iseed) {
    module::Perlin myModule;

    myModule.SetSeed (iseed);
    utils::NoiseMap heightMap;
    utils::NoiseMapBuilderPlane heightMapBuilder;
    heightMapBuilder.SetSourceModule(myModule);
    heightMapBuilder.SetDestNoiseMap(heightMap);
    heightMapBuilder.SetDestSize(512, 512);
    heightMapBuilder.SetBounds(2.0, 6.0, 1.0, 5.0);
    heightMapBuilder.Build();

    float islandMap[512][512];
    srand(iseed);

    for (int count = 0; count < 1; count++ ){
        //Initialize values for a new map
        for (int i = 0; i < 512; i++) {
            for (int j = 0; j < 512; j++) {
                islandMap[j][i] = 0;
            }
        }

        //Choose a random location, travel in random directions
        int x = 0, y = 0;
        float previous = 0;

        for (int i = 0; i < 1000000; i++) {
            if(y == 511 || y == 0 || x == 511 || x == 0) {
                x = rand() % 512;
                y = rand() % 512;
            }   

            if(previous >= islandMap[x][y]) {
                islandMap[x][y] += 1;
            }

            previous = islandMap[x][y];

            switch(rand() % 4) {
                case 0:
                    x -= 1;
                    break;
                case 1:
                    y -= 1;
                    break;
                case 2:
                    x += 1;
                    break;
                case 3:
                    y += 1;
                    break;
                default:
                    break;
            }
        }

        //find max value for normalizing
        for (int i = 0; i < 512; i++) {
            for (int j = 0; j < 512; j++) {
                islandMap[i][j] = islandMap[i][j] * 2 - 1;
            }
        }

        int max = 0;
        int min = 0;
        for (int i = 0; i < 512; i++) {
            for (int j = 0; j < 512; j++) {
                if(max < islandMap[i][j]) {
                    max = islandMap[i][j];
                }

                if(min > islandMap[i][j]) {
                    min = islandMap[i][j];
                }
            }
        }

        //Multiply values of original by new maps generated
        for (int i = 0; i < 512; i++) {
            for (int j = 0; j < 512; j++) {
                float islandValue = (islandMap[i][j] - min) / (max - min);
                float mapValue = (heightMap.GetValue(i, j) + 1) / 2;
                float newValue = 2 * islandValue * mapValue - 1;
                heightMap.SetValue(i, j, newValue);
            }
        }
    }

    utils::RendererImage renderer;
    utils::Image image;
    renderer.SetSourceNoiseMap (heightMap);
    renderer.SetDestImage (image);
    renderer.ClearGradient ();
    renderer.AddGradientPoint (-1.0000, utils::Color (  0,   0, 255, 255)); // shallow
    renderer.AddGradientPoint (-0.9701, utils::Color (  0,   0, 255, 255)); // shallow
    renderer.AddGradientPoint (-0.9700, utils::Color (  0, 128, 255, 255)); // shore
    renderer.AddGradientPoint (-0.9690, utils::Color (  0, 128, 255, 255)); // shore
    renderer.AddGradientPoint (-0.9689, utils::Color (240, 240,  64, 255)); // sand
    renderer.AddGradientPoint (-0.9601, utils::Color (240, 240,  64, 255)); // sand
    renderer.AddGradientPoint (-0.9600, utils::Color ( 32, 160,   0, 255)); // grass
    renderer.AddGradientPoint (-0.4991, utils::Color ( 32, 160,   0, 255)); // grass
    renderer.AddGradientPoint (-0.4990, utils::Color ( 0, 0,   0, 255)); // pines
    renderer.AddGradientPoint (-0.4987, utils::Color ( 0, 0,   0, 255)); // pines
    renderer.AddGradientPoint (-0.3986, utils::Color (96, 63,   0, 255)); // dirt
    renderer.AddGradientPoint ( 0.0000, utils::Color (96, 63,   0, 255)); // dirt
    renderer.AddGradientPoint ( 0.0001, utils::Color (128, 128, 128, 255)); // rock
    renderer.AddGradientPoint ( 1.0000, utils::Color (128, 128, 128, 255)); // rock
    renderer.EnableLight ();
    renderer.SetLightContrast (3.0);
    renderer.SetLightBrightness (2.0);
    renderer.Render ();

    utils::WriterBMP writer;
    writer.SetSourceImage (image);
    writer.SetDestFilename ("tutorial" + tostring(iseed) + ".bmp");
    writer.WriteDestFile ();
}

int main() {
    for(int i=0; i<10; ++i){
        generate_island(i);
    }
    return 0;
}

 

 

Thankyou very much for this! I like the randomness and I love the code but do you know if there is any way to make it less "holey". There are specks of water all over the terrain and what I am going for is more of a solid island surrounded by water tongue.png


Edited by Riztro, 27 December 2012 - 08:10 PM.


#10 MarkS   Prime Members   -  Reputation: 886

Like
0Likes
Like

Posted 27 December 2012 - 08:34 PM


I just got done playing with his code. I took out the multiple calls to srand (now a single call: srand(iseed);), the do nothing for loop and various other oddities ((2 / 1) ?). It now creates very regular terrains. The generated terrains show a very strong rotational symmetry. Each 1/4 of the image is nearly an exact copy of each other, rotated 90°. 
 
I think the entire algorithm needs to be rewritten.

Sorry yeah the (2/1) thing gets the numbers into the range of -1 and 1. The 1 in that equation is the max number in the set of numbers. And what algorithm needs to be rewritten, the island masking one? :/ Because if that is so, I have no clue what to do. I just followed what this guy said he did on his blog.



I apologize for that. I've been dealing with something in my personal life that has kind of clouded my judgement today. I shouldn't have posted that; it wasn't helpful. However, since I *did* post it, look at TrickyLogic's changes. They were small, but significant.

#11 Riztro   Members   -  Reputation: 240

Like
0Likes
Like

Posted 27 December 2012 - 10:54 PM

I apologize for that. I've been dealing with something in my personal life that has kind of clouded my judgement today. I shouldn't have posted that; it wasn't helpful. However, since I *did* post it, look at TrickyLogic's changes. They were small, but significant.

 

It is no problem :D. I am glad you are just willing to help. I hope your personal problem clears up soon buddy :). I am wondering though, do you know how to make the terrain more solid and smooth? It seems very holey and turbulent :P



#12 MarkS   Prime Members   -  Reputation: 886

Like
0Likes
Like

Posted 28 December 2012 - 12:22 AM

 I am wondering though, do you know how to make the terrain more solid and smooth? It seems very holey and turbulent tongue.png

I wish I did. I would like to use this, but it all looks like eroded islands. :/

#13 Riztro   Members   -  Reputation: 240

Like
0Likes
Like

Posted 28 December 2012 - 12:28 AM

I wish I did. I would like to use this, but it all looks like eroded islands. :/

 

Oh :/. Maybe someone will come to help us :D



#14 Bacterius   Crossbones+   -  Reputation: 9266

Like
2Likes
Like

Posted 28 December 2012 - 12:35 AM

Thankyou very much for this! I like the randomness and I love the code but do you know if there is any way to make it less "holey". There are specks of water all over the terrain and what I am going for is more of a solid island surrounded by water

 

 

I don't fully grasp the code, I take it the last AddGradientPoint method calls simply generate a heightmap gradient to color-code elevation. If so, try raising the elevation offset by a small constant, like so:

 

 

 

float newValue = 2 * islandValue * mapValue - 1 + 0.1f;

That should raise the island by a bit, and get rid of most specks of water (which are really just parts of land which randomly happen to "dip" under sea level, if my understanding is correct). If that's not enough, try 0.2f, etc... experiment.

 

It is no problem . I am glad you are just willing to help. I hope your personal problem clears up soon buddy . I am wondering though, do you know how to make the terrain more solid and smooth? It seems very holey and turbulent

 

I think to achieve this you'll need to modify some parameters of your NoiseMap (it can be configured.. right?). If I recall correctly, basic perlin noise has two parameters, amplitude, which describes how high hills and troughs are, and frequency, which indicates how close those hills and troughs are to each other. Of course, it's a fractal design, so it's not so easy to visualize. Here you can see the terrain looks very rugged, which I suspect is because your NoiseMap is using too many octaves (the more octaves you use, the higher the frequency, which causes a lot of tiny ripples everywhere - lower it and you get a less detailed, but smoother look). Try experimenting with those settings, see what happens when you change such and such..

 

Procedural generation is really about tweaking until it looks cool, from my experience. Look for configurable settings in your noise classes, and check them out :)


The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis


#15 Riztro   Members   -  Reputation: 240

Like
0Likes
Like

Posted 28 December 2012 - 01:12 AM

I think to achieve this you'll need to modify some parameters of your NoiseMap (it can be configured.. right?). If I recall correctly, basic perlin noise has two parameters, amplitude, which describes how high hills and troughs are, and frequency, which indicates how close those hills and troughs are to each other. Of course, it's a fractal design, so it's not so easy to visualize. Here you can see the terrain looks very rugged, which I suspect is because your NoiseMap is using too many octaves (the more octaves you use, the higher the frequency, which causes a lot of tiny ripples everywhere - lower it and you get a less detailed, but smoother look). Try experimenting with those settings, see what happens when you change such and such..
 
Procedural generation is really about tweaking until it looks cool, from my experience. Look for configurable settings in your noise classes, and check them out
 

 

 

So I cut the frequency down to 0.0625 and the persistence to 0.01 and the amount of octaves to 3 and 4. With those new values I still have little bumps everywhere. It is very odd. So maybe the problem is with the island mask? IDK, I am not sure. What I would like to ultimately do is have some scattered forests and then the rest could just be flat grass land. Forests would be in the higher range instead of mountains.  This game is going to be top down tile based so I am looking more to just generate tiles that clump together on an island :)

 

So I am guessing that I might just have to write my own noise function of some sorts to get the desired flat effect. Am I right? Or do you think it is easily possible with libnoise?


Edited by Riztro, 28 December 2012 - 01:28 AM.


#16 TrickyLogic   Members   -  Reputation: 171

Like
2Likes
Like

Posted 28 December 2012 - 04:27 AM

Thankyou very much for this! I like the randomness and I love the code but do you know if there is any way to make it less "holey". There are specks of water all over the terrain and what I am going for is more of a solid island surrounded by water

 

 

You're probably better off writing your own noise function if you want that amount of control. The problem is both with the perlin noise and the island mask. Some fixes that make it a bit better:

//Little program to generate test map with only 0 and 1 tile

#include <iostream>
#include <noise/noise.h>
#include "noiseutils.h"
#include <stdlib.h>
#include <string>
#include <sstream>

#define MAP_SIZE 512

using namespace std;
using namespace noise;

template <typename T> string tostring (T v) {
    ostringstream ss;
    ss << v;
    return ss.str();
}

void generate_island(int iseed) {
    module::Perlin myModule;

    myModule.SetSeed (iseed);
    utils::NoiseMap heightMap;
    utils::NoiseMapBuilderPlane heightMapBuilder;
    heightMapBuilder.SetSourceModule(myModule);
    heightMapBuilder.SetDestNoiseMap(heightMap);
    heightMapBuilder.SetDestSize(MAP_SIZE, MAP_SIZE);
    heightMapBuilder.SetBounds(2.0, 6.0, 1.0, 5.0);
    heightMapBuilder.Build();

    float islandMap[MAP_SIZE][MAP_SIZE];
    srand(iseed);

    for (int count = 0; count < 1; count++ ){
        //Initialize values for a new map
        for (int i = 0; i < MAP_SIZE; i++) {
            for (int j = 0; j < MAP_SIZE; j++) {
                islandMap[j][i] = 0;
            }
        }

        //Choose a random location, travel in random directions
        int x = 0, y = 0;
        int sx = 0, sy = 0;
        int size = MAP_SIZE / 2;
        int distance = 0;

        for (int i = 0; i < 1000000; i++) {
            int dx = x - sx;
            int dy = y - sy;
            distance = dx * dx + dy * dy;
            if((y > MAP_SIZE - 1) || y < 0 || (x > MAP_SIZE - 1) || x < 0 || distance > 5000) {
                x = rand() % size / 2 + rand() % size / 2 + MAP_SIZE / 2 - size / 2;
                y = rand() % size / 2 + rand() % size / 2 + MAP_SIZE / 2 - size / 2;
                sx = x;
                sy = y;
            }

            ++islandMap[x][y];

            switch(rand() % 4) {
                case 0:
                    ++x;
                    break;
                case 1:
                    --y;
                    break;
                case 2:
                    --x;
                    break;
                case 3:
                    ++y;
                    break;
                default:
                    break;
            }
        }

        //find max value for normalizing
        for (int i = 0; i < MAP_SIZE; i++) {
            for (int j = 0; j < MAP_SIZE; j++) {
                islandMap[i][j] = islandMap[i][j] * 2 - 1;
            }
        }

        int max = 0;
        int min = 0;
        for (int i = 0; i < MAP_SIZE; i++) {
            for (int j = 0; j < MAP_SIZE; j++) {
                if(max < islandMap[i][j]) {
                    max = islandMap[i][j];
                }

                if(min > islandMap[i][j]) {
                    min = islandMap[i][j];
                }
            }
        }

        //Multiply values of original by new maps generated
        for (int i = 0; i < MAP_SIZE; i++) {
            for (int j = 0; j < MAP_SIZE; j++) {
                float islandValue = (islandMap[i][j] - min) / (max - min);
                float mapValue = (heightMap.GetValue(i, j) + 1) / 2;
                float newValue = 2 * islandValue * mapValue - 1;
                heightMap.SetValue(i, j, newValue);
            }
        }
    }

    utils::RendererImage renderer;
    utils::Image image;
    renderer.SetSourceNoiseMap (heightMap);
    renderer.SetDestImage (image);
    renderer.ClearGradient ();
    renderer.AddGradientPoint (-1.0000, utils::Color (  0,   0, 255, 255)); // shallow
    renderer.AddGradientPoint (-0.9701, utils::Color (  0,   0, 255, 255)); // shallow
    renderer.AddGradientPoint (-0.9700, utils::Color (  0, 128, 255, 255)); // shore
    renderer.AddGradientPoint (-0.9690, utils::Color (  0, 128, 255, 255)); // shore
    renderer.AddGradientPoint (-0.9689, utils::Color (240, 240,  64, 255)); // sand
    renderer.AddGradientPoint (-0.9601, utils::Color (240, 240,  64, 255)); // sand
    renderer.AddGradientPoint (-0.9600, utils::Color ( 32, 160,   0, 255)); // grass
    renderer.AddGradientPoint (-0.4991, utils::Color ( 32, 160,   0, 255)); // grass
    renderer.AddGradientPoint (-0.4990, utils::Color ( 0, 0,   0, 255)); // pines
    renderer.AddGradientPoint (-0.4987, utils::Color ( 0, 0,   0, 255)); // pines
    renderer.AddGradientPoint (-0.3986, utils::Color (96, 63,   0, 255)); // dirt
    renderer.AddGradientPoint ( 0.0000, utils::Color (96, 63,   0, 255)); // dirt
    renderer.AddGradientPoint ( 0.0001, utils::Color (128, 128, 128, 255)); // rock
    renderer.AddGradientPoint ( 1.0000, utils::Color (128, 128, 128, 255)); // rock
    renderer.EnableLight ();
    renderer.SetLightContrast (3.0);
    renderer.SetLightBrightness (2.0);
    renderer.Render ();

    utils::WriterBMP writer;
    writer.SetSourceImage (image);
    writer.SetDestFilename ("tutorial" + tostring(iseed) + ".bmp");
    writer.WriteDestFile ();
}

int main() {
    for(int i=0; i<10; ++i){
        generate_island(i);
    }
    return 0;
}

The island mask consists of many random walks added together. The random walks scale poorly with size of the map (change the MAP_SIZE to see for yourself) because they tend to diverge very quickly. With the above code I've applied two methods two remedy this a bit:

  1. Terminate any random walk if they get beyond a certain distance away from their origin.
  2. Make the starting point of any random walk more likely to be in the middle with a triangular distribution and within a smaller region (controlled with the 'size' variable).

Play a bit with the numbers to see if you can improve the results.

 

If you want to try something else try this instead: http://en.wikipedia.org/wiki/Diamond-square_algorithm If you set the first N levels yourself instead of randomly generating them you get much more control over the final output.

Attached Thumbnails

  • tutorial0.png
  • tutorial1.png

Edited by TrickyLogic, 28 December 2012 - 04:42 AM.


#17 Riztro   Members   -  Reputation: 240

Like
0Likes
Like

Posted 28 December 2012 - 05:36 PM


Thankyou very much for this! I like the randomness and I love the code but do you know if there is any way to make it less "holey". There are specks of water all over the terrain and what I am going for is more of a solid island surrounded by water


You're probably better off writing your own noise function if you want that amount of control. The problem is both with the perlin noise and the island mask. Some fixes that make it a bit better:
//Little program to generate test map with only 0 and 1 tile#include #include #include "noiseutils.h"#include #include #include #define MAP_SIZE 512using namespace std;using namespace noise;template  string tostring (T v) {    ostringstream ss;    ss << v;    return ss.str();}void generate_island(int iseed) {    module::Perlin myModule;    myModule.SetSeed (iseed);    utils::NoiseMap heightMap;    utils::NoiseMapBuilderPlane heightMapBuilder;    heightMapBuilder.SetSourceModule(myModule);    heightMapBuilder.SetDestNoiseMap(heightMap);    heightMapBuilder.SetDestSize(MAP_SIZE, MAP_SIZE);    heightMapBuilder.SetBounds(2.0, 6.0, 1.0, 5.0);    heightMapBuilder.Build();    float islandMap[MAP_SIZE][MAP_SIZE];    srand(iseed);    for (int count = 0; count < 1; count++ ){        //Initialize values for a new map        for (int i = 0; i < MAP_SIZE; i++) {            for (int j = 0; j < MAP_SIZE; j++) {                islandMap[j][i] = 0;            }        }        //Choose a random location, travel in random directions        int x = 0, y = 0;        int sx = 0, sy = 0;        int size = MAP_SIZE / 2;        int distance = 0;        for (int i = 0; i < 1000000; i++) {            int dx = x - sx;            int dy = y - sy;            distance = dx * dx + dy * dy;            if((y > MAP_SIZE - 1) || y < 0 || (x > MAP_SIZE - 1) || x < 0 || distance > 5000) {                x = rand() % size / 2 + rand() % size / 2 + MAP_SIZE / 2 - size / 2;                y = rand() % size / 2 + rand() % size / 2 + MAP_SIZE / 2 - size / 2;                sx = x;                sy = y;            }            ++islandMap[x][y];            switch(rand() % 4) {                case 0:                    ++x;                    break;                case 1:                    --y;                    break;                case 2:                    --x;                    break;                case 3:                    ++y;                    break;                default:                    break;            }        }        //find max value for normalizing        for (int i = 0; i < MAP_SIZE; i++) {            for (int j = 0; j < MAP_SIZE; j++) {                islandMap[i][j] = islandMap[i][j] * 2 - 1;            }        }        int max = 0;        int min = 0;        for (int i = 0; i < MAP_SIZE; i++) {            for (int j = 0; j < MAP_SIZE; j++) {                if(max < islandMap[i][j]) {                    max = islandMap[i][j];                }                if(min > islandMap[i][j]) {                    min = islandMap[i][j];                }            }        }        //Multiply values of original by new maps generated        for (int i = 0; i < MAP_SIZE; i++) {            for (int j = 0; j < MAP_SIZE; j++) {                float islandValue = (islandMap[i][j] - min) / (max - min);                float mapValue = (heightMap.GetValue(i, j) + 1) / 2;                float newValue = 2 * islandValue * mapValue - 1;                heightMap.SetValue(i, j, newValue);            }        }    }    utils::RendererImage renderer;    utils::Image image;    renderer.SetSourceNoiseMap (heightMap);    renderer.SetDestImage (image);    renderer.ClearGradient ();    renderer.AddGradientPoint (-1.0000, utils::Color (  0,   0, 255, 255)); // shallow    renderer.AddGradientPoint (-0.9701, utils::Color (  0,   0, 255, 255)); // shallow    renderer.AddGradientPoint (-0.9700, utils::Color (  0, 128, 255, 255)); // shore    renderer.AddGradientPoint (-0.9690, utils::Color (  0, 128, 255, 255)); // shore    renderer.AddGradientPoint (-0.9689, utils::Color (240, 240,  64, 255)); // sand    renderer.AddGradientPoint (-0.9601, utils::Color (240, 240,  64, 255)); // sand    renderer.AddGradientPoint (-0.9600, utils::Color ( 32, 160,   0, 255)); // grass    renderer.AddGradientPoint (-0.4991, utils::Color ( 32, 160,   0, 255)); // grass    renderer.AddGradientPoint (-0.4990, utils::Color ( 0, 0,   0, 255)); // pines    renderer.AddGradientPoint (-0.4987, utils::Color ( 0, 0,   0, 255)); // pines    renderer.AddGradientPoint (-0.3986, utils::Color (96, 63,   0, 255)); // dirt    renderer.AddGradientPoint ( 0.0000, utils::Color (96, 63,   0, 255)); // dirt    renderer.AddGradientPoint ( 0.0001, utils::Color (128, 128, 128, 255)); // rock    renderer.AddGradientPoint ( 1.0000, utils::Color (128, 128, 128, 255)); // rock    renderer.EnableLight ();    renderer.SetLightContrast (3.0);    renderer.SetLightBrightness (2.0);    renderer.Render ();    utils::WriterBMP writer;    writer.SetSourceImage (image);    writer.SetDestFilename ("tutorial" + tostring(iseed) + ".bmp");    writer.WriteDestFile ();}int main() {    for(int i=0; i<10; ++i){        generate_island(i);    }    return 0;}.h>
The island mask consists of many random walks added together. The random walks scale poorly with size of the map (change the MAP_SIZE to see for yourself) because they tend to diverge very quickly. With the above code I've applied two methods two remedy this a bit:
  • Terminate any random walk if they get beyond a certain distance away from their origin.
     
  • Make the starting point of any random walk more likely to be in the middle with a triangular distribution and within a smaller region (controlled with the 'size' variable).
Play a bit with the numbers to see if you can improve the results.

If you want to try something else try this instead: http://en.wikipedia.org/wiki/Diamond-square_algorithm If you set the first N levels yourself instead of randomly generating them you get much more control over the final output.

Here are my results when I put it in my engine! Looks good! biggrin.png Thanks a ton!!! biggrin.png

Attached Thumbnails

  • map.png


#18 Blind Radish   Members   -  Reputation: 355

Like
0Likes
Like

Posted 30 December 2012 - 02:11 AM

All /I/ was saying was that if your problem is division, an easy hack would be to divide by a number that couldn't carry the problem over.

Really though, you want to be able to get it working with any size.  Still it might help to try it in certain situations, to find out if that is the problem.

But I'm really doubting it is.  Listen to these guys, they know better than me it looks like.

I could help you build one that kicks ass, well the general design not so much specific implementation, but fixing one isn't my area of expertise.  I think in code but I still have trouble reading it.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS