mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
220 lines
7.1 KiB
C++
220 lines
7.1 KiB
C++
#include "stdafx.h"
|
||
#include "ImprovedNoise.h"
|
||
#include "Random.h" // íàø óëó÷øåííûé Random
|
||
#include <cmath> // äëÿ floor, åñëè íóæíî, íî èñïîëüçóåì static_cast
|
||
|
||
ImprovedNoise::ImprovedNoise()
|
||
{
|
||
Random random; // èñïîëüçóåò íîâûé âûñîêîýíòðîïèéíûé seed
|
||
init(&random);
|
||
}
|
||
|
||
ImprovedNoise::ImprovedNoise(Random* random)
|
||
{
|
||
init(random);
|
||
}
|
||
|
||
void ImprovedNoise::init(Random* random)
|
||
{
|
||
// Ñëó÷àéíûå ñìåùåíèÿ äëÿ êàæäîé êîîðäèíàòû (óáèðàþò ñèììåòðèþ)
|
||
xo = random->nextDouble() * 256.0;
|
||
yo = random->nextDouble() * 256.0;
|
||
zo = random->nextDouble() * 256.0;
|
||
|
||
// Çàïîëíÿåì permutation table ÷èñëàìè 0..255 â ñëó÷àéíîì ïîðÿäêå
|
||
for (int i = 0; i < 256; ++i)
|
||
p[i] = i;
|
||
|
||
for (int i = 0; i < 256; ++i)
|
||
{
|
||
int j = random->nextInt(256 - i) + i; // ñëó÷àéíàÿ ïåðåñòàíîâêà
|
||
int tmp = p[i];
|
||
p[i] = p[j];
|
||
p[j] = tmp;
|
||
|
||
p[i + 256] = p[i]; // äóáëèðóåì äëÿ èçáåæàíèÿ ïðîâåðîê ãðàíèö
|
||
}
|
||
}
|
||
|
||
// ----------------------------------------------------------------------
|
||
// Îñíîâíîé ìåòîä âû÷èñëåíèÿ 3D øóìà Ïåðëèíà
|
||
double ImprovedNoise::noise(double x, double y, double z) const
|
||
{
|
||
// Äîáàâëÿåì óíèêàëüíîå ñìåùåíèå äëÿ ýòîãî ýêçåìïëÿðà
|
||
x += xo;
|
||
y += yo;
|
||
z += zo;
|
||
|
||
// Öåëàÿ ÷àñòü êîîðäèíàò (îïðåäåëÿåì êóá, ñîäåðæàùèé òî÷êó)
|
||
int X = static_cast<int>(std::floor(x)) & 255;
|
||
int Y = static_cast<int>(std::floor(y)) & 255;
|
||
int Z = static_cast<int>(std::floor(z)) & 255;
|
||
|
||
// Îòíîñèòåëüíûå êîîðäèíàòû âíóòðè êóáà [0,1)
|
||
x -= std::floor(x);
|
||
y -= std::floor(y);
|
||
z -= std::floor(z);
|
||
|
||
// Ïëàâíàÿ êðèâàÿ (fade function): 6t^5 - 15t^4 + 10t^3
|
||
double u = x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
|
||
double v = y * y * y * (y * (y * 6.0 - 15.0) + 10.0);
|
||
double w = z * z * z * (z * (z * 6.0 - 15.0) + 10.0);
|
||
|
||
// Õåøè èíäåêñîâ âîñüìè óãëîâ êóáà
|
||
int A = p[X] + Y;
|
||
int AA = p[A] + Z;
|
||
int AB = p[A + 1] + Z;
|
||
int B = p[X + 1] + Y;
|
||
int BA = p[B] + Z;
|
||
int BB = p[B + 1] + Z;
|
||
|
||
// Èíòåðïîëÿöèÿ
|
||
double y1 = lerp(u,
|
||
grad(p[AA], x, y, z),
|
||
grad(p[BA], x - 1, y, z));
|
||
double y2 = lerp(u,
|
||
grad(p[AB], x, y - 1, z),
|
||
grad(p[BB], x - 1, y - 1, z));
|
||
double y3 = lerp(u,
|
||
grad(p[AA + 1], x, y, z - 1),
|
||
grad(p[BA + 1], x - 1, y, z - 1));
|
||
double y4 = lerp(u,
|
||
grad(p[AB + 1], x, y - 1, z - 1),
|
||
grad(p[BB + 1], x - 1, y - 1, z - 1));
|
||
|
||
double z1 = lerp(v, y1, y2);
|
||
double z2 = lerp(v, y3, y4);
|
||
return lerp(w, z1, z2);
|
||
}
|
||
|
||
double ImprovedNoise::lerp(double t, double a, double b)
|
||
{
|
||
return a + t * (b - a);
|
||
}
|
||
|
||
// 3D ãðàäèåíò (èñïîëüçóåòñÿ â noise)
|
||
double ImprovedNoise::grad(int hash, double x, double y, double z)
|
||
{
|
||
int h = hash & 15; // ìëàäøèå 4 áèòà
|
||
double u = h < 8 ? x : y;
|
||
double v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
|
||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||
}
|
||
|
||
// 2D ãðàäèåíò (èñïîëüçóåòñÿ â add() äëÿ ñëó÷àÿ ySize==1)
|
||
double ImprovedNoise::grad2(int hash, double x, double z)
|
||
{
|
||
int h = hash & 15;
|
||
double u = (h & 8) ? x : z; // àëüòåðíàòèâíîå ðàñïðåäåëåíèå äëÿ 2D
|
||
double v = (h < 4) ? 0 : (h == 12 || h == 14 ? x : z);
|
||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||
}
|
||
|
||
// Synth èíòåðôåéñ
|
||
double ImprovedNoise::getValue(double x, double y)
|
||
{
|
||
return noise(x, y, 0.0);
|
||
}
|
||
|
||
double ImprovedNoise::getValue(double x, double y, double z)
|
||
{
|
||
return noise(x, y, z);
|
||
}
|
||
|
||
// ----------------------------------------------------------------------
|
||
// Ìåòîä add – áûñòðîå çàïîëíåíèå áóôåðà çíà÷åíèÿìè øóìà äëÿ ïðÿìîóãîëüíîé îáëàñòè
|
||
// (îïòèìèçèðîâàí, ÷òîáû èçáåæàòü ïîâòîðíûõ âû÷èñëåíèé ãðàäèåíòîâ)
|
||
void ImprovedNoise::add(doubleArray buffer, double _x, double _y, double _z,
|
||
int xSize, int ySize, int zSize,
|
||
double xs, double ys, double zs, double pow) const
|
||
{
|
||
double invPow = 1.0 / pow;
|
||
int idx = 0; // èíäåêñ â áóôåðå
|
||
|
||
if (ySize == 1)
|
||
{
|
||
// Îïòèìèçàöèÿ äëÿ 2D ñðåçà (y ôèêñèðîâàí)
|
||
for (int xx = 0; xx < xSize; ++xx)
|
||
{
|
||
double x = _x + xx * xs + xo;
|
||
int X = static_cast<int>(std::floor(x)) & 255;
|
||
double dx = x - std::floor(x);
|
||
double u = dx * dx * dx * (dx * (dx * 6.0 - 15.0) + 10.0);
|
||
|
||
for (int zz = 0; zz < zSize; ++zz)
|
||
{
|
||
double z = _z + zz * zs + zo;
|
||
int Z = static_cast<int>(std::floor(z)) & 255;
|
||
double dz = z - std::floor(z);
|
||
double w = dz * dz * dz * (dz * (dz * 6.0 - 15.0) + 10.0);
|
||
|
||
int A = p[X];
|
||
int AA = p[A] + Z;
|
||
int B = p[X + 1];
|
||
int BA = p[B] + Z;
|
||
|
||
double v0 = lerp(u,
|
||
grad2(p[AA], dx, dz),
|
||
grad2(p[BA], dx - 1.0, dz));
|
||
double v2 = lerp(u,
|
||
grad2(p[AA + 1], dx, dz - 1.0),
|
||
grad2(p[BA + 1], dx - 1.0, dz - 1.0));
|
||
|
||
buffer[idx++] += lerp(w, v0, v2) * invPow;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Ïîëíàÿ 3D âåðñèÿ ñ êýøèðîâàíèåì ïî Y
|
||
int yPrev = -1;
|
||
int A, AA, AB, B, BA, BB;
|
||
double vv0, vv1, vv2, vv3;
|
||
|
||
for (int xx = 0; xx < xSize; ++xx)
|
||
{
|
||
double x = _x + xx * xs + xo;
|
||
int X = static_cast<int>(std::floor(x)) & 255;
|
||
double dx = x - std::floor(x);
|
||
double u = dx * dx * dx * (dx * (dx * 6.0 - 15.0) + 10.0);
|
||
|
||
for (int zz = 0; zz < zSize; ++zz)
|
||
{
|
||
double z = _z + zz * zs + zo;
|
||
int Z = static_cast<int>(std::floor(z)) & 255;
|
||
double dz = z - std::floor(z);
|
||
double w = dz * dz * dz * (dz * (dz * 6.0 - 15.0) + 10.0);
|
||
|
||
for (int yy = 0; yy < ySize; ++yy)
|
||
{
|
||
double y = _y + yy * ys + yo;
|
||
int Y = static_cast<int>(std::floor(y)) & 255;
|
||
double dy = y - std::floor(y);
|
||
double v = dy * dy * dy * (dy * (dy * 6.0 - 15.0) + 10.0);
|
||
|
||
// Êýøèðóåì çíà÷åíèÿ, çàâèñÿùèå òîëüêî îò Y
|
||
if (yy == 0 || Y != yPrev)
|
||
{
|
||
yPrev = Y;
|
||
A = p[X] + Y;
|
||
AA = p[A] + Z;
|
||
AB = p[A + 1] + Z;
|
||
B = p[X + 1] + Y;
|
||
BA = p[B] + Z;
|
||
BB = p[B + 1] + Z;
|
||
|
||
vv0 = lerp(u, grad(p[AA], dx, dy, dz), grad(p[BA], dx - 1.0, dy, dz));
|
||
vv1 = lerp(u, grad(p[AB], dx, dy - 1.0, dz), grad(p[BB], dx - 1.0, dy - 1.0, dz));
|
||
vv2 = lerp(u, grad(p[AA + 1], dx, dy, dz - 1.0), grad(p[BA + 1], dx - 1.0, dy, dz - 1.0));
|
||
vv3 = lerp(u, grad(p[AB + 1], dx, dy - 1.0, dz - 1.0), grad(p[BB + 1], dx - 1.0, dy - 1.0, dz - 1.0));
|
||
}
|
||
|
||
double v0 = lerp(v, vv0, vv1);
|
||
double v1 = lerp(v, vv2, vv3);
|
||
buffer[idx++] += lerp(w, v0, v1) * invPow;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|