我创建了一个 Perlin 噪声函数。我的问题是,当我从噪声中生成地形图时,它最终会变成块状,与我见过的云状图像完全不同。我很好奇我做错了什么(如果有的话)。这是我的代码:
主文件
#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;
}