0

I've created a Perlin noise function. My issue is when I generate a terrain map from the noise it ends up blocky, nothing like the cloudlike images I've seen. I'm curious on what I'm doing wrong (if anything). here's my code:

main.cpp

#include "PerlinNoise.h"
#include <stdio.h>
#include <SDL/SDL.h>

void DrawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B);
SDL_Surface *Render_Noise(int w, int h, int r, int g, int b);
PerlinNoise noiseGen(2,.5,25);

int main(int argc, char **argv)
{
    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_Surface *screen = SDL_SetVideoMode(500,500,32,SDL_SWSURFACE);
    SDL_Surface *noise = Render_Noise(500,500,255,255,255);

    SDL_SaveBMP(noise, "noise.bmp");

    bool quit = false;

    while(!quit)
    {
        SDL_Event e;

        SDL_WaitEvent(&e);

        switch(e.type)
        {
        case SDL_QUIT:
            quit = true;
        }

        SDL_BlitSurface(noise,NULL,screen,NULL);
        SDL_Flip(screen);
        SDL_Delay(2000);
    }

    SDL_FreeSurface(noise);
    SDL_Quit();

    return 0;
}

void DrawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B)
{
    Uint32 color = SDL_MapRGB(screen->format, R, G, B);

    if(SDL_MUSTLOCK(screen))
    {
        if(SDL_LockSurface(screen) < 0)
        {
            return;
        }
    }

    switch(screen->format->BytesPerPixel)
    {
    case 1:
        {
        Uint8 *bufp;

        bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
        *bufp = color;
        }
        break;

    case 2:
        {
        Uint16 *bufp;
        bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
        *bufp = color;
        }
        break;

    case 3:
        {
        Uint8 *bufp;

        bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
        *(bufp+screen->format->Rshift/8) = R;
        *(bufp+screen->format->Bshift/8) = B;
        *(bufp+screen->format->Gshift/8) = G;
        }
        break;

    case 4:
        {
        Uint32 *bufp;

        bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
        *bufp = color;
        }
        break;
    }

    if(SDL_MUSTLOCK(screen))
    {
        SDL_UnlockSurface(screen);
    }
    SDL_UpdateRect(screen, x, y, 1, 1);
}

SDL_Surface *Render_Noise(int w, int h, int r, int g, int b)
{
    SDL_Surface *ret = SDL_CreateRGBSurface(SDL_SWSURFACE,w,h,32,0,0,0,0);          //create an empty image

    for(int y = 0; y < h; y++)
    {
        for(int x = 0; x < w; x++)
        {
            double getnoise = 0;
            for(int a = 0; a < noiseGen.n; a++)
            {
                getnoise += noiseGen.generateNoise(x,y);
                noiseGen.z = rand() % 100;
            }

            getnoise / noiseGen.n;

            int color = (int)((getnoise * 128.0) + 128.0);      //convert noise to 0-256 value

            if (color > 255)
                color = 255;
            if (color < 0)
                color = 0;

            DrawPixel( ret, x, y, (int)((r/255.0) * (double)color), (int)((g/255.0) * (double)color), (int)((b/255.0) * (double)color) );
        }
    }
    return ret;
}

perlinnoise.cpp

#include "PerlinNoise.h"

PerlinNoise::PerlinNoise(int octaves, double persistence, int zoom)
{
    p = persistence;
    n = octaves - 1;
    z = zoom;
}

PerlinNoise::~PerlinNoise()
{

}

///<summary>Gets a random number using x and y as seeds </summary>
///<param name = x> A double value </param>
///<param name = y> A double value </param>
///<returns> A random number between -1.0 and 1.0 </returns>
inline double PerlinNoise::noise(double x, double y)
{
    int n = x + y * 57; 
    n = (n << 13) ^ n;

    return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}

///<summary> Smooths out noise values </summary>
///<param name = x> a double value </param>
///<param name = y> a double value </param>
///<returns> a smoothed value between -1.0 and 1.0 </returns>
double PerlinNoise::smoothNoise(double x, double y)
{
    double corners = (noise(x+1, y+1) + noise(x+1,y-1) + noise(x-1,y+1) + noise(x-1,y-1)) / 16;
    double sides = (noise(x,y+1) + noise(x,y-1) + noise(x+1,y) + noise(x-1,y)) / 8;
    double center = noise(x,y) / 4;

    return corners + sides + center;
}

///<summary> Cosine Interpolation </summary>
///<param name = a> The low value to be interpolated </param>
///<param name = b> The high value to be interpolated </param>
///<param name = x> A value between -1.0 and 1.0 </param>
///<returns> Interpolated value between a and b </returns>
double PerlinNoise::cosineInterpolation(double a, double b, double x)
{
    double ft = x * 3.1415927;
    double f = (1.0 - cos(ft)) * .5;

    return a * (1.0 - f) + b * f;
}

///<summary> Gets smoothed noise values and interpolates them </summary>
///<param name = x> a double value </param>
///<param name = y> a double value </param>
///<returns> a value between -1 and 1 that's been smoothed and interpolated </returns>
double PerlinNoise::interpolatedNoise(double x, double y)
{
    double integer_x = (int)x;
    double fractional_x = x - integer_x;

    double integer_y = (int)y;
    double fractional_y = y - integer_y;

    double v1 = smoothNoise(integer_x, integer_y);
    double v2 = smoothNoise(integer_x + 1, integer_y);
    double v3 = smoothNoise(integer_x, integer_y + 1);
    double v4 = smoothNoise(integer_x + 1, integer_y + 1);

    double inter1 = cosineInterpolation(v1, v2, fractional_x);
    double inter2 = cosineInterpolation(v3, v4, fractional_x);

    return cosineInterpolation(inter1, inter2, fractional_y);
}

double PerlinNoise::generateNoise(double x, double y)
{
    double total = 0;

    for(int i = 0; i < n; i++)
    {
        frequency = pow(2.0,i);
        amplitude = pow(p,i);

        total = total + interpolatedNoise(x * frequency / z, y * frequency / z) * amplitude;
    }

    return total;
}
Jason Sturges
  • 15,855
  • 14
  • 59
  • 80
  • 2
    Posting an image of your output would be very helpful. – Pubby Jun 24 '12 at 07:15
  • Given that your code does not compile (the listing is incomplete) it is quite challenging to provide any useful comments. That said, blocky outputs suggest too few octaves of noise, and gritty outputs would suggest that some sort of filtering is needed. Link some outputs, please. – Rook Jun 24 '12 at 09:37
  • [here's](http://imgur.com/zfyTU) what I've been getting. To compile, you'll need SDL and [this](http://pastie.org/4144014) header. I chose the 2 most important files to upload, since stack overflow would only allow me 2 – Zacharias3960 Jun 24 '12 at 18:23

1 Answers1

0

Found the problem, my persistence was much lower than it should be, upping that I got the cloudlike image I expected