riverbank_renderer.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. #include "riverbank_renderer.h"
  2. #include "../../game/map/visibility_service.h"
  3. #include "../gl/mesh.h"
  4. #include "../gl/resources.h"
  5. #include "../scene_renderer.h"
  6. #include "ground_utils.h"
  7. #include "map/terrain.h"
  8. #include <QVector2D>
  9. #include <QVector3D>
  10. #include <algorithm>
  11. #include <cmath>
  12. #include <cstddef>
  13. #include <memory>
  14. #include <qglobal.h>
  15. #include <qmatrix4x4.h>
  16. #include <qvectornd.h>
  17. #include <utility>
  18. #include <vector>
  19. namespace Render::GL {
  20. RiverbankRenderer::RiverbankRenderer() = default;
  21. RiverbankRenderer::~RiverbankRenderer() = default;
  22. void RiverbankRenderer::configure(
  23. const std::vector<Game::Map::RiverSegment> &riverSegments,
  24. const Game::Map::TerrainHeightMap &height_map) {
  25. m_riverSegments = riverSegments;
  26. m_tile_size = height_map.getTileSize();
  27. m_grid_width = height_map.getWidth();
  28. m_grid_height = height_map.getHeight();
  29. m_heights = height_map.getHeightData();
  30. buildMeshes();
  31. }
  32. void RiverbankRenderer::buildMeshes() {
  33. m_meshes.clear();
  34. m_visibilitySamples.clear();
  35. if (m_riverSegments.empty()) {
  36. return;
  37. }
  38. auto noise = [](float x, float y) -> float {
  39. float const ix = std::floor(x);
  40. float const iy = std::floor(y);
  41. float fx = x - ix;
  42. float fy = y - iy;
  43. fx = fx * fx * (3.0F - 2.0F * fx);
  44. fy = fy * fy * (3.0F - 2.0F * fy);
  45. float const a = Ground::noise_hash(ix, iy);
  46. float const b = Ground::noise_hash(ix + 1.0F, iy);
  47. float const c = Ground::noise_hash(ix, iy + 1.0F);
  48. float const d = Ground::noise_hash(ix + 1.0F, iy + 1.0F);
  49. return a * (1.0F - fx) * (1.0F - fy) + b * fx * (1.0F - fy) +
  50. c * (1.0F - fx) * fy + d * fx * fy;
  51. };
  52. auto sample_height = [&](float world_x, float world_z) -> float {
  53. if (m_heights.empty() || m_grid_width == 0 || m_grid_height == 0) {
  54. return 0.0F;
  55. }
  56. float const half_width = m_grid_width * 0.5F - 0.5F;
  57. float const half_height = m_grid_height * 0.5F - 0.5F;
  58. float gx = (world_x / m_tile_size) + half_width;
  59. float gz = (world_z / m_tile_size) + half_height;
  60. gx = std::clamp(gx, 0.0F, float(m_grid_width - 1));
  61. gz = std::clamp(gz, 0.0F, float(m_grid_height - 1));
  62. int const x0 = int(std::floor(gx));
  63. int const z0 = int(std::floor(gz));
  64. int const x1 = std::min(x0 + 1, m_grid_width - 1);
  65. int const z1 = std::min(z0 + 1, m_grid_height - 1);
  66. float const tx = gx - float(x0);
  67. float const tz = gz - float(z0);
  68. float const h00 = m_heights[z0 * m_grid_width + x0];
  69. float const h10 = m_heights[z0 * m_grid_width + x1];
  70. float const h01 = m_heights[z1 * m_grid_width + x0];
  71. float const h11 = m_heights[z1 * m_grid_width + x1];
  72. float const h0 = h00 * (1.0F - tx) + h10 * tx;
  73. float const h1 = h01 * (1.0F - tx) + h11 * tx;
  74. return h0 * (1.0F - tz) + h1 * tz;
  75. };
  76. for (const auto &segment : m_riverSegments) {
  77. QVector3D dir = segment.end - segment.start;
  78. float const length = dir.length();
  79. if (length < 0.01F) {
  80. m_meshes.push_back(nullptr);
  81. m_visibilitySamples.emplace_back();
  82. continue;
  83. }
  84. dir.normalize();
  85. QVector3D const perpendicular(-dir.z(), 0.0F, dir.x());
  86. float const half_width = segment.width * 0.5F;
  87. float const bank_width = 0.2F;
  88. int length_steps =
  89. static_cast<int>(std::ceil(length / (m_tile_size * 0.5F))) + 1;
  90. length_steps = std::max(length_steps, 8);
  91. std::vector<Vertex> vertices;
  92. std::vector<unsigned int> indices;
  93. std::vector<QVector3D> samples;
  94. for (int i = 0; i < length_steps; ++i) {
  95. float const t =
  96. static_cast<float>(i) / static_cast<float>(length_steps - 1);
  97. QVector3D center_pos = segment.start + dir * (length * t);
  98. constexpr float k_edge_noise_freq_1 = 2.0F;
  99. constexpr float k_edge_noise_freq_2 = 5.0F;
  100. constexpr float k_edge_noise_freq_3 = 10.0F;
  101. float const edge_noise1 = noise(center_pos.x() * k_edge_noise_freq_1,
  102. center_pos.z() * k_edge_noise_freq_1);
  103. float const edge_noise2 = noise(center_pos.x() * k_edge_noise_freq_2,
  104. center_pos.z() * k_edge_noise_freq_2);
  105. float const edge_noise3 = noise(center_pos.x() * k_edge_noise_freq_3,
  106. center_pos.z() * k_edge_noise_freq_3);
  107. float combined_noise =
  108. edge_noise1 * 0.5F + edge_noise2 * 0.3F + edge_noise3 * 0.2F;
  109. combined_noise = (combined_noise - 0.5F) * 2.0F;
  110. float const width_variation = combined_noise * half_width * 0.35F;
  111. float const meander = noise(t * 3.0F, length * 0.1F) * 0.3F;
  112. QVector3D const center_offset = perpendicular * meander;
  113. center_pos += center_offset;
  114. QVector3D const inner_left =
  115. center_pos - perpendicular * (half_width + width_variation);
  116. QVector3D const inner_right =
  117. center_pos + perpendicular * (half_width + width_variation);
  118. samples.push_back(inner_left);
  119. samples.push_back(inner_right);
  120. float const outer_variation =
  121. noise(center_pos.x() * 8.0F, center_pos.z() * 8.0F) * 0.5F;
  122. QVector3D const outer_left =
  123. inner_left - perpendicular * (bank_width + outer_variation);
  124. QVector3D const outer_right =
  125. inner_right + perpendicular * (bank_width + outer_variation);
  126. float const normal[3] = {0.0F, 1.0F, 0.0F};
  127. Vertex left_inner;
  128. Vertex left_outer;
  129. float const height_inner_left =
  130. sample_height(inner_left.x(), inner_left.z());
  131. float const height_outer_left =
  132. sample_height(outer_left.x(), outer_left.z());
  133. left_inner.position[0] = inner_left.x();
  134. left_inner.position[1] = height_inner_left + 0.05F;
  135. left_inner.position[2] = inner_left.z();
  136. left_inner.normal[0] = normal[0];
  137. left_inner.normal[1] = normal[1];
  138. left_inner.normal[2] = normal[2];
  139. left_inner.tex_coord[0] = 0.0F;
  140. left_inner.tex_coord[1] = t;
  141. vertices.push_back(left_inner);
  142. left_outer.position[0] = outer_left.x();
  143. left_outer.position[1] = height_outer_left + 0.05F;
  144. left_outer.position[2] = outer_left.z();
  145. left_outer.normal[0] = normal[0];
  146. left_outer.normal[1] = normal[1];
  147. left_outer.normal[2] = normal[2];
  148. left_outer.tex_coord[0] = 1.0F;
  149. left_outer.tex_coord[1] = t;
  150. vertices.push_back(left_outer);
  151. Vertex right_inner;
  152. Vertex right_outer;
  153. float const height_inner_right =
  154. sample_height(inner_right.x(), inner_right.z());
  155. float const height_outer_right =
  156. sample_height(outer_right.x(), outer_right.z());
  157. right_inner.position[0] = inner_right.x();
  158. right_inner.position[1] = height_inner_right + 0.05F;
  159. right_inner.position[2] = inner_right.z();
  160. right_inner.normal[0] = normal[0];
  161. right_inner.normal[1] = normal[1];
  162. right_inner.normal[2] = normal[2];
  163. right_inner.tex_coord[0] = 0.0F;
  164. right_inner.tex_coord[1] = t;
  165. vertices.push_back(right_inner);
  166. right_outer.position[0] = outer_right.x();
  167. right_outer.position[1] = height_outer_right + 0.05F;
  168. right_outer.position[2] = outer_right.z();
  169. right_outer.normal[0] = normal[0];
  170. right_outer.normal[1] = normal[1];
  171. right_outer.normal[2] = normal[2];
  172. right_outer.tex_coord[0] = 1.0F;
  173. right_outer.tex_coord[1] = t;
  174. vertices.push_back(right_outer);
  175. if (i < length_steps - 1) {
  176. unsigned int const idx0 = i * 4;
  177. indices.push_back(idx0 + 0);
  178. indices.push_back(idx0 + 4);
  179. indices.push_back(idx0 + 1);
  180. indices.push_back(idx0 + 1);
  181. indices.push_back(idx0 + 4);
  182. indices.push_back(idx0 + 5);
  183. indices.push_back(idx0 + 2);
  184. indices.push_back(idx0 + 3);
  185. indices.push_back(idx0 + 6);
  186. indices.push_back(idx0 + 3);
  187. indices.push_back(idx0 + 7);
  188. indices.push_back(idx0 + 6);
  189. }
  190. }
  191. if (!vertices.empty() && !indices.empty()) {
  192. m_meshes.push_back(std::make_unique<Mesh>(vertices, indices));
  193. m_visibilitySamples.push_back(std::move(samples));
  194. } else {
  195. m_meshes.push_back(nullptr);
  196. m_visibilitySamples.emplace_back();
  197. }
  198. }
  199. }
  200. void RiverbankRenderer::submit(Renderer &renderer, ResourceManager *resources) {
  201. if (m_meshes.empty() || m_riverSegments.empty()) {
  202. return;
  203. }
  204. Q_UNUSED(resources);
  205. auto &visibility = Game::Map::VisibilityService::instance();
  206. const bool use_visibility = visibility.isInitialized();
  207. auto *shader = renderer.getShader("riverbank");
  208. if (shader == nullptr) {
  209. return;
  210. }
  211. renderer.setCurrentShader(shader);
  212. QMatrix4x4 model;
  213. model.setToIdentity();
  214. size_t mesh_index = 0;
  215. for (const auto &segment : m_riverSegments) {
  216. if (mesh_index >= m_meshes.size()) {
  217. break;
  218. }
  219. auto *mesh = m_meshes[mesh_index].get();
  220. ++mesh_index;
  221. if (mesh == nullptr) {
  222. continue;
  223. }
  224. if (use_visibility) {
  225. bool any_visible = false;
  226. if (mesh_index - 1 < m_visibilitySamples.size()) {
  227. const auto &samples = m_visibilitySamples[mesh_index - 1];
  228. const int min_required =
  229. std::max<int>(2, static_cast<int>(samples.size() * 0.3F));
  230. int visible_count = 0;
  231. for (const auto &pos : samples) {
  232. if (visibility.isVisibleWorld(pos.x(), pos.z())) {
  233. ++visible_count;
  234. if (visible_count >= min_required) {
  235. any_visible = true;
  236. break;
  237. }
  238. }
  239. }
  240. }
  241. if (!any_visible) {
  242. continue;
  243. }
  244. }
  245. renderer.mesh(mesh, model, QVector3D(1.0F, 1.0F, 1.0F), nullptr, 1.0F);
  246. }
  247. renderer.setCurrentShader(nullptr);
  248. }
  249. } // namespace Render::GL