17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-30 23:40:29 +01:00

Draw volumetric clouds, their shadows, a volumetric fog and catalogue stars from a new weather system in the GL 4.6 renderer

This commit is contained in:
2026-10-16 21:44:47 +02:00
parent d509775269
commit 2be85410ce
47 changed files with 5092 additions and 74 deletions

View File

@@ -190,6 +190,7 @@ bool opengl46_renderer::Init(GLFWwindow *Window)
try
{
m_sky.init();
m_weather.init();
m_instancecull.init();
m_hiz.init();
m_exposure.init();
@@ -485,6 +486,7 @@ bool opengl46_renderer::init_viewport(viewport_config &vp)
scene_ubo->bind_uniform();
light_ssbo->bind_base();
m_sky.bind();
m_weather.bind();
m_exposure.bind();
vp.clusters = std::make_unique<gl::cluster_grid>();
@@ -627,7 +629,12 @@ bool opengl46_renderer::Render()
// the light of the sky for the render: colours of the sun, ambient light and fog from the atmosphere where it is
// used, the directional part of the ambient light
m_fogcolor = Global.FogColor;
// the volumetric clouds of the previous frame tell the sky whether to look overcast and dim the sun itself
m_sky.set_clouds(m_weather.clouds_drawn(), m_weather.cloud_shadows());
m_sky.update(m_sunlight, m_fogcolor, simulation::Environment.skydome(), simulation::Environment.sun().getDirection(), simulation::Environment.sun().getAngle());
// fog, clouds and stars of the weather, in the light of the sky worked out above
if (false == Global.gfx_skiprendering)
m_weather.update(m_sky, -m_sunlight.direction, glm::vec3{m_sunlight.diffuse} * simulation::Environment.light_intensity(), glm::vec3{m_sunlight.ambient}, m_fogcolor, Global.pCamera.Pos);
// lamps of models and vehicles around the camera and the cab lamp, for the views of the frame to take into their light buffers
if ((false == Global.gfx_skiprendering) && (simulation::Region != nullptr))
m_locallights.gather(Global.pCamera.Pos, *simulation::Region, m_geometry, m_framestamp);
@@ -729,6 +736,7 @@ void opengl46_renderer::SwapBuffers()
if (auto const culltime = m_cullstimer.result())
m_debugtimestext += " cull: " + to_string(static_cast<double>(*culltime) / 1000000.0, 3) + " ms\n";
m_debugtimestext += m_sky.info_times();
m_debugtimestext += m_weather.info_times();
m_debugtimestext += m_exposure.info_times();
m_debugtimestext += m_ao.info_times();
m_debugtimestext += m_instancecull.info_times();
@@ -834,6 +842,12 @@ void opengl46_renderer::draw_debug_ui()
}
ImGui::End();
if (ImGui::Begin("Weather"))
{
m_weather.draw_debug_ui();
}
ImGui::End();
if (ImGui::Begin("Sky and exposure"))
{
m_sky.draw_debug_ui();
@@ -1068,6 +1082,19 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
Cull_Lights( vp );
}
// the clouds of the view and the fog volume, which take the lights of the clusters and the shadow map of the pass
{
auto const fogtarget{ Global.gfx_skippipeline ? target_size : glm::ivec2{ vp.width, vp.height } };
if( vp.main ) {
if( Global.gfx_shadowmap_enabled )
setup_shadow_bind_map();
m_weather.render_view(
OpenGLMatrices.data( GL_PROJECTION ), glm::mat4{ m_colorpass.pass_camera.modelview() }, m_colorpass.pass_camera.position(), fogtarget,
( m_cablamplit && Global.gfx_lights_clustered && vp.clusters->valid() ) ? 1 : -1 );
}
m_weather.setup_pass( vp.main, fogtarget );
}
glDebug("render environment");
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
@@ -1344,6 +1371,8 @@ if (!Global.gfx_skippipeline)
m_env_fb->bind();
setup_env_map(m_empty_cubemap.get());
// the fog volume is the one of the main view
m_weather.setup_pass(false, glm::ivec2{static_cast<int>(gl::ENVMAP_SIZE)});
setup_matrices();
// the light buffer holds what the last color pass left in it, in the view space of its camera, while the face is drawn
@@ -2096,6 +2125,9 @@ bool opengl46_renderer::Render(world_environment *Environment)
Bind_Material(null_handle);
::glPushMatrix();
// the sky gets its fog all at once, laid over it with the clouds (opengl46_weather::draw_sky)
auto const fogdensity{model_ubs.fog_density};
model_ubs.fog_density = 0.f;
// skydome
// drawn with 500m radius to blend in if the fog range is low
@@ -2118,28 +2150,18 @@ bool opengl46_renderer::Render(world_environment *Environment)
::glBlendFunc( GL_SRC_ALPHA, GL_ONE );
// stars
if (Environment->m_stars.m_stars != nullptr && Global.fFogEnd > 500.f)
{
// setup
::glPushMatrix();
::glRotatef(Environment->m_stars.m_latitude, 1.f, 0.f, 0.f); // ustawienie osi OY na północ
::glRotatef(-std::fmod((float)Global.fTimeAngleDeg, 360.f), 0.f, 1.f, 0.f); // obrót dobowy osi OX
auto const &modelview = OpenGLMatrices.data(GL_MODELVIEW);
// render
Render(Environment->m_stars.m_stars, nullptr, 1.0);
// post-render cleanup
::glPopMatrix();
}
// stars of the catalogue, turned by the sidereal time; the fog and the clouds go over them
m_weather.draw_stars(modelview, Environment->m_sun.getAngle(), Environment->m_sun.getSiderealTime(), Environment->m_sun.getLatitude());
::glBlendFunc( GL_SRC_ALPHA, GL_ONE );
// celestial bodies
m_celestial_shader->bind();
m_empty_vao->bind();
auto const &modelview = OpenGLMatrices.data(GL_MODELVIEW);
auto const fogfactor{std::clamp(Global.fFogEnd / 2000.f, 0.f, 1.f)}; // stronger fog reduces opacity of the celestial bodies
// the fog and the clouds laid over the sky hide the sun and the moon; without the clouds the overcast fades them
auto const overcastfactor{m_weather.clouds_drawn() ? 1.f : std::clamp(1.5f - Global.Overcast, 0.f, 1.f)};
float const duskfactor = 1.0f - std::clamp(std::abs(Environment->m_sun.getAngle()), 0.0f, 12.0f) / 12.0f;
glm::vec3 suncolor = glm::mix(glm::vec3(1.0f, 242.0f / 255.0f, 231.0f / 255.0f), glm::vec3(235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f), duskfactor);
suncolor = m_sky.sun_disc_color(suncolor);
@@ -2147,7 +2169,7 @@ bool opengl46_renderer::Render(world_environment *Environment)
// sun
{
Bind_Texture(0, m_suntexture);
glm::vec4 color(suncolor.x, suncolor.y, suncolor.z, std::clamp(1.5f - Global.Overcast, 0.f, 1.f) * fogfactor);
glm::vec4 color(suncolor.x, suncolor.y, suncolor.z, overcastfactor);
auto const sunvector = Environment->m_sun.getDirection();
/*float const size = std::lerp( // TODO: expose distance/scale factor from the moon object
@@ -2166,7 +2188,7 @@ bool opengl46_renderer::Render(world_environment *Environment)
glm::vec3 mooncolor(1.0f, 0.9490196f, 0.9058824f);
glm::vec4 color(mooncolor.r, mooncolor.g, mooncolor.b,
// fade the moon if it's near the sun in the sky, especially during the day
std::max<float>(0.f, 1.0 - 0.5 * Global.fLuminance - 0.65 * std::max(0.f, glm::dot(Environment->m_sun.getDirection(), Environment->m_moon.getDirection()))) * fogfactor);
std::max<float>(0.f, 1.0 - 0.5 * Global.fLuminance - 0.65 * std::max(0.f, glm::dot(Environment->m_sun.getDirection(), Environment->m_moon.getDirection()))) * overcastfactor);
auto const moonvector = Environment->m_moon.getDirection();
@@ -2241,31 +2263,19 @@ bool opengl46_renderer::Render(world_environment *Environment)
::glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// clouds
if (Environment->m_clouds.mdCloud)
// clouds of the weather and the fog over the sky: of the main view in its colour pass, of the panorama around the camera in
// the other views and in the faces of the environment map
{
// setup
auto const color {
glm::clamp(
( glm::vec3 { Global.DayLight.ambient }
+ 0.35f * glm::vec3{ Global.DayLight.diffuse } ) * simulation::Environment.light_intensity()
* 0.5f,
glm::vec3{ 0.f }, glm::vec3{ 1.f } ) };
// write cloud color into material
TSubModel *mdl = Environment->m_clouds.mdCloud->Root;
if (mdl->m_material != null_handle)
m_materials.material(mdl->m_material).params[0] = glm::vec4(color * 2.5f, 1.0f);
// render
Render(Environment->m_clouds.mdCloud, nullptr, 100.0);
Render_Alpha(Environment->m_clouds.mdCloud, nullptr, 100.0);
// post-render cleanup
auto const mainview{(m_renderpass.draw_mode == rendermode::color) && (m_current_viewport != nullptr) && m_current_viewport->main};
m_empty_vao->bind();
m_weather.draw_sky(OpenGLMatrices.data(GL_PROJECTION), modelview, mainview);
}
gl::program::unbind();
gl::vao::unbind();
::glPopMatrix();
model_ubs.fog_density = fogdensity;
model_ubo->update(model_ubs);
m_sunlight.apply_angle();
m_sunlight.apply_intensity();
@@ -2277,8 +2287,9 @@ bool opengl46_renderer::Render(world_environment *Environment)
// turn on moon shadows after nautical twilight, if the moon is actually up
m_shadowcolor = colors::shadow;
}
// soften shadows depending on sky overcast factor
m_shadowcolor = glm::min(colors::white, m_shadowcolor + ((colors::white - colors::shadow) * Global.Overcast));
// soften shadows depending on sky overcast factor, unless the shadows of the clouds hold back the sun where they fall
if (false == m_weather.cloud_shadows())
m_shadowcolor = glm::min(colors::white, m_shadowcolor + ((colors::white - colors::shadow) * Global.Overcast));
setup_shadow_color( m_shadowcolor);
@@ -6522,8 +6533,9 @@ void opengl46_renderer::Update_Lights(light_array &Lights, bool const Headlights
light_data.fog_color = m_fogcolor;
if (Global.fFogEnd > 0)
{
m_fogrange = Global.fFogEnd / std::max(1.f, Global.Overcast * 2.f);
model_ubs.fog_density = 1.0f / m_fogrange;
// the fog of the weather; the regular density is a reference the shading scales the fog of a draw with
m_fogrange = m_weather.fog_range();
model_ubs.fog_density = m_weather.fog_density();
}
else
{