| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- #include "rain_pipeline.h"
- #include "../../ground/rain_gpu.h"
- #include "../backend.h"
- #include "../camera.h"
- #include "../render_constants.h"
- #include "../shader_cache.h"
- #include <QDebug>
- #include <QOpenGLContext>
- #include <cmath>
- #include <numbers>
- #include <random>
- namespace Render::GL::BackendPipelines {
- using namespace Render::GL::VertexAttrib;
- using namespace Render::GL::ComponentCount;
- namespace {
- constexpr float kRainColorR = 0.7F;
- constexpr float kRainColorG = 0.75F;
- constexpr float kRainColorB = 0.85F;
- constexpr float kSnowColorR = 1.0F;
- constexpr float kSnowColorG = 1.0F;
- constexpr float kSnowColorB = 1.0F;
- void clear_gl_errors() {
- #ifndef NDEBUG
- while (glGetError() != GL_NO_ERROR) {
- }
- #endif
- }
- auto check_gl_error(const char *operation) -> bool {
- #ifndef NDEBUG
- GLenum err = glGetError();
- if (err != GL_NO_ERROR) {
- qWarning() << "RainPipeline GL error in" << operation << ":" << err;
- return false;
- }
- #else
- Q_UNUSED(operation);
- #endif
- return true;
- }
- } // namespace
- auto RainPipeline::initialize() -> bool {
- if (m_shader_cache == nullptr) {
- qWarning() << "RainPipeline::initialize: null ShaderCache";
- return false;
- }
- initializeOpenGLFunctions();
- clear_gl_errors();
- m_rain_shader = m_shader_cache->get("rain");
- if (m_rain_shader == nullptr) {
- m_rain_shader = m_shader_cache->load(
- "rain", QStringLiteral(":/assets/shaders/rain.vert"),
- QStringLiteral(":/assets/shaders/rain.frag"));
- }
- if (m_rain_shader == nullptr) {
- qWarning() << "RainPipeline: Failed to get rain shader";
- return false;
- }
- cache_uniforms();
- generate_rain_drops();
- if (!create_rain_geometry()) {
- qWarning() << "RainPipeline: Failed to create rain geometry";
- return false;
- }
- qInfo() << "RainPipeline initialized successfully";
- return is_initialized();
- }
- void RainPipeline::shutdown() {
- shutdown_geometry();
- m_rain_shader = nullptr;
- m_rain_drops.clear();
- }
- void RainPipeline::shutdown_geometry() {
- if (QOpenGLContext::currentContext() == nullptr) {
- m_vao = 0;
- m_vertex_buffer = 0;
- m_index_buffer = 0;
- m_index_count = 0;
- return;
- }
- initializeOpenGLFunctions();
- clear_gl_errors();
- if (m_vao != 0) {
- glDeleteVertexArrays(1, &m_vao);
- m_vao = 0;
- }
- if (m_vertex_buffer != 0) {
- glDeleteBuffers(1, &m_vertex_buffer);
- m_vertex_buffer = 0;
- }
- if (m_index_buffer != 0) {
- glDeleteBuffers(1, &m_index_buffer);
- m_index_buffer = 0;
- }
- m_index_count = 0;
- }
- void RainPipeline::cache_uniforms() {
- if (m_rain_shader == nullptr) {
- return;
- }
- m_uniforms.view_proj = m_rain_shader->uniform_handle("u_view_proj");
- m_uniforms.time = m_rain_shader->uniform_handle("u_time");
- m_uniforms.intensity = m_rain_shader->uniform_handle("u_intensity");
- m_uniforms.camera_pos = m_rain_shader->uniform_handle("u_camera_pos");
- m_uniforms.rain_color = m_rain_shader->uniform_handle("u_rain_color");
- m_uniforms.wind = m_rain_shader->uniform_handle("u_wind");
- m_uniforms.weather_type = m_rain_shader->uniform_handle("u_weather_type");
- m_uniforms.wind_strength = m_rain_shader->uniform_handle("u_wind_strength");
- }
- auto RainPipeline::is_initialized() const -> bool {
- return m_rain_shader != nullptr && m_vao != 0 && m_index_count > 0;
- }
- void RainPipeline::generate_rain_drops() {
- m_rain_drops.clear();
- m_rain_drops.reserve(k_max_drops);
- std::mt19937 rng(42);
- std::uniform_real_distribution<float> dist_xz(-k_area_radius, k_area_radius);
- std::uniform_real_distribution<float> dist_y(0.0F, k_area_height);
- std::uniform_real_distribution<float> dist_speed(0.8F, 1.2F);
- std::uniform_real_distribution<float> dist_alpha(0.3F, 0.7F);
- for (std::size_t i = 0; i < k_max_drops; ++i) {
- RainDropData drop;
- drop.position = QVector3D(dist_xz(rng), dist_y(rng), dist_xz(rng));
- drop.speed = k_drop_speed * dist_speed(rng);
- drop.length = k_drop_length;
- drop.alpha = dist_alpha(rng);
- m_rain_drops.push_back(drop);
- }
- }
- struct RainVertex {
- float position[3];
- float offset[3];
- float alpha;
- };
- auto RainPipeline::create_rain_geometry() -> bool {
- initializeOpenGLFunctions();
- shutdown_geometry();
- clear_gl_errors();
- std::vector<RainVertex> vertices;
- std::vector<unsigned int> indices;
- vertices.reserve(m_rain_drops.size() * 2);
- indices.reserve(m_rain_drops.size() * 2);
- for (std::size_t i = 0; i < m_rain_drops.size(); ++i) {
- const auto &drop = m_rain_drops[i];
- RainVertex top;
- top.position[0] = drop.position.x();
- top.position[1] = drop.position.y();
- top.position[2] = drop.position.z();
- top.offset[0] = 0.0F;
- top.offset[1] = 0.0F;
- top.offset[2] = drop.speed;
- top.alpha = drop.alpha;
- vertices.push_back(top);
- RainVertex bottom;
- bottom.position[0] = drop.position.x();
- bottom.position[1] = drop.position.y() - drop.length;
- bottom.position[2] = drop.position.z();
- bottom.offset[0] = 0.0F;
- bottom.offset[1] = -drop.length;
- bottom.offset[2] = drop.speed;
- bottom.alpha = drop.alpha * 0.3F;
- vertices.push_back(bottom);
- auto base = static_cast<unsigned int>(i * 2);
- indices.push_back(base);
- indices.push_back(base + 1);
- }
- glGenVertexArrays(1, &m_vao);
- if (!check_gl_error("glGenVertexArrays") || m_vao == 0) {
- return false;
- }
- glBindVertexArray(m_vao);
- if (!check_gl_error("glBindVertexArray")) {
- glDeleteVertexArrays(1, &m_vao);
- m_vao = 0;
- return false;
- }
- glGenBuffers(1, &m_vertex_buffer);
- glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER,
- static_cast<GLsizeiptr>(vertices.size() * sizeof(RainVertex)),
- vertices.data(), GL_STATIC_DRAW);
- if (!check_gl_error("vertex buffer")) {
- shutdown_geometry();
- return false;
- }
- glGenBuffers(1, &m_index_buffer);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER,
- static_cast<GLsizeiptr>(indices.size() * sizeof(unsigned int)),
- indices.data(), GL_STATIC_DRAW);
- if (!check_gl_error("index buffer")) {
- shutdown_geometry();
- return false;
- }
- m_index_count = static_cast<GLsizei>(indices.size());
- glEnableVertexAttribArray(VertexAttrib::Position);
- glVertexAttribPointer(
- VertexAttrib::Position, ComponentCount::Vec3, GL_FLOAT, GL_FALSE,
- sizeof(RainVertex),
- reinterpret_cast<void *>(offsetof(RainVertex, position)));
- glEnableVertexAttribArray(VertexAttrib::Normal);
- glVertexAttribPointer(VertexAttrib::Normal, ComponentCount::Vec3, GL_FLOAT,
- GL_FALSE, sizeof(RainVertex),
- reinterpret_cast<void *>(offsetof(RainVertex, offset)));
- glEnableVertexAttribArray(VertexAttrib::TexCoord);
- glVertexAttribPointer(VertexAttrib::TexCoord, 1, GL_FLOAT, GL_FALSE,
- sizeof(RainVertex),
- reinterpret_cast<void *>(offsetof(RainVertex, alpha)));
- glBindVertexArray(0);
- if (!check_gl_error("vertex attributes")) {
- shutdown_geometry();
- return false;
- }
- return true;
- }
- void RainPipeline::render(const Camera &cam, const RainBatchParams ¶ms) {
- if (!is_initialized() || params.intensity < 0.01F) {
- return;
- }
- clear_gl_errors();
- GLboolean depth_mask_enabled = GL_TRUE;
- glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask_enabled);
- GLboolean blend_enabled = glIsEnabled(GL_BLEND);
- GLboolean depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
- glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- if (params.weather_type == Game::Map::WeatherType::Snow) {
- glEnable(GL_PROGRAM_POINT_SIZE);
- }
- m_rain_shader->use();
- glBindVertexArray(m_vao);
- QMatrix4x4 view_proj = cam.get_projection_matrix() * cam.get_view_matrix();
- QVector3D camera_pos = cam.get_position();
- QVector3D particle_color;
- if (params.weather_type == Game::Map::WeatherType::Snow) {
- particle_color = QVector3D(kSnowColorR, kSnowColorG, kSnowColorB);
- } else {
- particle_color = QVector3D(kRainColorR, kRainColorG, kRainColorB);
- }
- m_rain_shader->set_uniform(m_uniforms.view_proj, view_proj);
- m_rain_shader->set_uniform(m_uniforms.time, params.time);
- m_rain_shader->set_uniform(m_uniforms.intensity, params.intensity);
- m_rain_shader->set_uniform(m_uniforms.camera_pos, camera_pos);
- m_rain_shader->set_uniform(m_uniforms.rain_color, particle_color);
- m_rain_shader->set_uniform(m_uniforms.wind, params.wind_direction);
- m_rain_shader->set_uniform(m_uniforms.weather_type,
- static_cast<int>(params.weather_type));
- m_rain_shader->set_uniform(m_uniforms.wind_strength, params.wind_strength);
- if (params.weather_type == Game::Map::WeatherType::Snow) {
- glDrawElements(GL_POINTS, m_index_count / 2, GL_UNSIGNED_INT, nullptr);
- } else {
- glDrawElements(GL_LINES, m_index_count, GL_UNSIGNED_INT, nullptr);
- }
- glBindVertexArray(0);
- if (params.weather_type == Game::Map::WeatherType::Snow) {
- glDisable(GL_PROGRAM_POINT_SIZE);
- }
- glDepthMask(depth_mask_enabled);
- if (!blend_enabled) {
- glDisable(GL_BLEND);
- }
- if (!depth_test_enabled) {
- glDisable(GL_DEPTH_TEST);
- }
- }
- } // namespace Render::GL::BackendPipelines
|