ground_renderer.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include "ground_renderer.h"
  2. #include "../draw_queue.h"
  3. #include "../gl/resources.h"
  4. #include "../scene_renderer.h"
  5. #include "ground/terrain_gpu.h"
  6. #include <algorithm>
  7. #include <cmath>
  8. #include <qmatrix4x4.h>
  9. #include <qvectornd.h>
  10. namespace Render::GL {
  11. namespace {
  12. const QMatrix4x4 k_identity_matrix;
  13. inline auto saturate(const QVector3D &c) -> QVector3D {
  14. return {std::clamp(c.x(), 0.0F, 1.0F), std::clamp(c.y(), 0.0F, 1.0F),
  15. std::clamp(c.z(), 0.0F, 1.0F)};
  16. }
  17. } // namespace
  18. static auto clamp01(const QVector3D &c) -> QVector3D { return saturate(c); }
  19. void GroundRenderer::recomputeModel() {
  20. QMatrix4x4 new_model = k_identity_matrix;
  21. new_model.translate(0.0F, -0.5F, 0.0F);
  22. if (m_width > 0 && m_height > 0) {
  23. const float scale_x = std::sqrt(float(m_width)) * m_tile_size;
  24. const float scale_z = std::sqrt(float(m_height)) * m_tile_size;
  25. new_model.scale(scale_x, 1.0F, scale_z);
  26. } else {
  27. new_model.scale(m_extent, 1.0F, m_extent);
  28. }
  29. if (new_model != m_model) {
  30. m_model = new_model;
  31. m_modelDirty = true;
  32. }
  33. }
  34. void GroundRenderer::updateNoiseOffset() {
  35. const float span_x = (m_width > 0 ? float(m_width) * m_tile_size : m_extent);
  36. const float span_z =
  37. (m_height > 0 ? float(m_height) * m_tile_size : m_extent);
  38. const auto seed = static_cast<float>(m_biomeSettings.seed % 1024U);
  39. QVector2D new_offset;
  40. new_offset.setX(span_x * 0.37F + seed * 0.21F);
  41. new_offset.setY(span_z * 0.43F + seed * 0.17F);
  42. m_noiseAngle = std::fmod(seed * 0.6180339887F, 1.0F) * 6.28318530718F;
  43. if (new_offset != m_noiseOffset) {
  44. m_noiseOffset = new_offset;
  45. invalidateParamsCache();
  46. }
  47. }
  48. auto GroundRenderer::buildParams() const -> TerrainChunkParams {
  49. if (m_cachedParamsValid) {
  50. return m_cachedParams;
  51. }
  52. TerrainChunkParams params;
  53. const QVector3D primary = m_biomeSettings.grass_primary * 0.97F;
  54. const QVector3D secondary = m_biomeSettings.grass_secondary * 0.93F;
  55. const QVector3D dry = m_biomeSettings.grass_dry * 0.90F;
  56. const QVector3D soil = m_biomeSettings.soil_color * 0.68F;
  57. params.grass_primary = saturate(primary);
  58. params.grass_secondary = saturate(secondary);
  59. params.grass_dry = saturate(dry);
  60. params.soil_color = saturate(soil);
  61. params.rock_low = saturate(m_biomeSettings.rock_low);
  62. params.rock_high = saturate(m_biomeSettings.rock_high);
  63. params.tint = QVector3D(0.96F, 0.98F, 0.96F);
  64. params.tile_size = std::max(0.25F, m_tile_size);
  65. params.macro_noise_scale =
  66. std::max(0.012F, m_biomeSettings.terrain_macro_noise_scale * 0.60F);
  67. params.detail_noise_scale =
  68. std::max(0.045F, m_biomeSettings.terrain_detail_noise_scale * 0.75F);
  69. params.slope_rock_threshold =
  70. std::clamp(m_biomeSettings.terrain_rock_threshold + 0.30F, 0.40F, 0.90F);
  71. params.slope_rock_sharpness =
  72. std::clamp(m_biomeSettings.terrain_rock_sharpness + 1.5F, 2.0F, 6.0F);
  73. params.soil_blend_height = m_biomeSettings.terrain_soil_height - 1.25F;
  74. params.soil_blend_sharpness =
  75. std::clamp(m_biomeSettings.terrain_soil_sharpness * 0.75F, 1.5F, 5.0F);
  76. params.noise_offset = m_noiseOffset;
  77. params.noise_angle = m_noiseAngle;
  78. float target_amp;
  79. float target_freq;
  80. if (m_biomeSettings.ground_irregularity_enabled) {
  81. target_amp = std::clamp(m_biomeSettings.irregularity_amplitude * 0.85F,
  82. 0.15F, 0.70F);
  83. target_freq = std::max(0.45F, m_biomeSettings.irregularity_scale * 2.5F);
  84. } else {
  85. target_amp = std::clamp(m_biomeSettings.height_noise_amplitude * 0.22F,
  86. 0.10F, 0.20F);
  87. target_freq =
  88. std::max(0.6F, m_biomeSettings.height_noise_frequency * 1.05F);
  89. }
  90. params.height_noise_strength = target_amp;
  91. params.height_noise_frequency = target_freq;
  92. params.micro_bump_amp = 0.07F;
  93. params.micro_bump_freq = 2.2F;
  94. params.micro_normal_weight = 0.65F;
  95. params.albedo_jitter = 0.05F;
  96. params.ambient_boost = m_biomeSettings.terrain_ambient_boost * 0.85F;
  97. params.rock_detail_strength =
  98. m_biomeSettings.terrain_rock_detail_strength * 0.18F;
  99. QVector3D const l(0.35F, 0.85F, 0.42F);
  100. params.light_direction = l.normalized();
  101. params.is_ground_plane = true;
  102. params.snow_coverage = std::clamp(m_biomeSettings.snow_coverage, 0.0F, 1.0F);
  103. params.moisture_level =
  104. std::clamp(m_biomeSettings.moisture_level, 0.0F, 1.0F);
  105. params.crack_intensity =
  106. std::clamp(m_biomeSettings.crack_intensity, 0.0F, 1.0F);
  107. params.rock_exposure = std::clamp(m_biomeSettings.rock_exposure, 0.0F, 1.0F);
  108. params.grass_saturation =
  109. std::clamp(m_biomeSettings.grass_saturation, 0.0F, 1.5F);
  110. params.soil_roughness =
  111. std::clamp(m_biomeSettings.soil_roughness, 0.0F, 1.0F);
  112. params.snow_color = saturate(m_biomeSettings.snow_color);
  113. m_cachedParams = params;
  114. m_cachedParamsValid = true;
  115. return params;
  116. }
  117. void GroundRenderer::submit(Renderer &renderer, ResourceManager *resources) {
  118. syncBiomeFromService();
  119. if (resources == nullptr) {
  120. return;
  121. }
  122. if (m_hasBiome) {
  123. Mesh *plane = resources->ground();
  124. if (plane != nullptr) {
  125. const TerrainChunkParams params = buildParams();
  126. const bool model_changed =
  127. m_modelDirty || (m_lastSubmittedModel != m_model);
  128. const bool state_changed =
  129. (m_lastSubmittedStateVersion != m_stateVersion);
  130. (void)model_changed;
  131. (void)state_changed;
  132. renderer.terrainChunk(plane, m_model, params, 0x0040U, true, +0.0008F);
  133. m_lastSubmittedModel = m_model;
  134. m_modelDirty = false;
  135. m_lastSubmittedStateVersion = m_stateVersion;
  136. return;
  137. }
  138. }
  139. const float cell = (m_tile_size > 0.0F ? m_tile_size : 1.0F);
  140. const float extent = (m_width > 0 && m_height > 0)
  141. ? std::max(m_width, m_height) * m_tile_size * 0.5F
  142. : m_extent;
  143. renderer.grid(m_model, m_color, cell, 0.06F, extent);
  144. }
  145. void GroundRenderer::syncBiomeFromService() {
  146. auto &service = Game::Map::TerrainService::instance();
  147. if (!service.isInitialized()) {
  148. return;
  149. }
  150. const auto &current = service.biomeSettings();
  151. if (!m_hasBiome || !biomeEquals(current, m_biomeSettings)) {
  152. m_biomeSettings = current;
  153. m_hasBiome = true;
  154. updateNoiseOffset();
  155. invalidateParamsCache();
  156. }
  157. }
  158. auto GroundRenderer::biomeEquals(const Game::Map::BiomeSettings &a,
  159. const Game::Map::BiomeSettings &b) -> bool {
  160. return a.ground_type == b.ground_type && a.grass_primary == b.grass_primary &&
  161. a.grass_secondary == b.grass_secondary && a.grass_dry == b.grass_dry &&
  162. a.soil_color == b.soil_color && a.rock_low == b.rock_low &&
  163. a.rock_high == b.rock_high &&
  164. a.terrain_macro_noise_scale == b.terrain_macro_noise_scale &&
  165. a.terrain_detail_noise_scale == b.terrain_detail_noise_scale &&
  166. a.terrain_soil_height == b.terrain_soil_height &&
  167. a.terrain_soil_sharpness == b.terrain_soil_sharpness &&
  168. a.terrain_rock_threshold == b.terrain_rock_threshold &&
  169. a.terrain_rock_sharpness == b.terrain_rock_sharpness &&
  170. a.terrain_ambient_boost == b.terrain_ambient_boost &&
  171. a.terrain_rock_detail_strength == b.terrain_rock_detail_strength &&
  172. a.height_noise_amplitude == b.height_noise_amplitude &&
  173. a.height_noise_frequency == b.height_noise_frequency &&
  174. a.ground_irregularity_enabled == b.ground_irregularity_enabled &&
  175. a.irregularity_scale == b.irregularity_scale &&
  176. a.irregularity_amplitude == b.irregularity_amplitude &&
  177. a.seed == b.seed && a.snow_coverage == b.snow_coverage &&
  178. a.moisture_level == b.moisture_level &&
  179. a.crack_intensity == b.crack_intensity &&
  180. a.rock_exposure == b.rock_exposure &&
  181. a.grass_saturation == b.grass_saturation &&
  182. a.soil_roughness == b.soil_roughness && a.snow_color == b.snow_color;
  183. }
  184. } // namespace Render::GL