riverbank_renderer.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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 <QVector2D>
  7. #include <QVector3D>
  8. #include <algorithm>
  9. #include <cmath>
  10. namespace Render::GL {
  11. RiverbankRenderer::RiverbankRenderer() = default;
  12. RiverbankRenderer::~RiverbankRenderer() = default;
  13. void RiverbankRenderer::configure(
  14. const std::vector<Game::Map::RiverSegment> &riverSegments,
  15. const Game::Map::TerrainHeightMap &heightMap) {
  16. m_riverSegments = riverSegments;
  17. m_tileSize = heightMap.getTileSize();
  18. m_gridWidth = heightMap.getWidth();
  19. m_gridHeight = heightMap.getHeight();
  20. m_heights = heightMap.getHeightData();
  21. buildMeshes();
  22. }
  23. void RiverbankRenderer::buildMeshes() {
  24. m_meshes.clear();
  25. m_visibilitySamples.clear();
  26. if (m_riverSegments.empty()) {
  27. return;
  28. }
  29. auto noiseHash = [](float x, float y) -> float {
  30. float n = std::sin(x * 127.1f + y * 311.7f) * 43758.5453123f;
  31. return n - std::floor(n);
  32. };
  33. auto noise = [&noiseHash](float x, float y) -> float {
  34. float ix = std::floor(x);
  35. float iy = std::floor(y);
  36. float fx = x - ix;
  37. float fy = y - iy;
  38. fx = fx * fx * (3.0f - 2.0f * fx);
  39. fy = fy * fy * (3.0f - 2.0f * fy);
  40. float a = noiseHash(ix, iy);
  41. float b = noiseHash(ix + 1.0f, iy);
  42. float c = noiseHash(ix, iy + 1.0f);
  43. float d = noiseHash(ix + 1.0f, iy + 1.0f);
  44. return a * (1.0f - fx) * (1.0f - fy) + b * fx * (1.0f - fy) +
  45. c * (1.0f - fx) * fy + d * fx * fy;
  46. };
  47. auto sampleHeight = [&](float worldX, float worldZ) -> float {
  48. if (m_heights.empty() || m_gridWidth == 0 || m_gridHeight == 0) {
  49. return 0.0f;
  50. }
  51. float halfWidth = m_gridWidth * 0.5f - 0.5f;
  52. float halfHeight = m_gridHeight * 0.5f - 0.5f;
  53. float gx = (worldX / m_tileSize) + halfWidth;
  54. float gz = (worldZ / m_tileSize) + halfHeight;
  55. gx = std::clamp(gx, 0.0f, float(m_gridWidth - 1));
  56. gz = std::clamp(gz, 0.0f, float(m_gridHeight - 1));
  57. int x0 = int(std::floor(gx));
  58. int z0 = int(std::floor(gz));
  59. int x1 = std::min(x0 + 1, m_gridWidth - 1);
  60. int z1 = std::min(z0 + 1, m_gridHeight - 1);
  61. float tx = gx - float(x0);
  62. float tz = gz - float(z0);
  63. float h00 = m_heights[z0 * m_gridWidth + x0];
  64. float h10 = m_heights[z0 * m_gridWidth + x1];
  65. float h01 = m_heights[z1 * m_gridWidth + x0];
  66. float h11 = m_heights[z1 * m_gridWidth + x1];
  67. float h0 = h00 * (1.0f - tx) + h10 * tx;
  68. float h1 = h01 * (1.0f - tx) + h11 * tx;
  69. return h0 * (1.0f - tz) + h1 * tz;
  70. };
  71. for (const auto &segment : m_riverSegments) {
  72. QVector3D dir = segment.end - segment.start;
  73. float length = dir.length();
  74. if (length < 0.01f) {
  75. m_meshes.push_back(nullptr);
  76. m_visibilitySamples.emplace_back();
  77. continue;
  78. }
  79. dir.normalize();
  80. QVector3D perpendicular(-dir.z(), 0.0f, dir.x());
  81. float halfWidth = segment.width * 0.5f;
  82. float bankWidth = 0.2f;
  83. int lengthSteps =
  84. static_cast<int>(std::ceil(length / (m_tileSize * 0.5f))) + 1;
  85. lengthSteps = std::max(lengthSteps, 8);
  86. std::vector<Vertex> vertices;
  87. std::vector<unsigned int> indices;
  88. std::vector<QVector3D> samples;
  89. for (int i = 0; i < lengthSteps; ++i) {
  90. float t = static_cast<float>(i) / static_cast<float>(lengthSteps - 1);
  91. QVector3D centerPos = segment.start + dir * (length * t);
  92. float noiseFreq1 = 2.0f;
  93. float noiseFreq2 = 5.0f;
  94. float noiseFreq3 = 10.0f;
  95. float edgeNoise1 =
  96. noise(centerPos.x() * noiseFreq1, centerPos.z() * noiseFreq1);
  97. float edgeNoise2 =
  98. noise(centerPos.x() * noiseFreq2, centerPos.z() * noiseFreq2);
  99. float edgeNoise3 =
  100. noise(centerPos.x() * noiseFreq3, centerPos.z() * noiseFreq3);
  101. float combinedNoise =
  102. edgeNoise1 * 0.5f + edgeNoise2 * 0.3f + edgeNoise3 * 0.2f;
  103. combinedNoise = (combinedNoise - 0.5f) * 2.0f;
  104. float widthVariation = combinedNoise * halfWidth * 0.35f;
  105. float meander = noise(t * 3.0f, length * 0.1f) * 0.3f;
  106. QVector3D centerOffset = perpendicular * meander;
  107. centerPos += centerOffset;
  108. QVector3D innerLeft =
  109. centerPos - perpendicular * (halfWidth + widthVariation);
  110. QVector3D innerRight =
  111. centerPos + perpendicular * (halfWidth + widthVariation);
  112. samples.push_back(innerLeft);
  113. samples.push_back(innerRight);
  114. float outerVariation =
  115. noise(centerPos.x() * 8.0f, centerPos.z() * 8.0f) * 0.5f;
  116. QVector3D outerLeft =
  117. innerLeft - perpendicular * (bankWidth + outerVariation);
  118. QVector3D outerRight =
  119. innerRight + perpendicular * (bankWidth + outerVariation);
  120. float normal[3] = {0.0f, 1.0f, 0.0f};
  121. Vertex leftInner, leftOuter;
  122. float heightInnerLeft = sampleHeight(innerLeft.x(), innerLeft.z());
  123. float heightOuterLeft = sampleHeight(outerLeft.x(), outerLeft.z());
  124. leftInner.position[0] = innerLeft.x();
  125. leftInner.position[1] = heightInnerLeft + 0.05f;
  126. leftInner.position[2] = innerLeft.z();
  127. leftInner.normal[0] = normal[0];
  128. leftInner.normal[1] = normal[1];
  129. leftInner.normal[2] = normal[2];
  130. leftInner.texCoord[0] = 0.0f;
  131. leftInner.texCoord[1] = t;
  132. vertices.push_back(leftInner);
  133. leftOuter.position[0] = outerLeft.x();
  134. leftOuter.position[1] = heightOuterLeft + 0.05f;
  135. leftOuter.position[2] = outerLeft.z();
  136. leftOuter.normal[0] = normal[0];
  137. leftOuter.normal[1] = normal[1];
  138. leftOuter.normal[2] = normal[2];
  139. leftOuter.texCoord[0] = 1.0f;
  140. leftOuter.texCoord[1] = t;
  141. vertices.push_back(leftOuter);
  142. Vertex rightInner, rightOuter;
  143. float heightInnerRight = sampleHeight(innerRight.x(), innerRight.z());
  144. float heightOuterRight = sampleHeight(outerRight.x(), outerRight.z());
  145. rightInner.position[0] = innerRight.x();
  146. rightInner.position[1] = heightInnerRight + 0.05f;
  147. rightInner.position[2] = innerRight.z();
  148. rightInner.normal[0] = normal[0];
  149. rightInner.normal[1] = normal[1];
  150. rightInner.normal[2] = normal[2];
  151. rightInner.texCoord[0] = 0.0f;
  152. rightInner.texCoord[1] = t;
  153. vertices.push_back(rightInner);
  154. rightOuter.position[0] = outerRight.x();
  155. rightOuter.position[1] = heightOuterRight + 0.05f;
  156. rightOuter.position[2] = outerRight.z();
  157. rightOuter.normal[0] = normal[0];
  158. rightOuter.normal[1] = normal[1];
  159. rightOuter.normal[2] = normal[2];
  160. rightOuter.texCoord[0] = 1.0f;
  161. rightOuter.texCoord[1] = t;
  162. vertices.push_back(rightOuter);
  163. if (i < lengthSteps - 1) {
  164. unsigned int idx0 = i * 4;
  165. indices.push_back(idx0 + 0);
  166. indices.push_back(idx0 + 4);
  167. indices.push_back(idx0 + 1);
  168. indices.push_back(idx0 + 1);
  169. indices.push_back(idx0 + 4);
  170. indices.push_back(idx0 + 5);
  171. indices.push_back(idx0 + 2);
  172. indices.push_back(idx0 + 3);
  173. indices.push_back(idx0 + 6);
  174. indices.push_back(idx0 + 3);
  175. indices.push_back(idx0 + 7);
  176. indices.push_back(idx0 + 6);
  177. }
  178. }
  179. if (!vertices.empty() && !indices.empty()) {
  180. m_meshes.push_back(std::make_unique<Mesh>(vertices, indices));
  181. m_visibilitySamples.push_back(std::move(samples));
  182. } else {
  183. m_meshes.push_back(nullptr);
  184. m_visibilitySamples.emplace_back();
  185. }
  186. }
  187. }
  188. void RiverbankRenderer::submit(Renderer &renderer, ResourceManager *resources) {
  189. if (m_meshes.empty() || m_riverSegments.empty()) {
  190. return;
  191. }
  192. Q_UNUSED(resources);
  193. auto &visibility = Game::Map::VisibilityService::instance();
  194. const bool useVisibility = visibility.isInitialized();
  195. auto shader = renderer.getShader("riverbank");
  196. if (!shader) {
  197. return;
  198. }
  199. renderer.setCurrentShader(shader);
  200. QMatrix4x4 model;
  201. model.setToIdentity();
  202. size_t meshIndex = 0;
  203. for (const auto &segment : m_riverSegments) {
  204. if (meshIndex >= m_meshes.size()) {
  205. break;
  206. }
  207. auto *mesh = m_meshes[meshIndex].get();
  208. ++meshIndex;
  209. if (!mesh) {
  210. continue;
  211. }
  212. if (useVisibility) {
  213. bool anyVisible = false;
  214. if (meshIndex - 1 < m_visibilitySamples.size()) {
  215. const auto &samples = m_visibilitySamples[meshIndex - 1];
  216. const int minRequired =
  217. std::max<int>(2, static_cast<int>(samples.size() * 0.3f));
  218. int visibleCount = 0;
  219. for (const auto &pos : samples) {
  220. if (visibility.isVisibleWorld(pos.x(), pos.z())) {
  221. ++visibleCount;
  222. if (visibleCount >= minRequired) {
  223. anyVisible = true;
  224. break;
  225. }
  226. }
  227. }
  228. }
  229. if (!anyVisible) {
  230. continue;
  231. }
  232. }
  233. renderer.mesh(mesh, model, QVector3D(1.0f, 1.0f, 1.0f), nullptr, 1.0f);
  234. }
  235. renderer.setCurrentShader(nullptr);
  236. }
  237. } // namespace Render::GL