Weather sim v2: use a fixed initial wind field + a small noise for all 8 climate snapshots

This commit is contained in:
Nikita Lisitsa 2026-04-09 15:18:19 +03:00
parent c097420a50
commit 5b98171283

View file

@ -44,7 +44,7 @@ auto make_perlin(random::generator & rng, int min_octave, int max_octave, float
return pcg::fractal<pcg::perlin<float, 2>>(std::move(octaves), std::move(weights));
}
void make_random_vector_field(random::generator & rng, util::ndarray<math::vector<float, 2>, 2> & result, int min_octave, int max_octave, float scale)
void add_random_vector_field(random::generator & rng, util::ndarray<math::vector<float, 2>, 2> & result, int min_octave, int max_octave, float scale)
{
auto noise_1 = make_perlin(rng, min_octave, max_octave, 2.f);
auto noise_2 = make_perlin(rng, min_octave, max_octave, 2.f);
@ -54,7 +54,7 @@ void make_random_vector_field(random::generator & rng, util::ndarray<math::vecto
for (int x = 0; x < result.width(); ++x)
{
math::point p{(x + 0.5f) / result.height(), (y + 0.5f) / result.width()};
result(x, y) = math::normalized(math::vector{2.f * noise_1(p) - 1.f, 2.f * noise_2(p) - 1.f}) * scale;
result(x, y) += math::normalized(math::vector{2.f * noise_1(p) - 1.f, 2.f * noise_2(p) - 1.f}) * scale;
}
}
}
@ -176,7 +176,8 @@ struct solver
int stage = 0;
bool finished = false;
solver(util::ndarray<float, 2> const & terrain, random::generator & rng, int season, int day_night, climate_snapshot & snapshot)
solver(util::ndarray<float, 2> const & terrain, random::generator & rng, int season, int day_night, climate_snapshot & snapshot,
util::ndarray<math::vector<float, 2>, 2> const & base_wind_velocity)
: terrain(terrain)
, rng(rng)
, season(season)
@ -191,7 +192,8 @@ struct solver
snapshot.humidity.resize({N, N}, 0.f);
new_humidity.resize({N, N}, 0.f);
make_random_vector_field(rng, initial_random_wind_velocity, 3, 6, 0.005f);
initial_random_wind_velocity = base_wind_velocity.copy();
add_random_vector_field(rng, initial_random_wind_velocity, 3, 6, 0.002f);
for (int y = 0; y < N; ++y)
for (int x = 0; x < N; ++x)
@ -398,6 +400,8 @@ struct weather_app
// 1 - Day
int day_night = 0;
util::ndarray<math::vector<float, 2>, 2> base_wind_velocity;
climate_snapshot snapshots[4][2];
climate_snapshot average;
climate_snapshot display_snapshot;
@ -417,13 +421,17 @@ struct weather_app
simulation_box = {{{0.f, N}, {0.f, N}}};
terrain.resize({N, N}, 0.f);
auto heightmap = gfx::read_image<std::uint8_t>(io::file_istream{std::filesystem::path{PSEMEK_EXAMPLES_DIR} / "heightmap_seed_3.png"});
auto heightmap = gfx::read_image<std::uint8_t>(io::file_istream{std::filesystem::path{PSEMEK_EXAMPLES_DIR} / "heightmap_seed_1.png"});
for (int y = 0; y < N; ++y)
for (int x = 0; x < N; ++x)
terrain(x, y) = ((heightmap(x, y) / 255.f) * 2048.f - 512.f) / 1024.f;
biomes_map = gfx::read_image<gfx::color_rgba>(io::file_istream{std::filesystem::path{PSEMEK_EXAMPLES_DIR} / "biomes.png"});
base_wind_velocity.resize({N, N}, math::vector{0.f, 0.f});
add_random_vector_field(rng, base_wind_velocity, 3, 6, 0.003f);
context.vsync(false);
}
@ -473,13 +481,13 @@ struct weather_app
}
if (!solver && season < 4)
solver.emplace(terrain, rng, season, day_night, snapshots[season][day_night]);
solver.emplace(terrain, rng, season, day_night, snapshots[season][day_night], base_wind_velocity);
if (!paused)
{
if (solver)
{
for (int i = 0; i < 16; ++i)
for (int i = 0; i < 64; ++i)
{
solver->step();
if (solver->finished)
@ -488,7 +496,7 @@ struct weather_app
}
else if (season == 4 && !rivers.queue.empty())
{
for (int i = 0; i < 16; ++i)
for (int i = 0; i < 64; ++i)
{
propagate_rivers();
if (rivers.queue.empty())