settings.gd 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. extends Control
  2. # Window project settings:
  3. # - Stretch mode is set to `canvas_items` (`2d` in Godot 3.x)
  4. # - Stretch aspect is set to `expand`
  5. @onready var world_environment := $WorldEnvironment
  6. @onready var directional_light := $Node3D/DirectionalLight3D
  7. @onready var camera := $Node3D/Camera3D
  8. @onready var fps_label := $FPSLabel
  9. @onready var resolution_label := $ResolutionLabel
  10. var counter := 0.0
  11. # When the screen changes size, we need to update the 3D
  12. # viewport quality setting. If we don't do this, the viewport will take
  13. # the size from the main viewport.
  14. var viewport_start_size := Vector2(
  15. ProjectSettings.get_setting(&"display/window/size/viewport_width"),
  16. ProjectSettings.get_setting(&"display/window/size/viewport_height")
  17. )
  18. func _ready() -> void:
  19. get_viewport().size_changed.connect(self.update_resolution_label)
  20. update_resolution_label()
  21. # Disable V-Sync to uncap framerate on supported platforms. This makes performance comparison
  22. # easier on high-end machines that easily reach the monitor's refresh rate.
  23. DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
  24. func _process(delta: float) -> void:
  25. counter += delta
  26. # Hide FPS label until it's initially updated by the engine (this can take up to 1 second).
  27. fps_label.visible = counter >= 1.0
  28. fps_label.text = "%d FPS (%.2f mspf)" % [Engine.get_frames_per_second(), 1000.0 / Engine.get_frames_per_second()]
  29. # Color FPS counter depending on framerate.
  30. # The Gradient resource is stored as metadata within the FPSLabel node (accessible in the inspector).
  31. fps_label.modulate = fps_label.get_meta("gradient").sample(remap(Engine.get_frames_per_second(), 0, 180, 0.0, 1.0))
  32. func update_resolution_label() -> void:
  33. var viewport_render_size = get_viewport().size * get_viewport().scaling_3d_scale
  34. resolution_label.text = "3D viewport resolution: %d × %d (%d%%)" \
  35. % [viewport_render_size.x, viewport_render_size.y, round(get_viewport().scaling_3d_scale * 100)]
  36. func _on_HideShowButton_toggled(show_settings: bool) -> void:
  37. # Option to hide the settings so you can see the changes to the 3d world better.
  38. var button := $HideShowButton
  39. var settings_menu := $SettingsMenu
  40. if show_settings:
  41. button.text = "Hide settings"
  42. else:
  43. button.text = "Show settings"
  44. settings_menu.visible = show_settings
  45. # Video settings.
  46. func _on_ui_scale_option_button_item_selected(index: int) -> void:
  47. # For changing the UI, we take the viewport size, which we set in the project settings.
  48. var new_size := viewport_start_size
  49. if index == 0: # Smaller (66%)
  50. new_size *= 1.5
  51. elif index == 1: # Small (80%)
  52. new_size *= 1.25
  53. elif index == 2: # Medium (100%) (default)
  54. new_size *= 1.0
  55. elif index == 3: # Large (133%)
  56. new_size *= 0.75
  57. elif index == 4: # Larger (200%)
  58. new_size *= 0.5
  59. get_tree().root.set_content_scale_size(new_size)
  60. func _on_quality_slider_value_changed(value: float) -> void:
  61. get_viewport().scaling_3d_scale = value
  62. update_resolution_label()
  63. func _on_filter_option_button_item_selected(index: int) -> void:
  64. # Viewport scale mode setting.
  65. if index == 0: # Bilinear (Fastest)
  66. get_viewport().scaling_3d_mode = Viewport.SCALING_3D_MODE_BILINEAR
  67. # FSR Sharpness is only effective when the scaling mode is FSR 1.0.
  68. %FSRSharpnessLabel.visible = false
  69. %FSRSharpnessSlider.visible = false
  70. elif index == 1: # FSR 1.0 (Fast)
  71. get_viewport().scaling_3d_mode = Viewport.SCALING_3D_MODE_FSR
  72. # FSR Sharpness is only effective when the scaling mode is FSR 1.0.
  73. %FSRSharpnessLabel.visible = true
  74. %FSRSharpnessSlider.visible = true
  75. func _on_fsr_sharpness_slider_value_changed(value: float) -> void:
  76. # Lower FSR sharpness values result in a sharper image.
  77. # Invert the slider so that higher values result in a sharper image,
  78. # which is generally expected from users.
  79. get_viewport().fsr_sharpness = 2.0 - value
  80. func _on_vsync_option_button_item_selected(index: int) -> void:
  81. # Vsync is enabled by default.
  82. # Vertical synchronization locks framerate and makes screen tearing not visible at the cost of
  83. # higher input latency and stuttering when the framerate target is not met.
  84. # Adaptive V-Sync automatically disables V-Sync when the framerate target is not met, and enables
  85. # V-Sync otherwise. This prevents suttering and reduces input latency when the framerate target
  86. # is not met, at the cost of visible tearing.
  87. if index == 0: # Disabled (default)
  88. DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
  89. elif index == 1: # Adaptive
  90. DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ADAPTIVE)
  91. elif index == 2: # Enabled
  92. DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED)
  93. func _on_limit_fps_slider_value_changed(value: float):
  94. # The maximum number of frames per second that can be rendered.
  95. # A value of 0 means "no limit".
  96. Engine.max_fps = value
  97. func _on_msaa_option_button_item_selected(index: int) -> void:
  98. # Multi-sample anti-aliasing. High quality, but slow. It also does not smooth out the edges of
  99. # transparent (alpha scissor) textures.
  100. if index == 0: # Disabled (default)
  101. get_viewport().msaa_3d = Viewport.MSAA_DISABLED
  102. elif index == 1: # 2×
  103. get_viewport().msaa_3d = Viewport.MSAA_2X
  104. elif index == 2: # 4×
  105. get_viewport().msaa_3d = Viewport.MSAA_4X
  106. elif index == 3: # 8×
  107. get_viewport().msaa_3d = Viewport.MSAA_8X
  108. func _on_taa_option_button_item_selected(index: int) -> void:
  109. # Temporal antialiasing. Smooths out everything including specular aliasing, but can introduce
  110. # ghosting artifacts and blurring in motion. Moderate performance cost.
  111. get_viewport().use_taa = index == 1
  112. func _on_fxaa_option_button_item_selected(index: int) -> void:
  113. # Fast approximate anti-aliasing. Much faster than MSAA (and works on alpha scissor edges),
  114. # but blurs the whole scene rendering slightly.
  115. get_viewport().screen_space_aa = int(index == 1) as Viewport.ScreenSpaceAA
  116. func _on_fullscreen_option_button_item_selected(index: int) -> void:
  117. # To change between winow, fullscreen and other window modes,
  118. # set the root mode to one of the options of Window.MODE_*.
  119. # Other modes are maximized and minimized.
  120. if index == 0: # Disabled (default)
  121. get_tree().root.set_mode(Window.MODE_WINDOWED)
  122. elif index == 1: # Fullscreen
  123. get_tree().root.set_mode(Window.MODE_FULLSCREEN)
  124. elif index == 2: # Exclusive Fullscreen
  125. get_tree().root.set_mode(Window.MODE_EXCLUSIVE_FULLSCREEN)
  126. func _on_fov_slider_value_changed(value: float) -> void:
  127. camera.fov = value
  128. # Quality settings.
  129. func _on_shadow_size_option_button_item_selected(index):
  130. if index == 0: # Minimum
  131. RenderingServer.directional_shadow_atlas_set_size(512, true)
  132. # Adjust shadow bias according to shadow resolution.
  133. # Higher resultions can use a lower bias without suffering from shadow acne.
  134. directional_light.shadow_bias = 0.06
  135. # Disable positional (omni/spot) light shadows entirely to further improve performance.
  136. # These often don't contribute as much to a scene compared to directional light shadows.
  137. get_viewport().positional_shadow_atlas_size = 0
  138. if index == 1: # Very Low
  139. RenderingServer.directional_shadow_atlas_set_size(1024, true)
  140. directional_light.shadow_bias = 0.04
  141. get_viewport().positional_shadow_atlas_size = 1024
  142. if index == 2: # Low
  143. RenderingServer.directional_shadow_atlas_set_size(2048, true)
  144. directional_light.shadow_bias = 0.03
  145. get_viewport().positional_shadow_atlas_size = 2048
  146. if index == 3: # Medium (default)
  147. RenderingServer.directional_shadow_atlas_set_size(4096, true)
  148. directional_light.shadow_bias = 0.02
  149. get_viewport().positional_shadow_atlas_size = 4096
  150. if index == 4: # High
  151. RenderingServer.directional_shadow_atlas_set_size(8192, true)
  152. directional_light.shadow_bias = 0.01
  153. get_viewport().positional_shadow_atlas_size = 8192
  154. if index == 5: # Ultra
  155. RenderingServer.directional_shadow_atlas_set_size(16384, true)
  156. directional_light.shadow_bias = 0.005
  157. get_viewport().positional_shadow_atlas_size = 16384
  158. func _on_shadow_filter_option_button_item_selected(index):
  159. if index == 0: # Very Low
  160. RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_HARD)
  161. RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_HARD)
  162. if index == 1: # Low
  163. RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_VERY_LOW)
  164. RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_VERY_LOW)
  165. if index == 2: # Medium (default)
  166. RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_LOW)
  167. RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_LOW)
  168. if index == 3: # High
  169. RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_MEDIUM)
  170. RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_MEDIUM)
  171. if index == 4: # Very High
  172. RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_HIGH)
  173. RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_HIGH)
  174. if index == 5: # Ultra
  175. RenderingServer.directional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_ULTRA)
  176. RenderingServer.positional_soft_shadow_filter_set_quality(RenderingServer.SHADOW_QUALITY_SOFT_ULTRA)
  177. func _on_mesh_lod_option_button_item_selected(index):
  178. if index == 0: # Very Low
  179. get_viewport().mesh_lod_threshold = 8.0
  180. if index == 0: # Low
  181. get_viewport().mesh_lod_threshold = 4.0
  182. if index == 1: # Medium
  183. get_viewport().mesh_lod_threshold = 2.0
  184. if index == 2: # High (default)
  185. get_viewport().mesh_lod_threshold = 1.0
  186. if index == 3: # Ultra
  187. # Always use highest LODs to avoid any form of pop-in.
  188. get_viewport().mesh_lod_threshold = 0.0
  189. # Effect settings.
  190. func _on_ss_reflections_option_button_item_selected(index: int) -> void:
  191. # This is a setting that is attached to the environment.
  192. # If your game requires you to change the environment,
  193. # then be sure to run this function again to make the setting effective.
  194. if index == 0: # Disabled (default)
  195. world_environment.environment.set_ssr_enabled(false)
  196. elif index == 1: # Low
  197. world_environment.environment.set_ssr_enabled(true)
  198. world_environment.environment.set_ssr_max_steps(8)
  199. elif index == 2: # Medium
  200. world_environment.environment.set_ssr_enabled(true)
  201. world_environment.environment.set_ssr_max_steps(32)
  202. elif index == 3: # High
  203. world_environment.environment.set_ssr_enabled(true)
  204. world_environment.environment.set_ssr_max_steps(56)
  205. func _on_ssao_option_button_item_selected(index: int) -> void:
  206. # This is a setting that is attached to the environment.
  207. # If your game requires you to change the environment,
  208. # then be sure to run this function again to make the setting effective.
  209. if index == 0: # Disabled (default)
  210. world_environment.environment.ssao_enabled = false
  211. if index == 1: # Very Low
  212. world_environment.environment.ssao_enabled = true
  213. RenderingServer.environment_set_ssao_quality(RenderingServer.ENV_SSAO_QUALITY_VERY_LOW, true, 0.5, 2, 50, 300)
  214. if index == 2: # Low
  215. world_environment.environment.ssao_enabled = true
  216. RenderingServer.environment_set_ssao_quality(RenderingServer.ENV_SSAO_QUALITY_VERY_LOW, true, 0.5, 2, 50, 300)
  217. if index == 3: # Medium
  218. world_environment.environment.ssao_enabled = true
  219. RenderingServer.environment_set_ssao_quality(RenderingServer.ENV_SSAO_QUALITY_MEDIUM, true, 0.5, 2, 50, 300)
  220. if index == 4: # High
  221. world_environment.environment.ssao_enabled = true
  222. RenderingServer.environment_set_ssao_quality(RenderingServer.ENV_SSAO_QUALITY_HIGH, true, 0.5, 2, 50, 300)
  223. func _on_ssil_option_button_item_selected(index: int) -> void:
  224. # This is a setting that is attached to the environment.
  225. # If your game requires you to change the environment,
  226. # then be sure to run this function again to make the setting effective.
  227. if index == 0: # Disabled (default)
  228. world_environment.environment.ssil_enabled = false
  229. if index == 1: # Very Low
  230. world_environment.environment.ssil_enabled = true
  231. RenderingServer.environment_set_ssil_quality(RenderingServer.ENV_SSIL_QUALITY_VERY_LOW, true, 0.5, 4, 50, 300)
  232. if index == 2: # Low
  233. world_environment.environment.ssil_enabled = true
  234. RenderingServer.environment_set_ssil_quality(RenderingServer.ENV_SSIL_QUALITY_LOW, true, 0.5, 4, 50, 300)
  235. if index == 3: # Medium
  236. world_environment.environment.ssil_enabled = true
  237. RenderingServer.environment_set_ssil_quality(RenderingServer.ENV_SSIL_QUALITY_MEDIUM, true, 0.5, 4, 50, 300)
  238. if index == 4: # High
  239. world_environment.environment.ssil_enabled = true
  240. RenderingServer.environment_set_ssil_quality(RenderingServer.ENV_SSIL_QUALITY_HIGH, true, 0.5, 4, 50, 300)
  241. func _on_sdfgi_option_button_item_selected(index: int) -> void:
  242. # This is a setting that is attached to the environment.
  243. # If your game requires you to change the environment,
  244. # then be sure to run this function again to make the setting effective.
  245. if index == 0: # Disabled (default)
  246. world_environment.environment.sdfgi_enabled = false
  247. if index == 1: # Low
  248. world_environment.environment.sdfgi_enabled = true
  249. RenderingServer.gi_set_use_half_resolution(true)
  250. if index == 2: # High
  251. world_environment.environment.sdfgi_enabled = true
  252. RenderingServer.gi_set_use_half_resolution(false)
  253. func _on_glow_option_button_item_selected(index: int) -> void:
  254. # This is a setting that is attached to the environment.
  255. # If your game requires you to change the environment,
  256. # then be sure to run this function again to make the setting effective.
  257. if index == 0: # Disabled (default)
  258. world_environment.environment.glow_enabled = false
  259. if index == 1: # Low
  260. world_environment.environment.glow_enabled = true
  261. if index == 2: # High
  262. world_environment.environment.glow_enabled = true
  263. func _on_volumetric_fog_option_button_item_selected(index: int) -> void:
  264. if index == 0: # Disabled (default)
  265. world_environment.environment.volumetric_fog_enabled = false
  266. if index == 1: # Low
  267. world_environment.environment.volumetric_fog_enabled = true
  268. RenderingServer.environment_set_volumetric_fog_filter_active(false)
  269. if index == 2: # High
  270. world_environment.environment.volumetric_fog_enabled = true
  271. RenderingServer.environment_set_volumetric_fog_filter_active(true)
  272. # Adjustment settings.
  273. func _on_brightness_slider_value_changed(value: float) -> void:
  274. # This is a setting that is attached to the environment.
  275. # If your game requires you to change the environment,
  276. # then be sure to run this function again to make the setting effective.
  277. # The slider value is clamped between 0.5 and 4.
  278. world_environment.environment.set_adjustment_brightness(value)
  279. func _on_contrast_slider_value_changed(value: float) -> void:
  280. # This is a setting that is attached to the environment.
  281. # If your game requires you to change the environment,
  282. # then be sure to run this function again to make the setting effective.
  283. # The slider value is clamped between 0.5 and 4.
  284. world_environment.environment.set_adjustment_contrast(value)
  285. func _on_saturation_slider_value_changed(value: float) -> void:
  286. # This is a setting that is attached to the environment.
  287. # If your game requires you to change the environment,
  288. # then be sure to run this function again to make the setting effective.
  289. # The slider value is clamped between 0.5 and 10.
  290. world_environment.environment.set_adjustment_saturation(value)
  291. # Quality presets.
  292. func _on_very_low_preset_pressed() -> void:
  293. %TAAOptionButton.selected = 0
  294. %MSAAOptionButton.selected = 0
  295. %FXAAOptionButton.selected = 0
  296. %ShadowSizeOptionButton.selected = 0
  297. %ShadowFilterOptionButton.selected = 0
  298. %MeshLODOptionButton.selected = 0
  299. %SDFGIOptionButton.selected = 0
  300. %GlowOptionButton.selected = 0
  301. %SSAOOptionButton.selected = 0
  302. %SSReflectionsOptionButton.selected = 0
  303. %SSILOptionButton.selected = 0
  304. %VolumetricFogOptionButton.selected = 0
  305. update_preset()
  306. func _on_low_preset_pressed() -> void:
  307. %TAAOptionButton.selected = 0
  308. %MSAAOptionButton.selected = 0
  309. %FXAAOptionButton.selected = 1
  310. %ShadowSizeOptionButton.selected = 1
  311. %ShadowFilterOptionButton.selected = 1
  312. %MeshLODOptionButton.selected = 1
  313. %SDFGIOptionButton.selected = 0
  314. %GlowOptionButton.selected = 0
  315. %SSAOOptionButton.selected = 0
  316. %SSReflectionsOptionButton.selected = 0
  317. %SSILOptionButton.selected = 0
  318. %VolumetricFogOptionButton.selected = 0
  319. update_preset()
  320. func _on_medium_preset_pressed() -> void:
  321. %TAAOptionButton.selected = 1
  322. %MSAAOptionButton.selected = 0
  323. %FXAAOptionButton.selected = 0
  324. %ShadowSizeOptionButton.selected = 2
  325. %ShadowFilterOptionButton.selected = 2
  326. %MeshLODOptionButton.selected = 1
  327. %SDFGIOptionButton.selected = 1
  328. %GlowOptionButton.selected = 1
  329. %SSAOOptionButton.selected = 1
  330. %SSReflectionsOptionButton.selected = 1
  331. %SSILOptionButton.selected = 0
  332. %VolumetricFogOptionButton.selected = 1
  333. update_preset()
  334. func _on_high_preset_pressed() -> void:
  335. %TAAOptionButton.selected = 1
  336. %MSAAOptionButton.selected = 0
  337. %FXAAOptionButton.selected = 0
  338. %ShadowSizeOptionButton.selected = 3
  339. %ShadowFilterOptionButton.selected = 3
  340. %MeshLODOptionButton.selected = 2
  341. %SDFGIOptionButton.selected = 1
  342. %GlowOptionButton.selected = 2
  343. %SSAOOptionButton.selected = 2
  344. %SSReflectionsOptionButton.selected = 2
  345. %SSILOptionButton.selected = 2
  346. %VolumetricFogOptionButton.selected = 2
  347. update_preset()
  348. func _on_ultra_preset_pressed() -> void:
  349. %TAAOptionButton.selected = 1
  350. %MSAAOptionButton.selected = 1
  351. %FXAAOptionButton.selected = 0
  352. %ShadowSizeOptionButton.selected = 4
  353. %ShadowFilterOptionButton.selected = 4
  354. %MeshLODOptionButton.selected = 3
  355. %SDFGIOptionButton.selected = 2
  356. %GlowOptionButton.selected = 2
  357. %SSAOOptionButton.selected = 3
  358. %SSReflectionsOptionButton.selected = 3
  359. %SSILOptionButton.selected = 3
  360. %VolumetricFogOptionButton.selected = 2
  361. update_preset()
  362. func update_preset() -> void:
  363. # Simulate options being manually selected to run their respective update code.
  364. %TAAOptionButton.item_selected.emit(%TAAOptionButton.selected)
  365. %MSAAOptionButton.item_selected.emit(%MSAAOptionButton.selected)
  366. %FXAAOptionButton.item_selected.emit(%FXAAOptionButton.selected)
  367. %ShadowSizeOptionButton.item_selected.emit(%ShadowSizeOptionButton.selected)
  368. %ShadowFilterOptionButton.item_selected.emit(%ShadowFilterOptionButton.selected)
  369. %MeshLODOptionButton.item_selected.emit(%MeshLODOptionButton.selected)
  370. %SDFGIOptionButton.item_selected.emit(%SDFGIOptionButton.selected)
  371. %GlowOptionButton.item_selected.emit(%GlowOptionButton.selected)
  372. %SSAOOptionButton.item_selected.emit(%SSAOOptionButton.selected)
  373. %SSReflectionsOptionButton.item_selected.emit(%SSReflectionsOptionButton.selected)
  374. %SSILOptionButton.item_selected.emit(%SSILOptionButton.selected)
  375. %VolumetricFogOptionButton.item_selected.emit(%VolumetricFogOptionButton.selected)