rain_pipeline.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include "rain_pipeline.h"
  2. #include "../../ground/rain_gpu.h"
  3. #include "../backend.h"
  4. #include "../camera.h"
  5. #include "../render_constants.h"
  6. #include "../shader_cache.h"
  7. #include <QDebug>
  8. #include <QOpenGLContext>
  9. #include <cmath>
  10. #include <numbers>
  11. #include <random>
  12. namespace Render::GL::BackendPipelines {
  13. using namespace Render::GL::VertexAttrib;
  14. using namespace Render::GL::ComponentCount;
  15. namespace {
  16. constexpr float kRainColorR = 0.7F;
  17. constexpr float kRainColorG = 0.75F;
  18. constexpr float kRainColorB = 0.85F;
  19. constexpr float kSnowColorR = 1.0F;
  20. constexpr float kSnowColorG = 1.0F;
  21. constexpr float kSnowColorB = 1.0F;
  22. void clear_gl_errors() {
  23. #ifndef NDEBUG
  24. while (glGetError() != GL_NO_ERROR) {
  25. }
  26. #endif
  27. }
  28. auto check_gl_error(const char *operation) -> bool {
  29. #ifndef NDEBUG
  30. GLenum err = glGetError();
  31. if (err != GL_NO_ERROR) {
  32. qWarning() << "RainPipeline GL error in" << operation << ":" << err;
  33. return false;
  34. }
  35. #else
  36. Q_UNUSED(operation);
  37. #endif
  38. return true;
  39. }
  40. } // namespace
  41. auto RainPipeline::initialize() -> bool {
  42. if (m_shader_cache == nullptr) {
  43. qWarning() << "RainPipeline::initialize: null ShaderCache";
  44. return false;
  45. }
  46. initializeOpenGLFunctions();
  47. clear_gl_errors();
  48. m_rain_shader = m_shader_cache->get("rain");
  49. if (m_rain_shader == nullptr) {
  50. m_rain_shader = m_shader_cache->load(
  51. "rain", QStringLiteral(":/assets/shaders/rain.vert"),
  52. QStringLiteral(":/assets/shaders/rain.frag"));
  53. }
  54. if (m_rain_shader == nullptr) {
  55. qWarning() << "RainPipeline: Failed to get rain shader";
  56. return false;
  57. }
  58. cache_uniforms();
  59. generate_rain_drops();
  60. if (!create_rain_geometry()) {
  61. qWarning() << "RainPipeline: Failed to create rain geometry";
  62. return false;
  63. }
  64. qInfo() << "RainPipeline initialized successfully";
  65. return is_initialized();
  66. }
  67. void RainPipeline::shutdown() {
  68. shutdown_geometry();
  69. m_rain_shader = nullptr;
  70. m_rain_drops.clear();
  71. }
  72. void RainPipeline::shutdown_geometry() {
  73. if (QOpenGLContext::currentContext() == nullptr) {
  74. m_vao = 0;
  75. m_vertex_buffer = 0;
  76. m_index_buffer = 0;
  77. m_index_count = 0;
  78. return;
  79. }
  80. initializeOpenGLFunctions();
  81. clear_gl_errors();
  82. if (m_vao != 0) {
  83. glDeleteVertexArrays(1, &m_vao);
  84. m_vao = 0;
  85. }
  86. if (m_vertex_buffer != 0) {
  87. glDeleteBuffers(1, &m_vertex_buffer);
  88. m_vertex_buffer = 0;
  89. }
  90. if (m_index_buffer != 0) {
  91. glDeleteBuffers(1, &m_index_buffer);
  92. m_index_buffer = 0;
  93. }
  94. m_index_count = 0;
  95. }
  96. void RainPipeline::cache_uniforms() {
  97. if (m_rain_shader == nullptr) {
  98. return;
  99. }
  100. m_uniforms.view_proj = m_rain_shader->uniform_handle("u_view_proj");
  101. m_uniforms.time = m_rain_shader->uniform_handle("u_time");
  102. m_uniforms.intensity = m_rain_shader->uniform_handle("u_intensity");
  103. m_uniforms.camera_pos = m_rain_shader->uniform_handle("u_camera_pos");
  104. m_uniforms.rain_color = m_rain_shader->uniform_handle("u_rain_color");
  105. m_uniforms.wind = m_rain_shader->uniform_handle("u_wind");
  106. m_uniforms.weather_type = m_rain_shader->uniform_handle("u_weather_type");
  107. m_uniforms.wind_strength = m_rain_shader->uniform_handle("u_wind_strength");
  108. }
  109. auto RainPipeline::is_initialized() const -> bool {
  110. return m_rain_shader != nullptr && m_vao != 0 && m_index_count > 0;
  111. }
  112. void RainPipeline::generate_rain_drops() {
  113. m_rain_drops.clear();
  114. m_rain_drops.reserve(k_max_drops);
  115. std::mt19937 rng(42);
  116. std::uniform_real_distribution<float> dist_xz(-k_area_radius, k_area_radius);
  117. std::uniform_real_distribution<float> dist_y(0.0F, k_area_height);
  118. std::uniform_real_distribution<float> dist_speed(0.8F, 1.2F);
  119. std::uniform_real_distribution<float> dist_alpha(0.3F, 0.7F);
  120. for (std::size_t i = 0; i < k_max_drops; ++i) {
  121. RainDropData drop;
  122. drop.position = QVector3D(dist_xz(rng), dist_y(rng), dist_xz(rng));
  123. drop.speed = k_drop_speed * dist_speed(rng);
  124. drop.length = k_drop_length;
  125. drop.alpha = dist_alpha(rng);
  126. m_rain_drops.push_back(drop);
  127. }
  128. }
  129. struct RainVertex {
  130. float position[3];
  131. float offset[3];
  132. float alpha;
  133. };
  134. auto RainPipeline::create_rain_geometry() -> bool {
  135. initializeOpenGLFunctions();
  136. shutdown_geometry();
  137. clear_gl_errors();
  138. std::vector<RainVertex> vertices;
  139. std::vector<unsigned int> indices;
  140. vertices.reserve(m_rain_drops.size() * 2);
  141. indices.reserve(m_rain_drops.size() * 2);
  142. for (std::size_t i = 0; i < m_rain_drops.size(); ++i) {
  143. const auto &drop = m_rain_drops[i];
  144. RainVertex top;
  145. top.position[0] = drop.position.x();
  146. top.position[1] = drop.position.y();
  147. top.position[2] = drop.position.z();
  148. top.offset[0] = 0.0F;
  149. top.offset[1] = 0.0F;
  150. top.offset[2] = drop.speed;
  151. top.alpha = drop.alpha;
  152. vertices.push_back(top);
  153. RainVertex bottom;
  154. bottom.position[0] = drop.position.x();
  155. bottom.position[1] = drop.position.y() - drop.length;
  156. bottom.position[2] = drop.position.z();
  157. bottom.offset[0] = 0.0F;
  158. bottom.offset[1] = -drop.length;
  159. bottom.offset[2] = drop.speed;
  160. bottom.alpha = drop.alpha * 0.3F;
  161. vertices.push_back(bottom);
  162. auto base = static_cast<unsigned int>(i * 2);
  163. indices.push_back(base);
  164. indices.push_back(base + 1);
  165. }
  166. glGenVertexArrays(1, &m_vao);
  167. if (!check_gl_error("glGenVertexArrays") || m_vao == 0) {
  168. return false;
  169. }
  170. glBindVertexArray(m_vao);
  171. if (!check_gl_error("glBindVertexArray")) {
  172. glDeleteVertexArrays(1, &m_vao);
  173. m_vao = 0;
  174. return false;
  175. }
  176. glGenBuffers(1, &m_vertex_buffer);
  177. glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
  178. glBufferData(GL_ARRAY_BUFFER,
  179. static_cast<GLsizeiptr>(vertices.size() * sizeof(RainVertex)),
  180. vertices.data(), GL_STATIC_DRAW);
  181. if (!check_gl_error("vertex buffer")) {
  182. shutdown_geometry();
  183. return false;
  184. }
  185. glGenBuffers(1, &m_index_buffer);
  186. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
  187. glBufferData(GL_ELEMENT_ARRAY_BUFFER,
  188. static_cast<GLsizeiptr>(indices.size() * sizeof(unsigned int)),
  189. indices.data(), GL_STATIC_DRAW);
  190. if (!check_gl_error("index buffer")) {
  191. shutdown_geometry();
  192. return false;
  193. }
  194. m_index_count = static_cast<GLsizei>(indices.size());
  195. glEnableVertexAttribArray(VertexAttrib::Position);
  196. glVertexAttribPointer(
  197. VertexAttrib::Position, ComponentCount::Vec3, GL_FLOAT, GL_FALSE,
  198. sizeof(RainVertex),
  199. reinterpret_cast<void *>(offsetof(RainVertex, position)));
  200. glEnableVertexAttribArray(VertexAttrib::Normal);
  201. glVertexAttribPointer(VertexAttrib::Normal, ComponentCount::Vec3, GL_FLOAT,
  202. GL_FALSE, sizeof(RainVertex),
  203. reinterpret_cast<void *>(offsetof(RainVertex, offset)));
  204. glEnableVertexAttribArray(VertexAttrib::TexCoord);
  205. glVertexAttribPointer(VertexAttrib::TexCoord, 1, GL_FLOAT, GL_FALSE,
  206. sizeof(RainVertex),
  207. reinterpret_cast<void *>(offsetof(RainVertex, alpha)));
  208. glBindVertexArray(0);
  209. if (!check_gl_error("vertex attributes")) {
  210. shutdown_geometry();
  211. return false;
  212. }
  213. return true;
  214. }
  215. void RainPipeline::render(const Camera &cam, const RainBatchParams &params) {
  216. if (!is_initialized() || params.intensity < 0.01F) {
  217. return;
  218. }
  219. clear_gl_errors();
  220. GLboolean depth_mask_enabled = GL_TRUE;
  221. glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask_enabled);
  222. GLboolean blend_enabled = glIsEnabled(GL_BLEND);
  223. GLboolean depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
  224. glEnable(GL_DEPTH_TEST);
  225. glDepthMask(GL_FALSE);
  226. glEnable(GL_BLEND);
  227. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  228. if (params.weather_type == Game::Map::WeatherType::Snow) {
  229. glEnable(GL_PROGRAM_POINT_SIZE);
  230. }
  231. m_rain_shader->use();
  232. glBindVertexArray(m_vao);
  233. QMatrix4x4 view_proj = cam.get_projection_matrix() * cam.get_view_matrix();
  234. QVector3D camera_pos = cam.get_position();
  235. QVector3D particle_color;
  236. if (params.weather_type == Game::Map::WeatherType::Snow) {
  237. particle_color = QVector3D(kSnowColorR, kSnowColorG, kSnowColorB);
  238. } else {
  239. particle_color = QVector3D(kRainColorR, kRainColorG, kRainColorB);
  240. }
  241. m_rain_shader->set_uniform(m_uniforms.view_proj, view_proj);
  242. m_rain_shader->set_uniform(m_uniforms.time, params.time);
  243. m_rain_shader->set_uniform(m_uniforms.intensity, params.intensity);
  244. m_rain_shader->set_uniform(m_uniforms.camera_pos, camera_pos);
  245. m_rain_shader->set_uniform(m_uniforms.rain_color, particle_color);
  246. m_rain_shader->set_uniform(m_uniforms.wind, params.wind_direction);
  247. m_rain_shader->set_uniform(m_uniforms.weather_type,
  248. static_cast<int>(params.weather_type));
  249. m_rain_shader->set_uniform(m_uniforms.wind_strength, params.wind_strength);
  250. if (params.weather_type == Game::Map::WeatherType::Snow) {
  251. glDrawElements(GL_POINTS, m_index_count / 2, GL_UNSIGNED_INT, nullptr);
  252. } else {
  253. glDrawElements(GL_LINES, m_index_count, GL_UNSIGNED_INT, nullptr);
  254. }
  255. glBindVertexArray(0);
  256. if (params.weather_type == Game::Map::WeatherType::Snow) {
  257. glDisable(GL_PROGRAM_POINT_SIZE);
  258. }
  259. glDepthMask(depth_mask_enabled);
  260. if (!blend_enabled) {
  261. glDisable(GL_BLEND);
  262. }
  263. if (!depth_test_enabled) {
  264. glDisable(GL_DEPTH_TEST);
  265. }
  266. }
  267. } // namespace Render::GL::BackendPipelines