graphics_settings.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #pragma once
  2. #include <cstdint>
  3. namespace Render {
  4. enum class GraphicsQuality : uint8_t {
  5. Low = 0,
  6. Medium = 1,
  7. High = 2,
  8. Ultra = 3
  9. };
  10. struct LODMultipliers {
  11. float humanoid_full;
  12. float humanoid_reduced;
  13. float humanoid_minimal;
  14. float humanoid_billboard;
  15. float horse_full;
  16. float horse_reduced;
  17. float horse_minimal;
  18. float horse_billboard;
  19. float shadow_distance;
  20. bool enable_shadows;
  21. };
  22. struct GraphicsFeatures {
  23. bool enable_facial_hair;
  24. bool enable_mane_detail;
  25. bool enable_tail_detail;
  26. bool enable_armor_detail;
  27. bool enable_equipment_detail;
  28. bool enable_ground_shadows;
  29. bool enable_pose_cache;
  30. };
  31. struct BatchingConfig {
  32. bool force_batching;
  33. bool never_batch;
  34. int batching_unit_threshold;
  35. float batching_zoom_start;
  36. float batching_zoom_full;
  37. };
  38. struct VisibilityBudget {
  39. int max_full_detail_units;
  40. bool enabled;
  41. };
  42. class GraphicsSettings {
  43. public:
  44. static auto instance() noexcept -> GraphicsSettings & {
  45. static GraphicsSettings inst;
  46. return inst;
  47. }
  48. [[nodiscard]] auto quality() const noexcept -> GraphicsQuality {
  49. return m_quality;
  50. }
  51. void setQuality(GraphicsQuality q) noexcept {
  52. m_quality = q;
  53. apply_preset(q);
  54. }
  55. [[nodiscard]] auto
  56. lod_multipliers() const noexcept -> const LODMultipliers & {
  57. return m_lod_multipliers;
  58. }
  59. [[nodiscard]] auto features() const noexcept -> const GraphicsFeatures & {
  60. return m_features;
  61. }
  62. [[nodiscard]] auto
  63. batching_config() const noexcept -> const BatchingConfig & {
  64. return m_batching_config;
  65. }
  66. [[nodiscard]] auto
  67. visibility_budget() const noexcept -> const VisibilityBudget & {
  68. return m_visibility_budget;
  69. }
  70. [[nodiscard]] auto
  71. calculate_batching_ratio(int visible_units,
  72. float camera_height) const noexcept -> float {
  73. if (m_batching_config.never_batch) {
  74. return 0.0F;
  75. }
  76. if (m_batching_config.force_batching) {
  77. return 1.0F;
  78. }
  79. float unit_factor = 0.0F;
  80. if (visible_units > m_batching_config.batching_unit_threshold) {
  81. int excess = visible_units - m_batching_config.batching_unit_threshold;
  82. int range = m_batching_config.batching_unit_threshold * 3;
  83. unit_factor = static_cast<float>(excess) / static_cast<float>(range);
  84. unit_factor =
  85. unit_factor < 0.0F ? 0.0F : (unit_factor > 1.0F ? 1.0F : unit_factor);
  86. }
  87. float zoom_factor = 0.0F;
  88. if (camera_height > m_batching_config.batching_zoom_start) {
  89. float range = m_batching_config.batching_zoom_full -
  90. m_batching_config.batching_zoom_start;
  91. if (range > 0.0F) {
  92. zoom_factor =
  93. (camera_height - m_batching_config.batching_zoom_start) / range;
  94. zoom_factor = zoom_factor < 0.0F
  95. ? 0.0F
  96. : (zoom_factor > 1.0F ? 1.0F : zoom_factor);
  97. }
  98. }
  99. return unit_factor > zoom_factor ? unit_factor : zoom_factor;
  100. }
  101. [[nodiscard]] auto humanoid_full_detail_distance() const noexcept -> float {
  102. return kBaseHumanoidFull * m_lod_multipliers.humanoid_full;
  103. }
  104. [[nodiscard]] auto
  105. humanoid_reduced_detail_distance() const noexcept -> float {
  106. return kBaseHumanoidReduced * m_lod_multipliers.humanoid_reduced;
  107. }
  108. [[nodiscard]] auto
  109. humanoid_minimal_detail_distance() const noexcept -> float {
  110. return kBaseHumanoidMinimal * m_lod_multipliers.humanoid_minimal;
  111. }
  112. [[nodiscard]] auto humanoid_billboard_distance() const noexcept -> float {
  113. return kBaseHumanoidBillboard * m_lod_multipliers.humanoid_billboard;
  114. }
  115. [[nodiscard]] auto horse_full_detail_distance() const noexcept -> float {
  116. return kBaseHorseFull * m_lod_multipliers.horse_full;
  117. }
  118. [[nodiscard]] auto horse_reduced_detail_distance() const noexcept -> float {
  119. return kBaseHorseReduced * m_lod_multipliers.horse_reduced;
  120. }
  121. [[nodiscard]] auto horse_minimal_detail_distance() const noexcept -> float {
  122. return kBaseHorseMinimal * m_lod_multipliers.horse_minimal;
  123. }
  124. [[nodiscard]] auto horse_billboard_distance() const noexcept -> float {
  125. return kBaseHorseBillboard * m_lod_multipliers.horse_billboard;
  126. }
  127. [[nodiscard]] auto shadow_max_distance() const noexcept -> float {
  128. return m_lod_multipliers.shadow_distance;
  129. }
  130. [[nodiscard]] auto shadows_enabled() const noexcept -> bool {
  131. return m_lod_multipliers.enable_shadows;
  132. }
  133. private:
  134. GraphicsSettings() { setQuality(GraphicsQuality::Ultra); }
  135. void apply_preset(GraphicsQuality q) noexcept {
  136. switch (q) {
  137. case GraphicsQuality::Low:
  138. m_lod_multipliers = {.humanoid_full = 0.8F,
  139. .humanoid_reduced = 0.8F,
  140. .humanoid_minimal = 0.8F,
  141. .humanoid_billboard = 0.8F,
  142. .horse_full = 0.8F,
  143. .horse_reduced = 0.8F,
  144. .horse_minimal = 0.8F,
  145. .horse_billboard = 0.8F,
  146. .shadow_distance = 25.0F,
  147. .enable_shadows = true};
  148. m_features = {.enable_facial_hair = false,
  149. .enable_mane_detail = false,
  150. .enable_tail_detail = false,
  151. .enable_armor_detail = true,
  152. .enable_equipment_detail = true,
  153. .enable_ground_shadows = true,
  154. .enable_pose_cache = true};
  155. m_batching_config = {.force_batching = true,
  156. .never_batch = false,
  157. .batching_unit_threshold = 0,
  158. .batching_zoom_start = 0.0F,
  159. .batching_zoom_full = 0.0F};
  160. m_visibility_budget = {.max_full_detail_units = 150, .enabled = true};
  161. break;
  162. case GraphicsQuality::Medium:
  163. m_lod_multipliers = {.humanoid_full = 1.0F,
  164. .humanoid_reduced = 1.0F,
  165. .humanoid_minimal = 1.0F,
  166. .humanoid_billboard = 1.0F,
  167. .horse_full = 1.0F,
  168. .horse_reduced = 1.0F,
  169. .horse_minimal = 1.0F,
  170. .horse_billboard = 1.0F,
  171. .shadow_distance = 40.0F,
  172. .enable_shadows = true};
  173. m_features = {.enable_facial_hair = true,
  174. .enable_mane_detail = true,
  175. .enable_tail_detail = true,
  176. .enable_armor_detail = true,
  177. .enable_equipment_detail = true,
  178. .enable_ground_shadows = true,
  179. .enable_pose_cache = true};
  180. m_batching_config = {.force_batching = false,
  181. .never_batch = false,
  182. .batching_unit_threshold = 30,
  183. .batching_zoom_start = 60.0F,
  184. .batching_zoom_full = 90.0F};
  185. m_visibility_budget = {.max_full_detail_units = 300, .enabled = true};
  186. break;
  187. case GraphicsQuality::High:
  188. m_lod_multipliers = {.humanoid_full = 2.0F,
  189. .humanoid_reduced = 2.0F,
  190. .humanoid_minimal = 2.0F,
  191. .humanoid_billboard = 2.0F,
  192. .horse_full = 2.0F,
  193. .horse_reduced = 2.0F,
  194. .horse_minimal = 2.0F,
  195. .horse_billboard = 2.0F,
  196. .shadow_distance = 80.0F,
  197. .enable_shadows = true};
  198. m_features = {.enable_facial_hair = true,
  199. .enable_mane_detail = true,
  200. .enable_tail_detail = true,
  201. .enable_armor_detail = true,
  202. .enable_equipment_detail = true,
  203. .enable_ground_shadows = true,
  204. .enable_pose_cache = true};
  205. m_batching_config = {.force_batching = false,
  206. .never_batch = false,
  207. .batching_unit_threshold = 50,
  208. .batching_zoom_start = 80.0F,
  209. .batching_zoom_full = 120.0F};
  210. m_visibility_budget = {.max_full_detail_units = 900, .enabled = true};
  211. break;
  212. case GraphicsQuality::Ultra:
  213. m_lod_multipliers = {.humanoid_full = 100.0F,
  214. .humanoid_reduced = 100.0F,
  215. .humanoid_minimal = 100.0F,
  216. .humanoid_billboard = 100.0F,
  217. .horse_full = 100.0F,
  218. .horse_reduced = 100.0F,
  219. .horse_minimal = 100.0F,
  220. .horse_billboard = 100.0F,
  221. .shadow_distance = 200.0F,
  222. .enable_shadows = true};
  223. m_features = {.enable_facial_hair = true,
  224. .enable_mane_detail = true,
  225. .enable_tail_detail = true,
  226. .enable_armor_detail = true,
  227. .enable_equipment_detail = true,
  228. .enable_ground_shadows = true,
  229. .enable_pose_cache = false};
  230. m_batching_config = {.force_batching = false,
  231. .never_batch = true,
  232. .batching_unit_threshold = 999999,
  233. .batching_zoom_start = 999999.0F,
  234. .batching_zoom_full = 999999.0F};
  235. m_visibility_budget = {.max_full_detail_units = 5000, .enabled = false};
  236. break;
  237. }
  238. }
  239. static constexpr float kBaseHumanoidFull = 15.0F;
  240. static constexpr float kBaseHumanoidReduced = 35.0F;
  241. static constexpr float kBaseHumanoidMinimal = 60.0F;
  242. static constexpr float kBaseHumanoidBillboard = 100.0F;
  243. static constexpr float kBaseHorseFull = 20.0F;
  244. static constexpr float kBaseHorseReduced = 40.0F;
  245. static constexpr float kBaseHorseMinimal = 70.0F;
  246. static constexpr float kBaseHorseBillboard = 100.0F;
  247. GraphicsQuality m_quality{GraphicsQuality::Ultra};
  248. LODMultipliers m_lod_multipliers{};
  249. GraphicsFeatures m_features{};
  250. BatchingConfig m_batching_config{};
  251. VisibilityBudget m_visibility_budget{};
  252. };
  253. } // namespace Render