river_renderer.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #include "river_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. RiverRenderer::RiverRenderer() = default;
  11. RiverRenderer::~RiverRenderer() = default;
  12. void RiverRenderer::configure(
  13. const std::vector<Game::Map::RiverSegment> &riverSegments, float tileSize) {
  14. m_riverSegments = riverSegments;
  15. m_tileSize = tileSize;
  16. buildMeshes();
  17. }
  18. void RiverRenderer::buildMeshes() {
  19. m_meshes.clear();
  20. if (m_riverSegments.empty()) {
  21. return;
  22. }
  23. auto noiseHash = [](float x, float y) -> float {
  24. float n = std::sin(x * 127.1f + y * 311.7f) * 43758.5453123f;
  25. return n - std::floor(n);
  26. };
  27. auto noise = [&noiseHash](float x, float y) -> float {
  28. float ix = std::floor(x);
  29. float iy = std::floor(y);
  30. float fx = x - ix;
  31. float fy = y - iy;
  32. fx = fx * fx * (3.0f - 2.0f * fx);
  33. fy = fy * fy * (3.0f - 2.0f * fy);
  34. float a = noiseHash(ix, iy);
  35. float b = noiseHash(ix + 1.0f, iy);
  36. float c = noiseHash(ix, iy + 1.0f);
  37. float d = noiseHash(ix + 1.0f, iy + 1.0f);
  38. return a * (1.0f - fx) * (1.0f - fy) + b * fx * (1.0f - fy) +
  39. c * (1.0f - fx) * fy + d * fx * fy;
  40. };
  41. for (const auto &segment : m_riverSegments) {
  42. QVector3D dir = segment.end - segment.start;
  43. float length = dir.length();
  44. if (length < 0.01f) {
  45. m_meshes.push_back(nullptr);
  46. continue;
  47. }
  48. dir.normalize();
  49. QVector3D perpendicular(-dir.z(), 0.0f, dir.x());
  50. float halfWidth = segment.width * 0.5f;
  51. int lengthSteps =
  52. static_cast<int>(std::ceil(length / (m_tileSize * 0.5f))) + 1;
  53. lengthSteps = std::max(lengthSteps, 8);
  54. std::vector<Vertex> vertices;
  55. std::vector<unsigned int> indices;
  56. for (int i = 0; i < lengthSteps; ++i) {
  57. float t = static_cast<float>(i) / static_cast<float>(lengthSteps - 1);
  58. QVector3D centerPos = segment.start + dir * (length * t);
  59. float noiseFreq1 = 2.0f;
  60. float noiseFreq2 = 5.0f;
  61. float noiseFreq3 = 10.0f;
  62. float edgeNoise1 =
  63. noise(centerPos.x() * noiseFreq1, centerPos.z() * noiseFreq1);
  64. float edgeNoise2 =
  65. noise(centerPos.x() * noiseFreq2, centerPos.z() * noiseFreq2);
  66. float edgeNoise3 =
  67. noise(centerPos.x() * noiseFreq3, centerPos.z() * noiseFreq3);
  68. float combinedNoise =
  69. edgeNoise1 * 0.5f + edgeNoise2 * 0.3f + edgeNoise3 * 0.2f;
  70. combinedNoise = (combinedNoise - 0.5f) * 2.0f;
  71. float widthVariation = combinedNoise * halfWidth * 0.35f;
  72. float meander = noise(t * 3.0f, length * 0.1f) * 0.3f;
  73. QVector3D centerOffset = perpendicular * meander;
  74. centerPos += centerOffset;
  75. QVector3D left = centerPos - perpendicular * (halfWidth + widthVariation);
  76. QVector3D right =
  77. centerPos + perpendicular * (halfWidth + widthVariation);
  78. float normal[3] = {0.0f, 1.0f, 0.0f};
  79. Vertex leftVertex;
  80. leftVertex.position[0] = left.x();
  81. leftVertex.position[1] = left.y();
  82. leftVertex.position[2] = left.z();
  83. leftVertex.normal[0] = normal[0];
  84. leftVertex.normal[1] = normal[1];
  85. leftVertex.normal[2] = normal[2];
  86. leftVertex.texCoord[0] = 0.0f;
  87. leftVertex.texCoord[1] = t;
  88. vertices.push_back(leftVertex);
  89. Vertex rightVertex;
  90. rightVertex.position[0] = right.x();
  91. rightVertex.position[1] = right.y();
  92. rightVertex.position[2] = right.z();
  93. rightVertex.normal[0] = normal[0];
  94. rightVertex.normal[1] = normal[1];
  95. rightVertex.normal[2] = normal[2];
  96. rightVertex.texCoord[0] = 1.0f;
  97. rightVertex.texCoord[1] = t;
  98. vertices.push_back(rightVertex);
  99. if (i < lengthSteps - 1) {
  100. unsigned int idx0 = i * 2;
  101. unsigned int idx1 = idx0 + 1;
  102. unsigned int idx2 = idx0 + 2;
  103. unsigned int idx3 = idx0 + 3;
  104. indices.push_back(idx0);
  105. indices.push_back(idx2);
  106. indices.push_back(idx1);
  107. indices.push_back(idx1);
  108. indices.push_back(idx2);
  109. indices.push_back(idx3);
  110. }
  111. }
  112. if (!vertices.empty() && !indices.empty()) {
  113. m_meshes.push_back(std::make_unique<Mesh>(vertices, indices));
  114. } else {
  115. m_meshes.push_back(nullptr);
  116. }
  117. }
  118. }
  119. void RiverRenderer::submit(Renderer &renderer, ResourceManager *resources) {
  120. if (m_meshes.empty() || m_riverSegments.empty()) {
  121. return;
  122. }
  123. Q_UNUSED(resources);
  124. auto &visibility = Game::Map::VisibilityService::instance();
  125. const bool useVisibility = visibility.isInitialized();
  126. auto shader = renderer.getShader("river");
  127. if (!shader) {
  128. return;
  129. }
  130. renderer.setCurrentShader(shader);
  131. QMatrix4x4 model;
  132. model.setToIdentity();
  133. size_t meshIndex = 0;
  134. for (const auto &segment : m_riverSegments) {
  135. if (meshIndex >= m_meshes.size())
  136. break;
  137. auto *mesh = m_meshes[meshIndex].get();
  138. ++meshIndex;
  139. if (!mesh) {
  140. continue;
  141. }
  142. QVector3D dir = segment.end - segment.start;
  143. float length = dir.length();
  144. float alpha = 1.0f;
  145. QVector3D colorMultiplier(1.0f, 1.0f, 1.0f);
  146. if (useVisibility) {
  147. int maxVisibilityState = 0;
  148. dir.normalize();
  149. int samplesPerSegment = 5;
  150. for (int i = 0; i < samplesPerSegment; ++i) {
  151. float t =
  152. static_cast<float>(i) / static_cast<float>(samplesPerSegment - 1);
  153. QVector3D pos = segment.start + dir * (length * t);
  154. if (visibility.isVisibleWorld(pos.x(), pos.z())) {
  155. maxVisibilityState = 2;
  156. break;
  157. } else if (visibility.isExploredWorld(pos.x(), pos.z())) {
  158. maxVisibilityState = std::max(maxVisibilityState, 1);
  159. }
  160. }
  161. if (maxVisibilityState == 0) {
  162. continue;
  163. } else if (maxVisibilityState == 1) {
  164. alpha = 0.5f;
  165. colorMultiplier = QVector3D(0.4f, 0.4f, 0.45f);
  166. }
  167. }
  168. QVector3D finalColor(colorMultiplier.x(), colorMultiplier.y(),
  169. colorMultiplier.z());
  170. renderer.mesh(mesh, model, finalColor, nullptr, alpha);
  171. }
  172. renderer.setCurrentShader(nullptr);
  173. }
  174. } // namespace Render::GL