MinecraftConsoles/Minecraft.World/ImprovedNoise.cpp
2026-03-11 20:04:11 +03:00

220 lines
7.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
}
}
}
}