柏林噪声(Perlin Noise)示例程序
2022-4-23 ~ 2022-4-24
(0)
本文章的柏林噪声的算法部分来自:https://ryuzhihao123.blog.csdn.net/article/details/54743672
柏林噪声
柏林噪声是一种自然噪声生成算法。可以生成不同于白噪声的平滑噪声。这个算法也常常被运用到游戏里,比如生成地图或模拟手绘效果之类的。
正好我的游戏要用到,所以写了这个程序。
这里只是将它包装成了一维和二维的示例。
代码:(这里为了计算速度将 double 改成了 float,可以根据自己的精度需求更改)
// 编译环境:Visual Studio 2015
#include<iostream>
#include<conio.h>
#include<easyx.h>
#include<ctime>
using namespace std;
float persistence = 0.50;
int Number_Of_Octaves = 2;
float Noise(int x, int y) // 根据(x, y)获取一个初步噪声值
{
int n = x + y * 57;
n = (n << 13) ^ n;
return (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
float SmoothedNoise(int x, int y) // 光滑噪声
{
float corners = (Noise(x - 1, y - 1) + Noise(x + 1, y - 1) + Noise(x - 1, y + 1) + Noise(x + 1, y + 1)) / 16;
float sides = (Noise(x - 1, y) + Noise(x + 1, y) + Noise(x, y - 1) + Noise(x, y + 1)) / 8;
float center = Noise(x, y) / 4;
return corners + sides + center;
}
float Cosine_Interpolate(float a, float b, float x) // 余弦插值
{
float ft = x * 3.1415927;
float f = (1 - cos(ft)) * 0.5;
return a * (1 - f) + b * f;
}
float InterpolatedNoise(float x, float y) // 获取插值噪声
{
int integer_X = int(x);
float fractional_X = x - integer_X;
int integer_Y = int(y);
float fractional_Y = y - integer_Y;
float v1 = SmoothedNoise(integer_X, integer_Y);
float v2 = SmoothedNoise(integer_X + 1, integer_Y);
float v3 = SmoothedNoise(integer_X, integer_Y + 1);
float v4 = SmoothedNoise(integer_X + 1, integer_Y + 1);
float i1 = Cosine_Interpolate(v1, v2, fractional_X);
float i2 = Cosine_Interpolate(v3, v4, fractional_X);
return Cosine_Interpolate(i1, i2, fractional_Y);
}
float PerlinNoise(float x, float y) // 最终调用:根据(x, y)获得其对应的 PerlinNoise 值
{
float total = 0;
float p = persistence;
int n = Number_Of_Octaves;
for (int i = 0; i<n; i++)
{
float frequency = pow(2, i);
float amplitude = pow(p, i);
total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
}
return total;
}
int color;
bool odortd = false;
int colordeep = 10;
float microxy = 15.0;
void drawnoise() // 绘制噪声
{
clearcliprgn;
if (odortd)
{
for (int i = 0; i < 500; i++)
{
color = PerlinNoise(i / microxy, i / microxy) * colordeep;
putpixel(i, 200 + color, WHITE);
}
}
else
{
for (int i = 0; i < 500; i++)
{
for (int j = 0; j < 500; j++)
{
color = PerlinNoise(i / microxy, j / microxy) * colordeep;
putpixel(i, j, RGB(color, color, color));
}
}
}
}
int main()
{
initgraph(900, 500);
ExMessage mmsg;
drawnoise();
for (;; )
{
peekmessage(&mmsg, EM_MOUSE);
BeginBatchDraw();
// 调试内容
setfillcolor(WHITE);
line(500, 100, 900, 100);
line(500, 200, 900, 200);
line(500, 300, 900, 300);
line(500, 400, 900, 400);
outtextxy(510, 50, _T("持续度"));
fillcircle(500 + persistence * 100.0, 100, 10);
outtextxy(510, 150, _T("倍率"));
fillcircle(500 + Number_Of_Octaves * 50.0, 200, 10);
outtextxy(510, 250, _T("二维时:色深,一维时:平滑度"));
fillcircle(510 + colordeep, 300, 10);
outtextxy(510, 350, _T("类似缩放的效果"));
fillcircle(500 + microxy * 5.0, 400, 10);
outtextxy(510, 450, _T("一维还是二维:"));
settextcolor(BLACK);
setbkcolor(WHITE);
outtextxy(640, 450, (odortd ? _T("一维") : _T("二维")));
settextcolor(WHITE);
setbkcolor(BLACK);
if (mmsg.x > 500 && mmsg.x < 900 && mmsg.lbutton == true)
{
if (mmsg.y > 50 && mmsg.y < 150)
{
persistence = (mmsg.x - 500) / 100.0;
clearcliprgn();
drawnoise();
}
if (mmsg.y > 150 && mmsg.y < 250)
{
Number_Of_Octaves = (mmsg.x - 500) / 50.0;
clearcliprgn();
drawnoise();
}
if (mmsg.y > 250 && mmsg.y < 350)
{
colordeep = mmsg.x - 500;
clearcliprgn();
drawnoise();
}
if (mmsg.y > 350 && mmsg.y < 450)
{
microxy = (mmsg.x - 500) / 5.0;
clearcliprgn();
drawnoise();
}
if (mmsg.y > 440 && mmsg.y < 560 && mmsg.x>640 && mmsg.x < 690)
{
odortd = !odortd;
clearcliprgn();
drawnoise();
}
}
FlushBatchDraw();
mmsg.lbutton = false;
}
closegraph();
return 0;
}
添加评论
取消回复