柏林噪声(Perlin Noise)示例程序

本文章的柏林噪声的算法部分来自:https://ryuzhihao123.blog.csdn.net/article/details/54743672

柏林噪声

柏林噪声是一种自然噪声生成算法。可以生成不同于白噪声的平滑噪声。这个算法也常常被运用到游戏里,比如生成地图或模拟手绘效果之类的。

正好我的游戏要用到,所以写了这个程序。

这里只是将它包装成了一维和二维的示例。

photo

代码:(这里为了计算速度将 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;
}

添加评论