パーリンノイズをChatGPTで学習した備忘録
ローグライクのマップ生成に使用できるアルゴリズムを探していた時の備忘録
備忘録
周囲の4点の値に重さ付けをして、それぞれの線分に対して線形補完を順番に行い、そのグリッドの値を出すイメージ?(違ったらコメントください)

関数の説明
float fade(float t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
フェード関数は線形補完で使用する2つの値の割合を決定する関数
// グラデーション関数
float grad(int hash, float x, float y) {
int h = hash & 15;
float u = h < 8 ? x : y;
float v = h < 4 ? y : (h == 12 || h == 14) ? x : 0;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
疑似乱数の値をもとに頂点の値を前後させる
// 線形補間関数
float lerp(float t, float a, float b) {
return a + t * (b - a);
}
線形補完をおこなう
fadeで求めた値をもとに2点の間の値を求める
使用したコード
#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <algorithm> // std::max と std::min のためのヘッダー
const int MAP_WIDTH = 30; // マップの幅
const int MAP_HEIGHT = 30; // マップの高さ
const float FREQUENCY = 0.1; // パーリンノイズの周波数
// パーリンノイズ関数の前方宣言
float perlinNoise(float x, float y);
// フェード関数の前方宣言
float fade(float t);
// 線形補間関数の前方宣言
float lerp(float t, float a, float b);
// グラデーション関数の前方宣言
float grad(int hash, float x, float y);
// パーリンノイズに使用するランダムな値の配列
int p[512];
// パーリンノイズ関数
float perlinNoise(float x, float y) {
int X = static_cast<int>(floor(x)) & 255; //&255でビット演算を行い0~255に制限している
int Y = static_cast<int>(floor(y)) & 255;
x -= floor(x);
y -= floor(y);
float u = fade(x);
float v = fade(y);
int A = p[X] + Y;
int B = p[X + 1] + Y;
return lerp(v, lerp(u, grad(p[A], x, y), grad(p[B], x - 1, y)), lerp(u, grad(p[A + 1], x, y - 1), grad(p[B + 1], x - 1, y - 1)));
}
// フェード関数
float fade(float t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
// 線形補間関数
float lerp(float t, float a, float b) {
return a + t * (b - a);
}
// グラデーション関数
float grad(int hash, float x, float y) {
int h = hash & 15;
float u = h < 8 ? x : y;
float v = h < 4 ? y : (h == 12 || h == 14) ? x : 0;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
int main() {
std::srand(static_cast<unsigned int>(std::time(nullptr)));
for (int i = 0; i < 512; i++) {
p[i] = std::rand() % 256;
}
for (int y = 0; y < MAP_HEIGHT; y++) {
for (int x = 0; x < MAP_WIDTH; x++) {
float value = perlinNoise(x * FREQUENCY, y * FREQUECY);
int intValue = static_cast<int>((value + 1.0) * 10.0); // 値を0から9の範囲に変換
intValue = std::max(0, std::min(intValue, 9)); // intValueを0から9の範囲内に制限
char pixelChar = (intValue == 9) ? '*' : '.';
std::cout << pixelChar;
}
std::cout << std::endl; // 改行して次の行へ
}
return 0;
}