Question

Okay first of all, I am trying to implement the Perlin noise algorithm, and I managed to achived something strange, and I can't find the solution. I am using matlab to visualize the results I have already checked this question:

"Blocky" Perlin noise

I am doing it from this website:

http://freespace.virgin.net/hugo.elias/models/m_perlin.htm

And another website which I can't find right now but I will update as soon as I can.

So here are some pictures about the problem:

This is the problem if increase zoom http://i.stack.imgur.com/KkD7u.png

And here are the .cpp-s:

//perlin.cpp
     #include "Perlin_H.h"
    #include <stdlib.h>
    #include <math.h>
    #include <iostream>
    #include <random>
    using namespace std;

double Perlin::interp1(double a, double b, double x) {

    double ft = x * 3.1415927;
    double f = (1.0-cos(ft)) * 0.5;
    //return (b-x > b-1/2) ? b-x : a+x;
    return a * (1.0-f) + b * f;
}

double Perlin::smoothNoise(double x,double y) {
    double corners =  ( rand2(x-1, y-1)+rand2(x+1, y-1)+rand2(x-1, y+1)+rand2(x+1, y+1) ) / 16;
    double sides = ( rand2(x-1, y)  +rand2(x+1, y)  +rand2(x, y-1)  +rand2(x, y+1) ) /  8;
    double center = rand2(x,y)/4;

    return corners + sides +center;
}



double Perlin::lininterp1(double a,double b, double x) {
    return a*(1-x) + b * x;
}
double Perlin::rand2(double x, double y) {

    int n = (int)x + (int)y*57;
    //n=pow((n<<13),n);
    n=(n<<13)^n;
    return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);

}

double Perlin::noise(double x, double y) {
    double floorX = (double)floor(x);
    double floorY = (double)floor(y);

    double s,t,u,v;

    s = smoothNoise(floorX,floorY);
    t = smoothNoise(floorX+1,floorY);
    u = smoothNoise(floorY,floorY+1);
    v = smoothNoise(floorX+1,floorY+1);

    double int1 = interp1(s,t,x-floorX);
    double int2 = interp1(u,v,x-floorX);

    return interp1(int1,int2,y-floorY);
}

//main.cpp

#include "Perlin_H.h"
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>;
using namespace std;
int main() {
    const int h=64,w=64,octaves=2;
    double p=1/1;
    double zoom = 30;
    Perlin perlin;

    double map[h][w];
    ofstream output;
    output.open("map.txt");
    for(int i = 0; i < h ; i++) {   
        for(int j = 0; j < w ; j++) {
            map[i][j] = 0;
        }
    }
    double freq = 2;




    for(int i = 0; i < h ; i++) {


        for(int j = 0; j < w ; j++) {

            double getnoise = 0;
            for(int a=0; a < octaves; a++) {


                double freq = pow(2,a);

                double amp = pow(p,a);
                getnoise = perlin.noise((((double)i)*freq)/zoom-(a*10),
                    ((((double)j))*freq)/zoom+(a*10))*amp;
                int color = (int)((getnoise * 128.0) + 128.0);
                if(color > 255) color = 255;
                if(color < 0) color = 0;

                map[i][j] = color;


            }
        output  << map[i][j] << "\t";
        }
        output << "\n";

    }


    output.close();



    system("PAUSE");
    return 0;
}
Was it helpful?

Solution

It's a typo!

s = smoothNoise(floorX,floorY);
t = smoothNoise(floorX+1,floorY);
u = smoothNoise(floorY,floorY+1);
v = smoothNoise(floorX+1,floorY+1);

Try: u = smoothNoise(floorX, floorY +1)

This explains why the diagonal didn't have the blocky appearance (where x=y), and why many of the common feature shapes are subtly off in a mirrored and skewed fashion. Since it is generally obvious that rand2(floor(y), floor(y)+1) != rand2(floor(x), floor(y+1)) the cell discontinuity will result.

OTHER TIPS

Finding no mathematical error in your implementation, I suspect this is a number format issue.

Such block patterns are created when the grid point values are not actually the same when fetched from different sides - when rand2(floor(n) +1 ,y) != rand2(floor(n+1) ,y)

To fix it, declare floorX to be an int or long instead, and pass it as such to smoothNoise() and rand2().

This can happen due to floating point error in the representation of the Integer values floorX , floorX + 1. The epsilon of magnitude ulp or less can have either sign. the results of addition [floor(n) + 1] and flooring directly [floor(n+1)] are bound by different code, and so need not share a pattern of choosing which side to err on. When the results err on different sides, the int type cast strips the 0.99999999999 and the 0.0000000001 equally, treating the mathematically equivalent numbers as different.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top