17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-05 19:29:11 +01:00

Improve rain shader

This commit is contained in:
2026-10-26 15:51:56 +01:00
parent a6bdeeaa2b
commit 719c729929
43 changed files with 5620 additions and 355 deletions

View File

@@ -86,6 +86,7 @@ bool opengl46_renderer::Init(GLFWwindow *Window)
m_window = Window;
gl::glsl_common_setup();
m_windscreenwater.set_host({[this](material_handle const Material) { return &m_materials.material(Material); }});
if (true == Global.ScaleSpecularValues)
{
@@ -1086,7 +1087,8 @@ void opengl46_renderer::SwapBuffers()
+ ( Global.gfx_lights_clustered ? "clustered" : "first " + std::to_string( std::max( Global.DynamicLightCount, 0 ) ) )
+ "\n" + m_locallights.info()
+ m_localshadows.info()
+ m_gpuparticles.info();
+ m_gpuparticles.info()
+ m_windscreenwater.info();
if( auto const cullstats = ( m_viewports.empty() || !( Global.gfx_lights_clustered || Global.gfx_lights_clusterheatmap ) ? std::nullopt : m_viewports.front()->clusters->stats() ) ) {
statstext +=
"\ncluster lists: " + std::to_string( cullstats->index_count )
@@ -1599,6 +1601,16 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
float percipitation_intensity = glm::saturate(Global.Overcast - 1.);
scene_ubs.rain_params.x = percipitation_intensity; // % amount of droplets
scene_ubs.rain_params.y = glm::mix(15., 1., percipitation_intensity); // Regeneration time
scene_ubs.rain_params.z = (Global.Weather == "snow:" ? 1.f : 0.f); // flakes on the glass in place of the drops
scene_ubs.rain_params.w = Global.AirTemperature; // how fast the flakes melt
{
// the air the drops on the glass are blown with: the wind as the particles drift with it, less the velocity of the
// vehicle (V is along the front of the vehicle)
glm::dvec3 air{glm::dvec3{simulation::Environment.wind()} * 0.5};
if (TDynamicObject const *owner = Global.pCamera.m_owner)
air -= owner->VectorFront() * owner->MoverParameters->V;
scene_ubs.rain_wind = glm::vec4{glm::vec3{air}, 0.f};
}
if (TDynamicObject const *owner = Global.pCamera.m_owner; owner && !!owner->MoverParameters->CabActive)
{
for (int i = 0; i < 4; ++i)
@@ -1643,6 +1655,10 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
scene_ubs.inv_view = glm::inverse( glm::mat4{ glm::mat3{ m_colorpass.pass_camera.modelview() } } );
scene_ubo->update(scene_ubs);
scene_ubo->bind_uniform();
// the water on the windscreens of the cab: a step of its simulation once a frame, its storage for the glasses of every view
if (vp.main)
m_windscreenwater.update(Timer::GetDeltaTime());
m_windscreenwater.bind();
if (Global.bWireFrame)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

View File

@@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "rendering/opengl46/opengl46light.h"
#include "rendering/opengl46/opengl46particles.h"
#include "rendering/opengl46/opengl46gpuparticles.h"
#include "rendering/opengl46/opengl46water.h"
#include "rendering/opengl46/opengl46skydome.h"
#include "rendering/opengl46/opengl46precipitation.h"
#include "simulation/simulationenvironment.h"
@@ -533,6 +534,7 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
opengl46_precipitation m_precipitationrenderer;
opengl46_particles m_particlerenderer; // particle visualization subsystem
opengl46_gpu_particles m_gpuparticles; // the smoke, rain and snow of the gpu (gfx.smoke.gpu, gfx.precipitation.gpu)
opengl46_windscreen_water m_windscreenwater; // the water on the windscreens of the cab of the train
bool m_particlesoft{false}; // the depth for the soft particles is bound in the colour pass being drawn
float m_framerate;

View File

@@ -0,0 +1,116 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/opengl46/opengl46water.h"
#include "rendering/renderer.h"
#include "utilities/Logs.h"
namespace
{
GLuint groups(std::size_t const Count)
{
return static_cast<GLuint>((Count + gl::WATER_GROUP_SIZE - 1) / gl::WATER_GROUP_SIZE);
}
} // namespace
bool opengl46_windscreen_water::gpu_init()
{
try
{
std::array<char const *, pass::count> const names{"water_trail.comp", "water_spawn.comp", "water_move.comp", "water_clear.comp", "water_grid.comp",
"water_merge.comp", "water_gather.comp", "water_settle.comp", "water_bake.comp"};
for (std::size_t i = 0; i < names.size(); ++i)
{
gl::shader shader(names[i]);
m_programs[i] = std::make_unique<gl::program>(std::vector<std::reference_wrapper<const gl::shader>>{shader});
}
}
catch (gl::shader_exception const &e)
{
ErrorLog("windscreen water: can't use the programs of the simulation: " + std::string(e.what()));
return false;
}
m_storage = std::make_unique<gl::ssbo>(static_cast<GLsizeiptr>(gl::WATER_STORAGE_SIZE), gl::WATER_SSBO_BINDING);
::glClearNamedBufferData(*m_storage, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);
m_block = std::make_unique<gl::ubo>(sizeof(gl::water_ubs), gl::WATER_UBO_BINDING);
return true;
}
void opengl46_windscreen_water::bind() const
{
if (m_storage)
m_storage->bind_base();
}
void opengl46_windscreen_water::gpu_setup(std::size_t const Slot, std::vector<glm::vec4> const &Axes)
{
if (!m_storage)
return;
// the frames before may still draw with the storage
::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT);
// the drops, the grid, the paths, the header and the counts of the slot cleared, the axes of the map put in
for (auto const &part : gl::water_slot_parts(Slot))
::glClearNamedBufferSubData(*m_storage, GL_R32UI, static_cast<GLintptr>(part.first), static_cast<GLsizeiptr>(part.second), GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);
auto const axes{gl::water_slot_parts(Slot)[1]};
m_storage->update(Axes.data(), static_cast<GLintptr>(axes.first), static_cast<GLsizeiptr>(std::min(axes.second, Axes.size() * sizeof(glm::vec4))));
::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT);
}
bool opengl46_windscreen_water::gpu_bake(std::size_t const Slot, texture_handle const Mask, gl::water_ubs const &Block)
{
if ((!m_storage) || (Mask == null_handle))
return false;
auto &texture{GfxRenderer->Texture(Mask)};
if ((false == texture.create()) || (false == texture.get_is_ready()) || (texture.get_id() == 0))
return false;
m_storage->bind_base();
m_block->update(Block);
m_block->bind_uniform();
::glBindTextureUnit(static_cast<GLuint>(gl::WATER_MASK_TEX), static_cast<GLuint>(texture.get_id()));
m_programs[pass::bake]->dispatch(groups(static_cast<std::size_t>(gl::WATER_MAP) * gl::WATER_MAP));
::glBindTextureUnit(static_cast<GLuint>(gl::WATER_MASK_TEX), 0);
::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
gl::program::unbind();
return true;
}
void opengl46_windscreen_water::gpu_step(gl::water_ubs const &Block, std::uint32_t const Tries)
{
if (!m_storage)
return;
m_storage->bind_base();
m_block->update(Block);
m_block->bind_uniform();
auto const slots{static_cast<GLuint>(gl::WATER_SLOTS)};
auto const drops{groups(gl::WATER_DROPS)};
auto const cells{groups(static_cast<std::size_t>(gl::WATER_GRID) * gl::WATER_GRID)};
auto const run = [&](pass const Pass, GLuint const Groups) {
if (Groups == 0)
return;
m_programs[Pass]->dispatch(Groups, slots);
::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
};
// the wetted paths the blades went over in the step wiped
if (Block.blades != Block.blades_before)
run(pass::trail, groups(static_cast<std::size_t>(gl::WATER_TRAIL) * gl::WATER_TRAIL));
run(pass::spawn, groups(Tries));
run(pass::move, drops);
run(pass::clear, cells);
run(pass::grid, drops);
run(pass::merge, drops);
run(pass::gather, drops);
run(pass::settle, drops);
run(pass::clear, cells);
run(pass::grid, drops);
gl::program::unbind();
}

View File

@@ -0,0 +1,55 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <array>
#include <memory>
#include "rendering/common/windscreenwater.h"
#include "gl/shader.h"
#include "gl/ssbo.h"
#include "gl/ubo.h"
// the water on the windscreens for the opengl 4.6 renderer (gfx::windscreen_water): the storage of the water, the block of the
// step and the compute programs
class opengl46_windscreen_water : public gfx::windscreen_water
{
public:
opengl46_windscreen_water() = default;
~opengl46_windscreen_water() override = default;
// the storage bound to its point for the glasses drawn next (the bindings are kept by every context of its own)
void bind() const;
protected:
bool gpu_init() override;
void gpu_setup(std::size_t Slot, std::vector<glm::vec4> const &Axes) override;
bool gpu_bake(std::size_t Slot, texture_handle Mask, gl::water_ubs const &Block) override;
void gpu_step(gl::water_ubs const &Block, std::uint32_t Tries) override;
private:
// the passes of the step, in their order
enum pass
{
trail,
spawn,
move,
clear,
grid,
merge,
gather,
settle,
bake,
count
};
std::array<std::unique_ptr<gl::program>, pass::count> m_programs;
std::unique_ptr<gl::ssbo> m_storage;
std::unique_ptr<gl::ubo> m_block;
};