riverbank_renderer.cpp 8.8 KB

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