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)); 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_1 = make_perlin(rng, min_octave, max_octave, 2.f);
auto noise_2 = 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) for (int x = 0; x < result.width(); ++x)
{ {
math::point p{(x + 0.5f) / result.height(), (y + 0.5f) / result.width()}; 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; int stage = 0;
bool finished = false; 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) : terrain(terrain)
, rng(rng) , rng(rng)
, season(season) , season(season)
@ -191,7 +192,8 @@ struct solver
snapshot.humidity.resize({N, N}, 0.f); snapshot.humidity.resize({N, N}, 0.f);
new_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 y = 0; y < N; ++y)
for (int x = 0; x < N; ++x) for (int x = 0; x < N; ++x)
@ -398,6 +400,8 @@ struct weather_app
// 1 - Day // 1 - Day
int day_night = 0; int day_night = 0;
util::ndarray<math::vector<float, 2>, 2> base_wind_velocity;
climate_snapshot snapshots[4][2]; climate_snapshot snapshots[4][2];
climate_snapshot average; climate_snapshot average;
climate_snapshot display_snapshot; climate_snapshot display_snapshot;
@ -417,13 +421,17 @@ struct weather_app
simulation_box = {{{0.f, N}, {0.f, N}}}; simulation_box = {{{0.f, N}, {0.f, N}}};
terrain.resize({N, N}, 0.f); 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 y = 0; y < N; ++y)
for (int x = 0; x < N; ++x) for (int x = 0; x < N; ++x)
terrain(x, y) = ((heightmap(x, y) / 255.f) * 2048.f - 512.f) / 1024.f; 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"}); 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); context.vsync(false);
} }
@ -473,13 +481,13 @@ struct weather_app
} }
if (!solver && season < 4) 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 (!paused)
{ {
if (solver) if (solver)
{ {
for (int i = 0; i < 16; ++i) for (int i = 0; i < 64; ++i)
{ {
solver->step(); solver->step();
if (solver->finished) if (solver->finished)
@ -488,7 +496,7 @@ struct weather_app
} }
else if (season == 4 && !rivers.queue.empty()) else if (season == 4 && !rivers.queue.empty())
{ {
for (int i = 0; i < 16; ++i) for (int i = 0; i < 64; ++i)
{ {
propagate_rivers(); propagate_rivers();
if (rivers.queue.empty()) if (rivers.queue.empty())