ground_renderer.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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.grassPrimary * 0.97F;
  54. const QVector3D secondary = m_biomeSettings.grassSecondary * 0.93F;
  55. const QVector3D dry = m_biomeSettings.grassDry * 0.90F;
  56. const QVector3D soil = m_biomeSettings.soilColor * 0.68F;
  57. params.grassPrimary = saturate(primary);
  58. params.grassSecondary = saturate(secondary);
  59. params.grassDry = saturate(dry);
  60. params.soilColor = saturate(soil);
  61. params.rockLow = saturate(m_biomeSettings.rockLow);
  62. params.rockHigh = saturate(m_biomeSettings.rockHigh);
  63. params.tint = QVector3D(0.96F, 0.98F, 0.96F);
  64. params.tile_size = std::max(0.25F, m_tile_size);
  65. params.macroNoiseScale =
  66. std::max(0.012F, m_biomeSettings.terrainMacroNoiseScale * 0.60F);
  67. params.detail_noiseScale =
  68. std::max(0.045F, m_biomeSettings.terrainDetailNoiseScale * 0.75F);
  69. params.slopeRockThreshold = 0.72F;
  70. params.slopeRockSharpness = 4.5F;
  71. params.soilBlendHeight = -0.65F;
  72. params.soilBlendSharpness = 2.6F;
  73. params.noiseOffset = m_noiseOffset;
  74. params.noiseAngle = m_noiseAngle;
  75. const float target_amp =
  76. std::clamp(m_biomeSettings.heightNoiseAmplitude * 0.22F, 0.10F, 0.20F);
  77. params.heightNoiseStrength = target_amp;
  78. params.heightNoiseFrequency =
  79. std::max(0.6F, m_biomeSettings.heightNoiseFrequency * 1.05F);
  80. params.microBumpAmp = 0.07F;
  81. params.microBumpFreq = 2.2F;
  82. params.microNormalWeight = 0.65F;
  83. params.albedoJitter = 0.05F;
  84. params.ambientBoost = m_biomeSettings.terrainAmbientBoost * 0.85F;
  85. params.rockDetailStrength = m_biomeSettings.terrainRockDetailStrength * 0.18F;
  86. QVector3D const l(0.35F, 0.85F, 0.42F);
  87. params.light_direction = l.normalized();
  88. params.isGroundPlane = true;
  89. m_cachedParams = params;
  90. m_cachedParamsValid = true;
  91. return params;
  92. }
  93. void GroundRenderer::submit(Renderer &renderer, ResourceManager *resources) {
  94. if (resources == nullptr) {
  95. return;
  96. }
  97. if (m_hasBiome) {
  98. Mesh *plane = resources->ground();
  99. if (plane != nullptr) {
  100. const TerrainChunkParams params = buildParams();
  101. const bool model_changed =
  102. m_modelDirty || (m_lastSubmittedModel != m_model);
  103. const bool state_changed =
  104. (m_lastSubmittedStateVersion != m_stateVersion);
  105. (void)model_changed;
  106. (void)state_changed;
  107. renderer.terrainChunk(plane, m_model, params, 0x0040U, true, +0.0008F);
  108. m_lastSubmittedModel = m_model;
  109. m_modelDirty = false;
  110. m_lastSubmittedStateVersion = m_stateVersion;
  111. return;
  112. }
  113. }
  114. const float cell = (m_tile_size > 0.0F ? m_tile_size : 1.0F);
  115. const float extent = (m_width > 0 && m_height > 0)
  116. ? std::max(m_width, m_height) * m_tile_size * 0.5F
  117. : m_extent;
  118. renderer.grid(m_model, m_color, cell, 0.06F, extent);
  119. }
  120. } // namespace Render::GL