riverbank_renderer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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 <GL/gl.h>
  9. #include <QVector2D>
  10. #include <QVector3D>
  11. #include <algorithm>
  12. #include <cmath>
  13. #include <cstddef>
  14. #include <memory>
  15. #include <qglobal.h>
  16. #include <qmatrix4x4.h>
  17. #include <qvectornd.h>
  18. #include <utility>
  19. #include <vector>
  20. namespace Render::GL {
  21. RiverbankRenderer::RiverbankRenderer() = default;
  22. RiverbankRenderer::~RiverbankRenderer() = default;
  23. void RiverbankRenderer::configure(
  24. const std::vector<Game::Map::RiverSegment> &riverSegments,
  25. const Game::Map::TerrainHeightMap &height_map) {
  26. m_riverSegments = riverSegments;
  27. m_tile_size = height_map.getTileSize();
  28. m_grid_width = height_map.getWidth();
  29. m_grid_height = height_map.getHeight();
  30. m_heights = height_map.getHeightData();
  31. m_visibilityTexture.reset();
  32. m_cachedVisibilityVersion = 0;
  33. m_visibilityWidth = 0;
  34. m_visibilityHeight = 0;
  35. build_meshes();
  36. }
  37. void RiverbankRenderer::build_meshes() {
  38. m_meshes.clear();
  39. m_visibilitySamples.clear();
  40. if (m_riverSegments.empty()) {
  41. return;
  42. }
  43. auto noise = [](float x, float y) -> float {
  44. float const ix = std::floor(x);
  45. float const iy = std::floor(y);
  46. float fx = x - ix;
  47. float fy = y - iy;
  48. fx = fx * fx * (3.0F - 2.0F * fx);
  49. fy = fy * fy * (3.0F - 2.0F * fy);
  50. float const a = Ground::noise_hash(ix, iy);
  51. float const b = Ground::noise_hash(ix + 1.0F, iy);
  52. float const c = Ground::noise_hash(ix, iy + 1.0F);
  53. float const d = Ground::noise_hash(ix + 1.0F, iy + 1.0F);
  54. return a * (1.0F - fx) * (1.0F - fy) + b * fx * (1.0F - fy) +
  55. c * (1.0F - fx) * fy + d * fx * fy;
  56. };
  57. auto sample_height = [&](float world_x, float world_z) -> float {
  58. if (m_heights.empty() || m_grid_width == 0 || m_grid_height == 0) {
  59. return 0.0F;
  60. }
  61. float const half_width = m_grid_width * 0.5F - 0.5F;
  62. float const half_height = m_grid_height * 0.5F - 0.5F;
  63. float gx = (world_x / m_tile_size) + half_width;
  64. float gz = (world_z / m_tile_size) + half_height;
  65. gx = std::clamp(gx, 0.0F, float(m_grid_width - 1));
  66. gz = std::clamp(gz, 0.0F, float(m_grid_height - 1));
  67. int const x0 = int(std::floor(gx));
  68. int const z0 = int(std::floor(gz));
  69. int const x1 = std::min(x0 + 1, m_grid_width - 1);
  70. int const z1 = std::min(z0 + 1, m_grid_height - 1);
  71. float const tx = gx - float(x0);
  72. float const tz = gz - float(z0);
  73. float const h00 = m_heights[z0 * m_grid_width + x0];
  74. float const h10 = m_heights[z0 * m_grid_width + x1];
  75. float const h01 = m_heights[z1 * m_grid_width + x0];
  76. float const h11 = m_heights[z1 * m_grid_width + x1];
  77. float const h0 = h00 * (1.0F - tx) + h10 * tx;
  78. float const h1 = h01 * (1.0F - tx) + h11 * tx;
  79. return h0 * (1.0F - tz) + h1 * tz;
  80. };
  81. for (const auto &segment : m_riverSegments) {
  82. QVector3D dir = segment.end - segment.start;
  83. float const length = dir.length();
  84. if (length < 0.01F) {
  85. m_meshes.push_back(nullptr);
  86. m_visibilitySamples.emplace_back();
  87. continue;
  88. }
  89. dir.normalize();
  90. QVector3D const perpendicular(-dir.z(), 0.0F, dir.x());
  91. float const half_width = segment.width * 0.5F;
  92. constexpr int k_rings_per_side = 5;
  93. constexpr int k_total_rings = k_rings_per_side * 2;
  94. int length_steps =
  95. static_cast<int>(std::ceil(length / (m_tile_size * 0.5F))) + 1;
  96. length_steps = std::max(length_steps, 8);
  97. std::vector<Vertex> vertices;
  98. std::vector<unsigned int> indices;
  99. std::vector<QVector3D> samples;
  100. for (int i = 0; i < length_steps; ++i) {
  101. float const t =
  102. static_cast<float>(i) / static_cast<float>(length_steps - 1);
  103. QVector3D center_pos = segment.start + dir * (length * t);
  104. float const center_height = sample_height(center_pos.x(), center_pos.z());
  105. constexpr float k_edge_noise_freq_1 = 2.0F;
  106. constexpr float k_edge_noise_freq_2 = 5.0F;
  107. constexpr float k_edge_noise_freq_3 = 10.0F;
  108. float const edge_noise1 = noise(center_pos.x() * k_edge_noise_freq_1,
  109. center_pos.z() * k_edge_noise_freq_1);
  110. float const edge_noise2 = noise(center_pos.x() * k_edge_noise_freq_2,
  111. center_pos.z() * k_edge_noise_freq_2);
  112. float const edge_noise3 = noise(center_pos.x() * k_edge_noise_freq_3,
  113. center_pos.z() * k_edge_noise_freq_3);
  114. float combined_noise =
  115. edge_noise1 * 0.5F + edge_noise2 * 0.3F + edge_noise3 * 0.2F;
  116. combined_noise = (combined_noise - 0.5F) * 2.0F;
  117. float const width_variation = combined_noise * half_width * 0.35F;
  118. float const meander = noise(t * 3.0F, length * 0.1F) * 0.3F;
  119. QVector3D const center_offset = perpendicular * meander;
  120. center_pos += center_offset;
  121. struct RingProfile {
  122. float distance_from_water;
  123. float height_offset;
  124. };
  125. constexpr RingProfile k_left_rings[k_rings_per_side] = {{0.0F, 0.02F},
  126. {0.125F, 0.175F},
  127. {0.25F, 0.3F},
  128. {0.375F, 0.125F},
  129. {0.5F, -0.15F}};
  130. float const ring_noise =
  131. noise(center_pos.x() * 3.0F, center_pos.z() * 3.0F) * 0.075F;
  132. float const base_bank_width = 0.5F + ring_noise;
  133. unsigned int const ring_start_idx =
  134. static_cast<unsigned int>(vertices.size());
  135. for (int ring = 0; ring < k_rings_per_side; ++ring) {
  136. float const ring_dist =
  137. k_left_rings[ring].distance_from_water * base_bank_width;
  138. float const ring_height = k_left_rings[ring].height_offset;
  139. QVector3D const ring_pos =
  140. center_pos -
  141. perpendicular * (half_width + width_variation + ring_dist);
  142. float const terrain_height = sample_height(ring_pos.x(), ring_pos.z());
  143. float const clamped_height =
  144. std::min(terrain_height, center_height + 0.05F);
  145. if (ring == 0) {
  146. samples.push_back(ring_pos);
  147. }
  148. Vertex vtx{};
  149. vtx.position[0] = ring_pos.x();
  150. vtx.position[1] = clamped_height + ring_height;
  151. vtx.position[2] = ring_pos.z();
  152. QVector3D normal;
  153. if (ring == 0) {
  154. QVector3D const next_ring_pos =
  155. center_pos -
  156. perpendicular *
  157. (half_width + width_variation +
  158. k_left_rings[1].distance_from_water * base_bank_width);
  159. float const next_terrain =
  160. sample_height(next_ring_pos.x(), next_ring_pos.z());
  161. float const next_clamped =
  162. std::min(next_terrain, center_height + 0.05F);
  163. QVector3D slope_vec(next_ring_pos.x() - ring_pos.x(),
  164. (next_clamped + k_left_rings[1].height_offset) -
  165. (clamped_height + ring_height),
  166. next_ring_pos.z() - ring_pos.z());
  167. normal = QVector3D::crossProduct(slope_vec, dir).normalized();
  168. } else if (ring == k_rings_per_side - 1) {
  169. unsigned int prev_idx = ring_start_idx + ring - 1;
  170. QVector3D prev_pos(vertices[prev_idx].position[0],
  171. vertices[prev_idx].position[1],
  172. vertices[prev_idx].position[2]);
  173. QVector3D slope_vec(ring_pos.x() - prev_pos.x(),
  174. (clamped_height + ring_height) - prev_pos.y(),
  175. ring_pos.z() - prev_pos.z());
  176. normal = QVector3D::crossProduct(slope_vec, dir).normalized();
  177. } else {
  178. unsigned int prev_idx = ring_start_idx + ring - 1;
  179. QVector3D prev_pos(vertices[prev_idx].position[0],
  180. vertices[prev_idx].position[1],
  181. vertices[prev_idx].position[2]);
  182. QVector3D const next_ring_pos =
  183. center_pos -
  184. perpendicular * (half_width + width_variation +
  185. k_left_rings[ring + 1].distance_from_water *
  186. base_bank_width);
  187. float const next_terrain =
  188. sample_height(next_ring_pos.x(), next_ring_pos.z());
  189. float const next_clamped =
  190. std::min(next_terrain, center_height + 0.05F);
  191. QVector3D slope_from_prev(ring_pos.x() - prev_pos.x(),
  192. (terrain_height + ring_height) -
  193. prev_pos.y(),
  194. ring_pos.z() - prev_pos.z());
  195. QVector3D slope_to_next(
  196. next_ring_pos.x() - ring_pos.x(),
  197. (next_clamped + k_left_rings[ring + 1].height_offset) -
  198. (clamped_height + ring_height),
  199. next_ring_pos.z() - ring_pos.z());
  200. QVector3D n1 =
  201. QVector3D::crossProduct(slope_from_prev, dir).normalized();
  202. QVector3D n2 =
  203. QVector3D::crossProduct(slope_to_next, dir).normalized();
  204. normal = ((n1 + n2) * 0.5F).normalized();
  205. }
  206. vtx.normal[0] = normal.x();
  207. vtx.normal[1] = normal.y();
  208. vtx.normal[2] = normal.z();
  209. vtx.tex_coord[0] = static_cast<float>(ring) / (k_rings_per_side - 1);
  210. vtx.tex_coord[1] = t;
  211. vertices.push_back(vtx);
  212. }
  213. for (int ring = 0; ring < k_rings_per_side; ++ring) {
  214. float const ring_dist =
  215. k_left_rings[ring].distance_from_water * base_bank_width;
  216. float const ring_height = k_left_rings[ring].height_offset;
  217. QVector3D const ring_pos =
  218. center_pos +
  219. perpendicular * (half_width + width_variation + ring_dist);
  220. float const terrain_height = sample_height(ring_pos.x(), ring_pos.z());
  221. float const clamped_height =
  222. std::min(terrain_height, center_height + 0.05F);
  223. if (ring == 0) {
  224. samples.push_back(ring_pos);
  225. }
  226. Vertex vtx{};
  227. vtx.position[0] = ring_pos.x();
  228. vtx.position[1] = clamped_height + ring_height;
  229. vtx.position[2] = ring_pos.z();
  230. QVector3D normal;
  231. if (ring == 0) {
  232. QVector3D const next_ring_pos =
  233. center_pos +
  234. perpendicular *
  235. (half_width + width_variation +
  236. k_left_rings[1].distance_from_water * base_bank_width);
  237. float const next_terrain =
  238. sample_height(next_ring_pos.x(), next_ring_pos.z());
  239. float const next_clamped =
  240. std::min(next_terrain, center_height + 0.05F);
  241. QVector3D slope_vec(next_ring_pos.x() - ring_pos.x(),
  242. (next_clamped + k_left_rings[1].height_offset) -
  243. (clamped_height + ring_height),
  244. next_ring_pos.z() - ring_pos.z());
  245. normal = QVector3D::crossProduct(dir, slope_vec).normalized();
  246. } else if (ring == k_rings_per_side - 1) {
  247. unsigned int prev_idx = ring_start_idx + k_rings_per_side + ring - 1;
  248. QVector3D prev_pos(vertices[prev_idx].position[0],
  249. vertices[prev_idx].position[1],
  250. vertices[prev_idx].position[2]);
  251. QVector3D slope_vec(ring_pos.x() - prev_pos.x(),
  252. (clamped_height + ring_height) - prev_pos.y(),
  253. ring_pos.z() - prev_pos.z());
  254. normal = QVector3D::crossProduct(dir, slope_vec).normalized();
  255. } else {
  256. unsigned int prev_idx = ring_start_idx + k_rings_per_side + ring - 1;
  257. QVector3D prev_pos(vertices[prev_idx].position[0],
  258. vertices[prev_idx].position[1],
  259. vertices[prev_idx].position[2]);
  260. QVector3D const next_ring_pos =
  261. center_pos +
  262. perpendicular * (half_width + width_variation +
  263. k_left_rings[ring + 1].distance_from_water *
  264. base_bank_width);
  265. float const next_terrain =
  266. sample_height(next_ring_pos.x(), next_ring_pos.z());
  267. float const next_clamped =
  268. std::min(next_terrain, center_height + 0.05F);
  269. QVector3D slope_from_prev(ring_pos.x() - prev_pos.x(),
  270. (clamped_height + ring_height) -
  271. prev_pos.y(),
  272. ring_pos.z() - prev_pos.z());
  273. QVector3D slope_to_next(
  274. next_ring_pos.x() - ring_pos.x(),
  275. (next_clamped + k_left_rings[ring + 1].height_offset) -
  276. (clamped_height + ring_height),
  277. next_ring_pos.z() - ring_pos.z());
  278. QVector3D n1 =
  279. QVector3D::crossProduct(dir, slope_from_prev).normalized();
  280. QVector3D n2 =
  281. QVector3D::crossProduct(dir, slope_to_next).normalized();
  282. normal = ((n1 + n2) * 0.5F).normalized();
  283. }
  284. vtx.normal[0] = normal.x();
  285. vtx.normal[1] = normal.y();
  286. vtx.normal[2] = normal.z();
  287. vtx.tex_coord[0] = static_cast<float>(ring) / (k_rings_per_side - 1);
  288. vtx.tex_coord[1] = t;
  289. vertices.push_back(vtx);
  290. }
  291. {
  292. Vertex const &water_edge_left = vertices[ring_start_idx];
  293. Vertex skirt_vtx = water_edge_left;
  294. skirt_vtx.position[1] = -0.05F;
  295. skirt_vtx.normal[0] = -perpendicular.x();
  296. skirt_vtx.normal[1] = 0.0F;
  297. skirt_vtx.normal[2] = -perpendicular.z();
  298. vertices.push_back(skirt_vtx);
  299. }
  300. {
  301. Vertex const &water_edge_right =
  302. vertices[ring_start_idx + k_rings_per_side];
  303. Vertex skirt_vtx = water_edge_right;
  304. skirt_vtx.position[1] = -0.05F;
  305. skirt_vtx.normal[0] = perpendicular.x();
  306. skirt_vtx.normal[1] = 0.0F;
  307. skirt_vtx.normal[2] = perpendicular.z();
  308. vertices.push_back(skirt_vtx);
  309. }
  310. if (i < length_steps - 1) {
  311. unsigned int const base_idx = ring_start_idx;
  312. unsigned int const next_base_idx = base_idx + k_total_rings + 2;
  313. for (int ring = 0; ring < k_rings_per_side - 1; ++ring) {
  314. unsigned int idx0 = base_idx + ring;
  315. unsigned int idx1 = base_idx + ring + 1;
  316. unsigned int idx2 = next_base_idx + ring;
  317. unsigned int idx3 = next_base_idx + ring + 1;
  318. indices.push_back(idx0);
  319. indices.push_back(idx2);
  320. indices.push_back(idx1);
  321. indices.push_back(idx1);
  322. indices.push_back(idx2);
  323. indices.push_back(idx3);
  324. }
  325. for (int ring = 0; ring < k_rings_per_side - 1; ++ring) {
  326. unsigned int idx0 = base_idx + k_rings_per_side + ring;
  327. unsigned int idx1 = base_idx + k_rings_per_side + ring + 1;
  328. unsigned int idx2 = next_base_idx + k_rings_per_side + ring;
  329. unsigned int idx3 = next_base_idx + k_rings_per_side + ring + 1;
  330. indices.push_back(idx0);
  331. indices.push_back(idx1);
  332. indices.push_back(idx2);
  333. indices.push_back(idx1);
  334. indices.push_back(idx3);
  335. indices.push_back(idx2);
  336. }
  337. {
  338. unsigned int left_top = base_idx;
  339. unsigned int left_bottom = base_idx + k_total_rings;
  340. unsigned int left_top_next = next_base_idx;
  341. unsigned int left_bottom_next = next_base_idx + k_total_rings;
  342. indices.push_back(left_top);
  343. indices.push_back(left_bottom);
  344. indices.push_back(left_top_next);
  345. indices.push_back(left_bottom);
  346. indices.push_back(left_bottom_next);
  347. indices.push_back(left_top_next);
  348. unsigned int right_top = base_idx + k_rings_per_side;
  349. unsigned int right_bottom = base_idx + k_total_rings + 1;
  350. unsigned int right_top_next = next_base_idx + k_rings_per_side;
  351. unsigned int right_bottom_next = next_base_idx + k_total_rings + 1;
  352. indices.push_back(right_top);
  353. indices.push_back(right_top_next);
  354. indices.push_back(right_bottom);
  355. indices.push_back(right_bottom);
  356. indices.push_back(right_top_next);
  357. indices.push_back(right_bottom_next);
  358. }
  359. }
  360. }
  361. if (!vertices.empty() && !indices.empty()) {
  362. m_meshes.push_back(std::make_unique<Mesh>(vertices, indices));
  363. m_visibilitySamples.push_back(std::move(samples));
  364. } else {
  365. m_meshes.push_back(nullptr);
  366. m_visibilitySamples.emplace_back();
  367. }
  368. }
  369. }
  370. void RiverbankRenderer::submit(Renderer &renderer, ResourceManager *resources) {
  371. if (m_meshes.empty() || m_riverSegments.empty()) {
  372. return;
  373. }
  374. Q_UNUSED(resources);
  375. auto *shader = renderer.get_shader("riverbank");
  376. if (shader == nullptr) {
  377. return;
  378. }
  379. renderer.set_current_shader(shader);
  380. auto *backend = renderer.backend();
  381. auto &visibility = Game::Map::VisibilityService::instance();
  382. const bool use_visibility = visibility.is_initialized();
  383. Texture *visibility_tex = nullptr;
  384. QVector2D visibility_size(0.0F, 0.0F);
  385. if (use_visibility) {
  386. const int vis_w = visibility.getWidth();
  387. const int vis_h = visibility.getHeight();
  388. const std::uint64_t version = visibility.version();
  389. bool const size_changed =
  390. (vis_w != m_visibilityWidth) || (vis_h != m_visibilityHeight);
  391. if (!m_visibilityTexture || size_changed) {
  392. m_visibilityTexture = std::make_unique<Texture>();
  393. m_visibilityTexture->create_empty(vis_w, vis_h, Texture::Format::RGBA);
  394. m_visibilityTexture->set_filter(Texture::Filter::Nearest,
  395. Texture::Filter::Nearest);
  396. m_visibilityTexture->set_wrap(Texture::Wrap::ClampToEdge,
  397. Texture::Wrap::ClampToEdge);
  398. m_visibilityWidth = vis_w;
  399. m_visibilityHeight = vis_h;
  400. m_cachedVisibilityVersion = 0;
  401. }
  402. if (version != m_cachedVisibilityVersion || size_changed) {
  403. auto cells = visibility.snapshotCells();
  404. std::vector<unsigned char> texels(
  405. static_cast<std::size_t>(vis_w * vis_h * 4), 0U);
  406. for (int z = 0; z < vis_h; ++z) {
  407. for (int x = 0; x < vis_w; ++x) {
  408. int const idx = z * vis_w + x;
  409. unsigned char val = 0U;
  410. switch (static_cast<Game::Map::VisibilityState>(cells[idx])) {
  411. case Game::Map::VisibilityState::Visible:
  412. val = 255U;
  413. break;
  414. case Game::Map::VisibilityState::Explored:
  415. val = 128U;
  416. break;
  417. case Game::Map::VisibilityState::Unseen:
  418. default:
  419. val = 0U;
  420. break;
  421. }
  422. texels[static_cast<std::size_t>(idx * 4)] = val;
  423. texels[static_cast<std::size_t>(idx * 4 + 3)] = 255;
  424. }
  425. }
  426. m_visibilityTexture->bind();
  427. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vis_w, vis_h, GL_RGBA,
  428. GL_UNSIGNED_BYTE, texels.data());
  429. visibility_tex = m_visibilityTexture.get();
  430. m_cachedVisibilityVersion = version;
  431. } else {
  432. visibility_tex = m_visibilityTexture.get();
  433. }
  434. visibility_size =
  435. QVector2D(static_cast<float>(vis_w), static_cast<float>(vis_h));
  436. }
  437. if (backend != nullptr) {
  438. backend->set_riverbank_visibility(
  439. use_visibility && visibility_tex != nullptr, visibility_tex,
  440. visibility_size, m_tile_size, m_exploredDimFactor);
  441. }
  442. QMatrix4x4 model;
  443. model.setToIdentity();
  444. size_t mesh_index = 0;
  445. for (const auto &segment : m_riverSegments) {
  446. if (mesh_index >= m_meshes.size()) {
  447. break;
  448. }
  449. auto *mesh = m_meshes[mesh_index].get();
  450. ++mesh_index;
  451. if (mesh == nullptr) {
  452. continue;
  453. }
  454. float segment_visibility = 1.0F;
  455. if (use_visibility) {
  456. enum class SegmentState { Hidden, Explored, Visible };
  457. SegmentState state = SegmentState::Hidden;
  458. const auto &samples = m_visibilitySamples[mesh_index - 1];
  459. if (samples.empty()) {
  460. state = SegmentState::Visible;
  461. }
  462. for (const auto &sample : samples) {
  463. if (visibility.isVisibleWorld(sample.x(), sample.z())) {
  464. state = SegmentState::Visible;
  465. break;
  466. }
  467. if ((state == SegmentState::Hidden) &&
  468. visibility.isExploredWorld(sample.x(), sample.z())) {
  469. state = SegmentState::Explored;
  470. }
  471. }
  472. if (state == SegmentState::Hidden) {
  473. continue;
  474. }
  475. segment_visibility =
  476. (state == SegmentState::Visible) ? 1.0F : m_exploredDimFactor;
  477. }
  478. renderer.mesh(mesh, model, QVector3D(1.0F, 1.0F, 1.0F), nullptr,
  479. segment_visibility);
  480. }
  481. renderer.set_current_shader(nullptr);
  482. }
  483. } // namespace Render::GL