Merge pull request #949 from MihailRis/fix-heightmaps

some generation fixes and features
This commit is contained in:
MihailRis 2026-08-24 20:49:43 +03:00 • committed by GitHub
commit bbd9e7065c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 85 additions and 48 deletions

View file

@ -284,6 +284,14 @@ A method that generates simplex noise, adding it to the existing values.
The noise seed can be specified in the `map.noiseSeed` field.
By default, noise octaves are mixed using addition:
$noise_{out} = noise_{source} + noise_{applied} * 2^{-{octave}}$
To obtain more normalized multi-octave noise, you can enable the `map.normalNoise = true` flag, which changes the scheme:
$noise_{out} = noise_{source} * (1 - 2^{-{octave}}) + noise_{applied} * 2^{-{octave}}$
```lua
map:noise(
-- coordinate offset
@ -313,6 +321,10 @@ The noise seed can be specified in the `map.noiseSeed` field.
![image](../images/cell-noise.gif)
> [!NOTE] cell noise looks better with `map.normalNoise = true`
![image](../images/normal-cell-noise.png)
### heightmap:resize(...)
```lua

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View file

@ -287,6 +287,14 @@ map:dump('export:test.png')
Зерно шума может быть указано в поле `map.noiseSeed`.
По-умолчанию октавы шума совмещаются через сложение:
$шум_{результат} = шум_{исходный} + шум_{применяемый} * 2^{-{октава}}$
Для более получения нормализованного многооктавного шума можно включить флаг `map.normalNoise = true`, меняющий схему на:
$шум_{результат} = шум_{исходный} * (1 - 2^{-{октава}}) + шум_{применяемый} * 2^{-{октава}}$
```lua
map:noise(
-- смещение координат
@ -316,6 +324,10 @@ map:noise(
![image](../images/cell-noise.gif)
> [!NOTE] клеточный шум выглядит лучше с `map.normalNoise = true`
![image](../images/normal-cell-noise.png)
### heightmap:resize(...)
```lua

View file

@ -110,6 +110,7 @@ static int l_noise(lua::State* L) {
if (gettop(L) > 6) {
shiftMapY = touserdata<LuaHeightmap>(L, 7);
}
bool normalizedNoise = heightmap->normalizedNoise;
noise->noise_type = noise_type;
for (uint y = 0; y < h; y++) {
for (uint x = 0; x < w; x++) {
@ -126,8 +127,14 @@ static int l_noise(lua::State* L) {
v += shiftMapY->getValues()[i];
}
value += fnlGetNoise2D(noise, u, v) /
static_cast<float>(1 << c) * multiplier;
float noiseValue = fnlGetNoise2D(noise, u, v);
if (normalizedNoise) {
float t = 1.0f / (static_cast<float>(1 << c) * multiplier);
value = value * (1.0f - t) + noiseValue * t;
} else {
float t = 1.0f / static_cast<float>(1 << c) * multiplier;
value += noiseValue * t;
}
heights[i] = value;
}
}
@ -317,6 +324,8 @@ static int l_meta_newindex(lua::State* L) {
auto fieldname = tostring(L, 2);
if (!std::strcmp(fieldname, "noiseSeed")) {
map->setSeed(tointeger(L, 3));
} else if (!std::strcmp(fieldname, "normalNoise")) {
map->normalizedNoise = toboolean(L, 3);
}
}
return 0;

View file

@ -10,6 +10,8 @@ namespace lua {
std::shared_ptr<Heightmap> map;
std::unique_ptr<fnl_state> noise;
public:
bool normalizedNoise = false;
LuaHeightmap(const std::shared_ptr<Heightmap>& map);
LuaHeightmap(uint width, uint height);

View file

@ -18,49 +18,66 @@ namespace util {
constexpr inline float EPSILON = 1e-6f;
class PseudoRandom {
unsigned short seed;
uint32_t seed;
public:
PseudoRandom(unsigned short seed) : seed(seed) {}
explicit PseudoRandom(uint32_t seed) : seed(seed) {}
PseudoRandom() {
seed = static_cast<unsigned short>(time(nullptr));
}
PseudoRandom()
: seed(static_cast<uint32_t>(time(nullptr))) {}
int rand() {
seed = (seed + 0x7ed5 + (seed << 6));
seed = (seed ^ 0xc23c ^ (seed >> 9));
seed = (seed + 0x1656 + (seed << 3));
seed = ((seed + 0xa264) ^ (seed << 4));
seed = (seed + 0xfd70 - (seed << 3));
seed = (seed ^ 0xba49 ^ (seed >> 8));
uint32_t rand() {
seed += 0x7ed55d16u;
seed ^= seed >> 16;
seed *= 0x21f0aaadu;
seed ^= seed >> 15;
seed *= 0x735a2d97u;
seed ^= seed >> 15;
return static_cast<int>(seed);
}
void rand(unsigned char* dst, size_t n) {
for (size_t i = 0; i < n; i++) {
dst[i] = rand();
}
}
int32_t rand32() {
return (rand() << 16) | rand();
return seed;
}
uint32_t randU32() {
return (rand() << 16) | rand();
}
int64_t rand64() {
uint64_t x = randU32();
uint64_t y = randU32();
return (x << 32ULL) | y;
return rand();
}
uint64_t randU64() {
uint64_t x = randU32();
uint64_t y = randU32();
return (x << 32ULL) | y;
return (x << 32) | y;
}
int32_t rand32() {
return static_cast<int32_t>(randU32());
}
int64_t rand64() {
uint64_t x = randU32();
uint64_t y = randU32();
return static_cast<int64_t>((x << 32) | y);
}
void setSeed(uint32_t value) {
seed = value;
if (seed == 0) {
seed = 0x6d2b79f5u;
}
rand();
}
void setSeed(int32_t number1, int32_t number2) {
uint32_t a = static_cast<uint32_t>(number1);
uint32_t b = static_cast<uint32_t>(number2);
uint32_t x = a * 23729u;
uint32_t y = b * 16786u;
seed = (x ^ y ^ (a * b));
if (seed == 0) {
seed = 0x6d2b79f5u;
}
rand();
}
float randFloat() {
@ -70,21 +87,6 @@ namespace util {
double randDouble() {
return randU64() / static_cast<double>(UINT64_MAX);
}
void setSeed(int number1, int number2) {
seed = ((static_cast<unsigned short>(number1 * 23729) |
static_cast<unsigned short>(number2 % 16786)) ^
static_cast<unsigned short>(number2 * number1));
rand();
}
void setSeed(long number) {
number = shuffle_bits_step(number, 0x2222222222222222ull, 1);
number = shuffle_bits_step(number, 0x0c0c0c0c0c0c0c0cull, 2);
number = shuffle_bits_step(number, 0x00f000f000f000f0ull, 4);
seed = number;
rand();
}
};
template<typename T>