Przeglądaj źródła

Merge pull request #179 from Calinou/improve-visuals

Improve visuals and settings menus, fix overly strong lights
Rémi Verschelde 1 rok temu
rodzic
commit
9024e4cc77

+ 7 - 4
level/debug.gd

@@ -2,10 +2,13 @@ extends Label
 
 func _process(_delta):
 	if Input.is_action_just_pressed("toggle_debug"):
-		visible = !visible
+		visible = not visible
 
 	text = "FPS: " + str(Engine.get_frames_per_second())
-	text += "\nVSync: " + ("checked" if ProjectSettings.get_setting("display/window/vsync/vsync_mode") else "unchecked")
+	text += "\nVSync: " + ("Enabled" if DisplayServer.window_get_vsync_mode() else "Disabled")
 	text += "\nMemory: " + "%3.2f" % (OS.get_static_memory_usage() / 1048576.0) + " MiB"
-	text += "\nOnline: " + ("false" if multiplayer.multiplayer_peer is OfflineMultiplayerPeer else "true")
-	text += "\nMultiplayer ID: " + str(multiplayer.get_unique_id())
+
+	var online := not multiplayer.multiplayer_peer is OfflineMultiplayerPeer
+	text += "\nOnline: " + ("Yes" if online else "No")
+	if online:
+		text += "\nMultiplayer ID: " + str(multiplayer.get_unique_id())

+ 8 - 9
level/geometry/environment.tres

@@ -9,17 +9,16 @@ reflected_light_source = 1
 tonemap_mode = 3
 tonemap_exposure = 3.0
 tonemap_white = 6.0
-ssao_enabled = true
 ssao_intensity = 3.0
 ssao_light_affect = 0.59
 ssao_ao_channel_affect = 1.0
-sdfgi_use_occlusion = true
 sdfgi_read_sky_light = false
-sdfgi_min_cell_size = 0.146484
-sdfgi_cascade0_distance = 9.375
-sdfgi_max_distance = 150.0
+sdfgi_bounce_feedback = 0.33
+sdfgi_min_cell_size = 0.4
+sdfgi_cascade0_distance = 25.6
+sdfgi_max_distance = 409.6
 sdfgi_y_scale = 0
-sdfgi_energy = 2.2
+sdfgi_energy = 8.0
 glow_levels/3 = 0.0
 glow_levels/4 = 1.0
 glow_levels/7 = 1.0
@@ -30,8 +29,8 @@ glow_hdr_luminance_cap = 3.0
 fog_enabled = true
 fog_light_color = Color(0.4, 0.25098, 0.101961, 1)
 fog_density = 0.002
-volumetric_fog_density = 0.02
-volumetric_fog_albedo = Color(0.4, 0.25098, 0.101961, 1)
-volumetric_fog_emission = Color(0.145098, 0.0901961, 0.0352941, 1)
+volumetric_fog_density = 0.0001
+volumetric_fog_gi_inject = 0.0
+volumetric_fog_temporal_reprojection_enabled = false
 adjustment_enabled = true
 adjustment_saturation = 1.4

BIN
level/geometry/giprobe_data.res


+ 148 - 98
level/geometry/scenes/lights.tscn

@@ -4,126 +4,176 @@
 
 [node name="LightsModel" instance=ExtResource("1")]
 
-[node name="Point001_Orientation" parent="Point001" index="0"]
-light_color = Color(1, 0.64, 0.09, 1)
-light_energy = 1.0
-shadow_enabled = true
+[node name="Point_001_Orientation" parent="Point_001" index="0"]
+light_color = Color(1, 0.282353, 0.12549, 1)
+light_energy = 9.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 omni_range = 25.0
 
-[node name="Spot010_Orientation" parent="Spot010" index="0"]
-light_energy = 3.0
+[node name="Spot_010_Orientation" parent="Spot_010" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-spot_range = 27.0
-spot_angle = 28.8
-spot_angle_attenuation = 1.0
-
-[node name="Spot009_Orientation" parent="Spot009" index="0"]
-light_energy = 3.0
-spot_range = 22.0
-spot_angle = 45.0
-spot_angle_attenuation = 1.0
-
-[node name="Spot008_Orientation" parent="Spot008" index="0"]
-light_energy = 3.0
-spot_range = 22.0
-spot_angle = 45.0
-spot_angle_attenuation = 1.0
-
-[node name="Spot007_Orientation" parent="Spot007" index="0"]
-light_energy = 2.0
-spot_range = 10.0
-spot_angle = 45.0
-spot_angle_attenuation = 1.0
-
-[node name="Spot006_Orientation" parent="Spot006" index="0"]
-light_energy = 2.0
-spot_range = 10.0
-spot_angle = 45.0
-
-[node name="Spot005_Orientation" parent="Spot005" index="0"]
-light_color = Color(0.82, 0.89, 0.89, 1)
-light_energy = 3.26
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_009_Orientation" parent="Spot_009" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-spot_range = 10.0
-spot_angle = 45.0
-
-[node name="Spot004_Orientation" parent="Spot004" index="0"]
-light_energy = 2.0
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_008_Orientation" parent="Spot_008" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-spot_range = 10.0
-spot_angle = 45.0
-spot_angle_attenuation = 1.0
-
-[node name="Spot003_Orientation" parent="Spot003" index="0"]
-light_energy = 2.0
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_007_Orientation" parent="Spot_007" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-spot_range = 10.0
-spot_angle = 45.0
-spot_angle_attenuation = 1.0
-
-[node name="Spot002_Orientation" parent="Spot002" index="0"]
-light_energy = 2.0
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_006_Orientation" parent="Spot_006" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-spot_range = 12.1
-spot_angle = 45.0
-spot_angle_attenuation = 1.0
-
-[node name="Spot001_Orientation" parent="Spot001" index="0"]
-light_energy = 2.0
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_005_Orientation" parent="Spot_005" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-spot_range = 8.8
-spot_angle = 28.8
-
-[node name="Spot000_Orientation" parent="Spot000" index="0"]
-light_energy = 2.26
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_004_Orientation" parent="Spot_004" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-spot_range = 26.3
-spot_angle = 45.0
-spot_angle_attenuation = 1.0
-
-[node name="Spot013_Orientation" parent="Spot013" index="0"]
-transform = Transform3D(1, 1.55903e-09, 6.81474e-17, 0, -4.37114e-08, 1, 1.55903e-09, -1, -4.37114e-08, -3.05176e-05, -2.994, 0)
-light_energy = 2.26
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_003_Orientation" parent="Spot_003" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
+shadow_enabled = true
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_002_Orientation" parent="Spot_002" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
+shadow_enabled = true
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_001_Orientation" parent="Spot_001" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
+shadow_enabled = true
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_000_Orientation" parent="Spot_000" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-shadow_bias = 0.01
-spot_range = 5.0
-spot_angle = 30.8
-spot_angle_attenuation = 1.0
-
-[node name="Spot012_Orientation" parent="Spot012" index="0"]
-transform = Transform3D(1, 1.55903e-09, 6.81474e-17, 0, -4.37114e-08, 1, 1.55903e-09, -1, -4.37114e-08, 0, -3.04347, -3.8147e-06)
-light_energy = 2.98
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_013_Orientation" parent="Spot_013" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
 shadow_enabled = true
-shadow_bias = 0.01
-spot_range = 5.0
-spot_angle = 26.8
+spot_range = 25.0
+spot_angle_attenuation = 2.0
+
+[node name="Spot_012_Orientation" parent="Spot_012" index="0"]
+light_color = Color(1, 1, 1, 1)
+light_energy = 12.0
+light_volumetric_fog_energy = 10000.0
+light_bake_mode = 1
+shadow_enabled = true
+spot_range = 25.0
+spot_angle_attenuation = 2.0
 
-[node name="Point010_Orientation" parent="Point010" index="0"]
-light_color = Color(0.0666667, 0.239216, 0.235294, 1)
+[node name="Point_010_Orientation" parent="Point_010" index="0"]
+light_color = Color(1, 1, 1, 1)
 light_energy = 1.0
-shadow_enabled = true
-omni_range = 15.0
+light_volumetric_fog_energy = 10000.0
+light_specular = 0.0
+light_bake_mode = 1
+omni_range = 25.0
 
-[node name="Point008_Orientation" parent="Point008" index="0"]
+[node name="Point_008_Orientation" parent="Point_008" index="0"]
+light_color = Color(1, 1, 1, 1)
 light_energy = 1.0
-shadow_enabled = true
-omni_range = 15.0
+light_volumetric_fog_energy = 10000.0
+light_specular = 0.0
+light_bake_mode = 1
+omni_range = 25.0
 
-[node name="Point006_Orientation" parent="Point006" index="0"]
+[node name="Point_006_Orientation" parent="Point_006" index="0"]
+light_color = Color(1, 1, 1, 1)
 light_energy = 1.0
-omni_range = 15.0
+light_volumetric_fog_energy = 10000.0
+light_specular = 0.0
+light_bake_mode = 1
+omni_range = 25.0
 
-[node name="Point004_Orientation" parent="Point004" index="0"]
+[node name="Point_004_Orientation" parent="Point_004" index="0"]
+light_color = Color(1, 1, 1, 1)
 light_energy = 1.0
-shadow_enabled = true
-omni_range = 15.0
+light_volumetric_fog_energy = 10000.0
+light_specular = 0.0
+light_bake_mode = 1
+omni_range = 25.0
 
-[node name="Point002_Orientation" parent="Point002" index="0"]
+[node name="Point_002_Orientation" parent="Point_002" index="0"]
+light_color = Color(1, 1, 1, 1)
 light_energy = 1.0
-shadow_enabled = true
-omni_range = 15.0
+light_volumetric_fog_energy = 10000.0
+light_specular = 0.0
+light_bake_mode = 1
+omni_range = 25.0
 
 [node name="Point_Orientation" parent="Point" index="0"]
+light_color = Color(1, 1, 1, 1)
 light_energy = 1.0
+light_volumetric_fog_energy = 10000.0
+light_specular = 0.0
+light_bake_mode = 1
 shadow_enabled = true
-omni_range = 15.0
+omni_range = 25.0
+omni_attenuation = 2.0

BIN
level/level.exr


+ 4 - 5
level/level.exr.import

@@ -3,20 +3,19 @@
 importer="2d_array_texture"
 type="CompressedTexture2DArray"
 uid="uid://bwrkkvnq7ekgo"
-path.bptc="res://.godot/imported/level.exr-f8692a9e8b90a50a8e781c95ee874290.bptc.ctexarray"
+path="res://.godot/imported/level.exr-f8692a9e8b90a50a8e781c95ee874290.ctexarray"
 metadata={
-"imported_formats": ["s3tc_bptc"],
-"vram_texture": true
+"vram_texture": false
 }
 
 [deps]
 
 source_file="res://level/level.exr"
-dest_files=["res://.godot/imported/level.exr-f8692a9e8b90a50a8e781c95ee874290.bptc.ctexarray"]
+dest_files=["res://.godot/imported/level.exr-f8692a9e8b90a50a8e781c95ee874290.ctexarray"]
 
 [params]
 
-compress/mode=2
+compress/mode=0
 compress/high_quality=true
 compress/lossy_quality=0.7
 compress/hdr_compression=1

+ 10 - 42
level/level.gd

@@ -14,47 +14,15 @@ signal replace_main_scene # Useless, but needed as there is no clean way to chec
 @onready var spawn_node = $SpawnedNodes
 
 func _ready():
+	Settings.apply_graphics_settings(get_window(), world_environment.environment, self)
 
-	if Settings.gi_type == Settings.GIType.SDFGI:
+	if Settings.config_file.get_value("rendering", "gi_type") == Settings.GIType.SDFGI:
 		setup_sdfgi()
-	elif Settings.gi_type == Settings.GIType.VOXEL_GI:
+	elif Settings.config_file.get_value("rendering", "gi_type") == Settings.GIType.VOXEL_GI:
 		setup_voxelgi()
 	else:
 		setup_lightmapgi()
 
-	if Settings.aa_quality == Settings.AAQuality.AA_8X:
-		get_viewport().msaa_3d = SubViewport.MSAA_8X
-	elif Settings.aa_quality == Settings.AAQuality.AA_4X:
-		get_viewport().msaa_3d = SubViewport.MSAA_4X
-	elif Settings.aa_quality == Settings.AAQuality.AA_2X:
-		get_viewport().msaa_3d = SubViewport.MSAA_2X
-	else:
-		get_viewport().msaa_3d = SubViewport.MSAA_DISABLED
-
-	if not Settings.shadow_enabled:
-		# Disable shadows checked all lights present checked level load,
-		# reducing the number of draw calls significantly.
-		propagate_call("set", ["shadow_enabled", false])
-
-	if Settings.fxaa:
-		get_viewport().screen_space_aa = Viewport.SCREEN_SPACE_AA_FXAA
-
-	if Settings.ssao_quality == Settings.SSAOQuality.HIGH:
-		world_environment.environment.ssao_enabled = true
-		RenderingServer.environment_set_ssao_quality(RenderingServer.ENV_SSAO_QUALITY_ULTRA, false, 0.0, 2, 50, 300)
-	elif Settings.ssao_quality == Settings.SSAOQuality.LOW:
-		world_environment.environment.ssao_enabled = true
-		RenderingServer.environment_set_ssao_quality(RenderingServer.ENV_SSAO_QUALITY_VERY_LOW, true, 0.5, 2, 50, 300)
-	else:
-		world_environment.environment.ssao_enabled = false
-
-	if Settings.bloom:
-		world_environment.environment.glow_enabled = true
-	else:
-		world_environment.environment.glow_enabled = false
-
-	get_viewport().set_scaling_3d_scale(Settings.resolution)
-
 	if multiplayer.is_server():
 		# Server will spawn the red robots
 		for c in robot_spawn_points.get_children():
@@ -82,10 +50,10 @@ func setup_sdfgi():
 	if (lightmap_gi != null):
 		lightmap_gi.queue_free()
 
-	if Settings.gi_quality == Settings.GIQuality.HIGH:
-		RenderingServer.environment_set_sdfgi_ray_count(RenderingServer.ENV_SDFGI_RAY_COUNT_64)
-	elif Settings.gi_quality == Settings.GIQuality.LOW:
-		RenderingServer.environment_set_sdfgi_ray_count(RenderingServer.ENV_SDFGI_RAY_COUNT_16)
+	if Settings.config_file.get_value("rendering", "gi_quality") == Settings.GIQuality.HIGH:
+		RenderingServer.environment_set_sdfgi_ray_count(RenderingServer.ENV_SDFGI_RAY_COUNT_96)
+	elif Settings.config_file.get_value("rendering", "gi_quality") == Settings.GIQuality.LOW:
+		RenderingServer.environment_set_sdfgi_ray_count(RenderingServer.ENV_SDFGI_RAY_COUNT_32)
 	else:
 		world_environment.environment.sdfgi_enabled = false
 
@@ -99,9 +67,9 @@ func setup_voxelgi():
 	if (lightmap_gi != null):
 		lightmap_gi.queue_free()
 
-	if Settings.gi_quality == Settings.GIQuality.HIGH:
+	if Settings.config_file.get_value("rendering", "gi_quality") == Settings.GIQuality.HIGH:
 		RenderingServer.voxel_gi_set_quality(RenderingServer.VOXEL_GI_QUALITY_HIGH)
-	elif Settings.gi_quality == Settings.GIQuality.LOW:
+	elif Settings.config_file.get_value("rendering", "gi_quality") == Settings.GIQuality.LOW:
 		RenderingServer.voxel_gi_set_quality(RenderingServer.VOXEL_GI_QUALITY_LOW)
 	else:
 		$VoxelGI.hide()
@@ -119,7 +87,7 @@ func setup_lightmapgi():
 		lightmap_gi = new_gi
 		add_child(new_gi)
 
-	if Settings.gi_quality == Settings.GIQuality.DISABLED:
+	if Settings.config_file.get_value("rendering", "gi_quality") == Settings.GIQuality.DISABLED:
 		lightmap_gi.hide()
 		$ReflectionProbes.hide()
 

BIN
level/level.lmbake


+ 99 - 1
level/level.tscn

@@ -141,10 +141,10 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 67.8049, 2.27771, 0)
 transform = Transform3D(-1, 0, -1.50996e-07, 0, 1, 0, 1.50996e-07, 0, -1, -68.2496, 2.27771, 0)
 
 [node name="AnimationPlayer" type="AnimationPlayer" parent="FlyingForklifts"]
-autoplay = "mawaru"
 libraries = {
 "": SubResource("AnimationLibrary_35gwb")
 }
+autoplay = "mawaru"
 
 [node name="Debug" type="Label" parent="."]
 offset_left = 10.0
@@ -159,3 +159,101 @@ script = ExtResource("9")
 [node name="Camera3D" type="Camera3D" parent="."]
 transform = Transform3D(0.671837, 0, -0.740699, 0, 1, 0, 0.740699, 0, 0.671837, -4.05309, -1.12911, 4)
 current = true
+
+[node name="LightmapProbes" type="Node3D" parent="."]
+
+[node name="LightmapProbe" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 62.5296, 0.471584, 76.5951)
+
+[node name="LightmapProbe2" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 55.6524, 0.471584, 80.586)
+
+[node name="LightmapProbe3" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 47.0721, 0.471585, 85.3028)
+
+[node name="LightmapProbe4" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 38.7611, 0.471585, 91.5065)
+
+[node name="LightmapProbe5" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 28.126, -1.71989, 93.7102)
+
+[node name="LightmapProbe6" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 26.779, -3.99063, 81.5517)
+
+[node name="LightmapProbe7" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.303036, -3.99063, 88.031)
+
+[node name="LightmapProbe8" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 38.3425, -3.99063, 75.6498)
+
+[node name="LightmapProbe9" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 46.6425, -3.99063, 69.996)
+
+[node name="LightmapProbe10" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 55.3363, -3.98122, 64.9444)
+
+[node name="LightmapProbe11" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 59.4825, -3.98122, 61.0453)
+
+[node name="LightmapProbe12" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 66.5419, -3.98122, 55.1641)
+
+[node name="LightmapProbe13" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 71.0176, -3.98122, 49.0469)
+
+[node name="LightmapProbe14" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 74.8073, -3.98122, 42.6597)
+
+[node name="LightmapProbe15" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 79.8779, -3.98122, 33.9284)
+
+[node name="LightmapProbe16" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 82.797, -3.98122, 27.6531)
+
+[node name="LightmapProbe17" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 86.1797, -3.98122, 16.2241)
+
+[node name="LightmapProbe18" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 75.3273, -3.98122, 23.7394)
+
+[node name="LightmapProbe19" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 67.785, -3.98122, 21.009)
+
+[node name="LightmapProbe20" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 60.8539, -3.98122, 18.9289)
+
+[node name="LightmapProbe21" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 53.1967, -3.98122, 16.3164)
+
+[node name="LightmapProbe22" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 45.6893, -3.98122, 13.8627)
+
+[node name="LightmapProbe23" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 36.0421, -3.98122, 11.062)
+
+[node name="LightmapProbe24" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 27.1032, -3.98122, 8.37205)
+
+[node name="LightmapProbe25" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 21.4103, -3.98122, 6.86614)
+
+[node name="LightmapProbe26" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0878527, -2.106, -0.0146277)
+
+[node name="LightmapProbe27" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.557192, -10.2858, 20.5457)
+
+[node name="LightmapProbe28" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12.0311, -10.2858, 15.1947)
+
+[node name="LightmapProbe29" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 17.4293, -10.2858, -8.03601)
+
+[node name="LightmapProbe30" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.47386, -10.2858, -19.8213)
+
+[node name="LightmapProbe31" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -11.6666, -10.2858, -15.6046)
+
+[node name="LightmapProbe32" type="LightmapProbe" parent="LightmapProbes"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.3694, -10.2858, 7.23363)

+ 1 - 1
main/main.gd

@@ -5,7 +5,7 @@ func _ready():
 	if DisplayServer.get_name() == "headless":
 		Engine.max_fps = 60
 	randomize()
-	get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (Settings.fullscreen) else Window.MODE_WINDOWED
+	get_window().mode = Settings.config_file.get_value("video", "display_mode")
 	go_to_main_menu()
 
 

+ 9 - 8
menu/button_focus.tres

@@ -1,17 +1,18 @@
-[gd_resource type="StyleBoxFlat" format=2]
+[gd_resource type="StyleBoxFlat" format=3 uid="uid://b807o31rnpht1"]
 
 [resource]
-bg_color = Color( 0, 0, 0, 0 )
+bg_color = Color(0, 0, 0, 0)
 draw_center = false
-border_width_left = 4
-border_width_top = 4
-border_width_right = 4
-border_width_bottom = 4
-border_color = Color( 0.321569, 0.396078, 0.890196, 0.752941 )
+skew = Vector2(0.5, 0)
+border_width_left = 5
+border_width_top = 5
+border_width_right = 5
+border_width_bottom = 5
+border_color = Color(0, 0.501961, 1, 1)
 border_blend = true
 corner_radius_top_left = 6
 corner_radius_top_right = 6
 corner_radius_bottom_right = 6
 corner_radius_bottom_left = 6
 anti_aliasing = false
-anti_aliasing_size = 2
+anti_aliasing_size = 2.0

+ 9 - 5
menu/button_hover.tres

@@ -1,17 +1,21 @@
-[gd_resource type="StyleBoxFlat" format=2]
+[gd_resource type="StyleBoxFlat" format=3 uid="uid://bsth0dexb32e8"]
 
 [resource]
-bg_color = Color( 0, 0, 0, 0 )
+content_margin_left = 20.0
+content_margin_top = 4.0
+content_margin_right = 20.0
+content_margin_bottom = 4.0
+bg_color = Color(1, 1, 1, 0)
 draw_center = false
+skew = Vector2(0.5, 0)
 border_width_left = 2
 border_width_top = 2
 border_width_right = 2
 border_width_bottom = 2
-border_color = Color( 1, 1, 1, 1 )
+border_color = Color(1, 1, 1, 1)
 corner_radius_top_left = 6
 corner_radius_top_right = 6
 corner_radius_bottom_right = 6
 corner_radius_bottom_left = 6
-shadow_color = Color( 1, 1, 1, 0.431373 )
+shadow_color = Color(1, 1, 1, 0.431373)
 shadow_size = 10
-anti_aliasing = false

+ 9 - 4
menu/button_normal.tres

@@ -1,14 +1,19 @@
-[gd_resource type="StyleBoxFlat" format=2]
+[gd_resource type="StyleBoxFlat" format=3 uid="uid://b5jvmt5xa2afe"]
 
 [resource]
-bg_color = Color( 0, 0, 0, 0 )
+content_margin_left = 20.0
+content_margin_top = 4.0
+content_margin_right = 20.0
+content_margin_bottom = 4.0
+bg_color = Color(1, 1, 1, 0.0627451)
+skew = Vector2(0.5, 0)
 border_width_left = 2
 border_width_top = 2
 border_width_right = 2
 border_width_bottom = 2
-border_color = Color( 0.145098, 0.145098, 0.145098, 1 )
+border_color = Color(0.145098, 0.145098, 0.145098, 1)
 corner_radius_top_left = 6
 corner_radius_top_right = 6
 corner_radius_bottom_right = 6
 corner_radius_bottom_left = 6
-shadow_color = Color( 1, 1, 1, 0.0901961 )
+shadow_color = Color(1, 1, 1, 0.0901961)

BIN
menu/button_play.png


+ 0 - 34
menu/button_play.png.import

@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://bg3ev35ayf2q"
-path="res://.godot/imported/button_play.png-7299d4317fc52b7050bffc2828101d30.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://menu/button_play.png"
-dest_files=["res://.godot/imported/button_play.png-7299d4317fc52b7050bffc2828101d30.ctex"]
-
-[params]
-
-compress/mode=0
-compress/high_quality=false
-compress/lossy_quality=0.7
-compress/hdr_compression=1
-compress/normal_map=0
-compress/channel_pack=0
-mipmaps/generate=false
-mipmaps/limit=-1
-roughness/mode=0
-roughness/src_normal=""
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/normal_map_invert_y=false
-process/hdr_as_srgb=false
-process/hdr_clamp_exposure=false
-process/size_limit=0
-detect_3d/compress_to=1

BIN
menu/button_play_hover.png


+ 0 - 34
menu/button_play_hover.png.import

@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://dn0ptke5qh8o5"
-path="res://.godot/imported/button_play_hover.png-b9bcd8b2eb01005a0886fb6fb65c4895.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://menu/button_play_hover.png"
-dest_files=["res://.godot/imported/button_play_hover.png-b9bcd8b2eb01005a0886fb6fb65c4895.ctex"]
-
-[params]
-
-compress/mode=0
-compress/high_quality=false
-compress/lossy_quality=0.7
-compress/hdr_compression=1
-compress/normal_map=0
-compress/channel_pack=0
-mipmaps/generate=false
-mipmaps/limit=-1
-roughness/mode=0
-roughness/src_normal=""
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/normal_map_invert_y=false
-process/hdr_as_srgb=false
-process/hdr_clamp_exposure=false
-process/size_limit=0
-detect_3d/compress_to=1

+ 9 - 5
menu/button_pressed.tres

@@ -1,8 +1,12 @@
-[gd_resource type="StyleBoxFlat" format=2]
+[gd_resource type="StyleBoxFlat" format=3 uid="uid://dd2346b4rjg8j"]
 
 [resource]
-bg_color = Color( 0, 0, 0, 0 )
-draw_center = false
+content_margin_left = 20.0
+content_margin_top = 4.0
+content_margin_right = 20.0
+content_margin_bottom = 4.0
+bg_color = Color(0, 0, 0, 0.65098)
+skew = Vector2(0.5, 0)
 border_width_left = 2
 border_width_top = 2
 border_width_right = 2
@@ -12,7 +16,7 @@ corner_radius_top_left = 6
 corner_radius_top_right = 6
 corner_radius_bottom_right = 6
 corner_radius_bottom_left = 6
-shadow_color = Color( 1, 1, 1, 0.6 )
+shadow_color = Color(1, 1, 1, 0.6)
 shadow_size = 10
 anti_aliasing = false
-anti_aliasing_size = 2
+anti_aliasing_size = 2.0

BIN
menu/button_quit.png


+ 0 - 34
menu/button_quit.png.import

@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://dsq5y32acbkji"
-path="res://.godot/imported/button_quit.png-7f5c836f655c30d8d5235d13f9c7b96b.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://menu/button_quit.png"
-dest_files=["res://.godot/imported/button_quit.png-7f5c836f655c30d8d5235d13f9c7b96b.ctex"]
-
-[params]
-
-compress/mode=0
-compress/high_quality=false
-compress/lossy_quality=0.7
-compress/hdr_compression=1
-compress/normal_map=0
-compress/channel_pack=0
-mipmaps/generate=false
-mipmaps/limit=-1
-roughness/mode=0
-roughness/src_normal=""
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/normal_map_invert_y=false
-process/hdr_as_srgb=false
-process/hdr_clamp_exposure=false
-process/size_limit=0
-detect_3d/compress_to=1

BIN
menu/button_quit_hover.png


+ 0 - 34
menu/button_quit_hover.png.import

@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://dfsb3q1v2mk3m"
-path="res://.godot/imported/button_quit_hover.png-88bea902fe8d3d8b23d4f57f395c2ecb.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://menu/button_quit_hover.png"
-dest_files=["res://.godot/imported/button_quit_hover.png-88bea902fe8d3d8b23d4f57f395c2ecb.ctex"]
-
-[params]
-
-compress/mode=0
-compress/high_quality=false
-compress/lossy_quality=0.7
-compress/hdr_compression=1
-compress/normal_map=0
-compress/channel_pack=0
-mipmaps/generate=false
-mipmaps/limit=-1
-roughness/mode=0
-roughness/src_normal=""
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/normal_map_invert_y=false
-process/hdr_as_srgb=false
-process/hdr_clamp_exposure=false
-process/size_limit=0
-detect_3d/compress_to=1

BIN
menu/button_settings.png


+ 0 - 34
menu/button_settings.png.import

@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://4nhlw88xbyk6"
-path="res://.godot/imported/button_settings.png-06b8a18804f47725df991d9510936730.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://menu/button_settings.png"
-dest_files=["res://.godot/imported/button_settings.png-06b8a18804f47725df991d9510936730.ctex"]
-
-[params]
-
-compress/mode=0
-compress/high_quality=false
-compress/lossy_quality=0.7
-compress/hdr_compression=1
-compress/normal_map=0
-compress/channel_pack=0
-mipmaps/generate=false
-mipmaps/limit=-1
-roughness/mode=0
-roughness/src_normal=""
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/normal_map_invert_y=false
-process/hdr_as_srgb=false
-process/hdr_clamp_exposure=false
-process/size_limit=0
-detect_3d/compress_to=1

BIN
menu/button_settings_hover.png


+ 0 - 34
menu/button_settings_hover.png.import

@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://c5mv5aa4n3e5e"
-path="res://.godot/imported/button_settings_hover.png-294d96b6e15f7653cafb155b50efba8d.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://menu/button_settings_hover.png"
-dest_files=["res://.godot/imported/button_settings_hover.png-294d96b6e15f7653cafb155b50efba8d.ctex"]
-
-[params]
-
-compress/mode=0
-compress/high_quality=false
-compress/lossy_quality=0.7
-compress/hdr_compression=1
-compress/normal_map=0
-compress/channel_pack=0
-mipmaps/generate=false
-mipmaps/limit=-1
-roughness/mode=0
-roughness/src_normal=""
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/normal_map_invert_y=false
-process/hdr_as_srgb=false
-process/hdr_clamp_exposure=false
-process/size_limit=0
-detect_3d/compress_to=1

+ 282 - 125
menu/menu.gd

@@ -8,6 +8,8 @@ signal quit # Useless, but needed as there is no clean way to check if a node ex
 
 var peer : MultiplayerPeer = OfflineMultiplayerPeer.new()
 
+@onready var world_environment = $WorldEnvironment
+
 @onready var ui = $UI
 @onready var main = ui.get_node("Main")
 @onready var online = ui.get_node("Online")
@@ -20,63 +22,106 @@ var peer : MultiplayerPeer = OfflineMultiplayerPeer.new()
 @onready var settings_action_apply = settings_actions.get_node("Apply")
 @onready var settings_action_cancel = settings_actions.get_node("Cancel")
 
-@onready var gi_type_menu = settings_menu.get_node("GIType")
-@onready var gi_sdfgi = gi_type_menu.get_node("SDFGI")
-@onready var gi_voxelgi = gi_type_menu.get_node("VoxelGI")
-@onready var gi_lightmapgi = gi_type_menu.get_node("LightmapGI")
+@onready var display_mode_menu = settings_menu.get_node("DisplayMode")
+@onready var display_mode_windowed = display_mode_menu.get_node("Windowed")
+@onready var display_mode_fullscreen = display_mode_menu.get_node("Fullscreen")
+@onready var display_mode_exclusive_fullscreen = display_mode_menu.get_node("ExclusiveFullscreen")
+
+@onready var vsync_menu = settings_menu.get_node("VSync")
+@onready var vsync_disabled = vsync_menu.get_node("Disabled")
+@onready var vsync_enabled = vsync_menu.get_node("Enabled")
+@onready var vsync_adaptive = vsync_menu.get_node("Adaptive")
+@onready var vsync_mailbox = vsync_menu.get_node("Mailbox")
+
+@onready var max_fps_menu = settings_menu.get_node("MaxFPS")
+@onready var max_fps_30 = max_fps_menu.get_node("30")
+@onready var max_fps_40 = max_fps_menu.get_node("40")
+@onready var max_fps_60 = max_fps_menu.get_node("60")
+@onready var max_fps_72 = max_fps_menu.get_node("72")
+@onready var max_fps_90 = max_fps_menu.get_node("90")
+@onready var max_fps_120 = max_fps_menu.get_node("120")
+@onready var max_fps_144 = max_fps_menu.get_node("144")
+@onready var max_fps_unlimited = max_fps_menu.get_node("Unlimited")
+
+@onready var resolution_scale_menu = settings_menu.get_node("ResolutionScale")
+@onready var resolution_scale_ultra_performance = resolution_scale_menu.get_node("UltraPerformance")
+@onready var resolution_scale_performance = resolution_scale_menu.get_node("Performance")
+@onready var resolution_scale_balanced = resolution_scale_menu.get_node("Balanced")
+@onready var resolution_scale_quality = resolution_scale_menu.get_node("Quality")
+@onready var resolution_scale_ultra_quality = resolution_scale_menu.get_node("UltraQuality")
+@onready var resolution_scale_native = resolution_scale_menu.get_node("Native")
+
+@onready var scale_filter_menu = settings_menu.get_node("ScaleFilter")
+@onready var scale_filter_bilinear = scale_filter_menu.get_node("Bilinear")
+@onready var scale_filter_fsr1 = scale_filter_menu.get_node("FSR1")
+@onready var scale_filter_fsr2 = scale_filter_menu.get_node("FSR2")
+
+@onready var taa_menu = settings_menu.get_node("TAA")
+@onready var taa_disabled = taa_menu.get_node("Disabled")
+@onready var taa_enabled = taa_menu.get_node("Enabled")
+
+@onready var msaa_menu = settings_menu.get_node("MSAA")
+@onready var msaa_disabled = msaa_menu.get_node("Disabled")
+@onready var msaa_2x = msaa_menu.get_node("2X")
+@onready var msaa_4x = msaa_menu.get_node("4X")
+@onready var msaa_8x = msaa_menu.get_node("8X")
 
-@onready var gi_menu = settings_menu.get_node("GI")
-@onready var gi_high = gi_menu.get_node("High")
-@onready var gi_low = gi_menu.get_node("Low")
-@onready var gi_disabled = gi_menu.get_node("Disabled")
+@onready var fxaa_menu = settings_menu.get_node("FXAA")
+@onready var fxaa_disabled = fxaa_menu.get_node("Disabled")
+@onready var fxaa_enabled = fxaa_menu.get_node("Enabled")
 
-@onready var aa_menu = settings_menu.get_node("AA")
-@onready var aa_8x = aa_menu.get_node("8X")
-@onready var aa_4x = aa_menu.get_node("4X")
-@onready var aa_2x = aa_menu.get_node("2X")
-@onready var aa_disabled = aa_menu.get_node("Disabled")
+@onready var shadow_mapping_menu = settings_menu.get_node("ShadowMapping")
+@onready var shadow_mapping_disabled = shadow_mapping_menu.get_node("Disabled")
+@onready var shadow_mapping_enabled = shadow_mapping_menu.get_node("Enabled")
 
-@onready var shadow_menu = settings_menu.get_node("Shadow")
-@onready var shadow_enabled = shadow_menu.get_node("Enabled")
-@onready var shadow_disabled = shadow_menu.get_node("Disabled")
+@onready var gi_type_menu = settings_menu.get_node("GIType")
+@onready var gi_lightmapgi = gi_type_menu.get_node("LightmapGI")
+@onready var gi_voxelgi = gi_type_menu.get_node("VoxelGI")
+@onready var gi_sdfgi = gi_type_menu.get_node("SDFGI")
 
-@onready var fxaa_menu = settings_menu.get_node("FXAA")
-@onready var fxaa_enabled = fxaa_menu.get_node("Enabled")
-@onready var fxaa_disabled = fxaa_menu.get_node("Disabled")
+@onready var gi_quality_menu = settings_menu.get_node("GIQuality")
+@onready var gi_disabled = gi_quality_menu.get_node("Disabled")
+@onready var gi_low = gi_quality_menu.get_node("Low")
+@onready var gi_high = gi_quality_menu.get_node("High")
 
 @onready var ssao_menu = settings_menu.get_node("SSAO")
-@onready var ssao_high = ssao_menu.get_node("High")
-@onready var ssao_low = ssao_menu.get_node("Low")
 @onready var ssao_disabled = ssao_menu.get_node("Disabled")
+@onready var ssao_medium = ssao_menu.get_node("Medium")
+@onready var ssao_high = ssao_menu.get_node("High")
+
+@onready var ssil_menu = settings_menu.get_node("SSIL")
+@onready var ssil_disabled = ssil_menu.get_node("Disabled")
+@onready var ssil_medium = ssil_menu.get_node("Medium")
+@onready var ssil_high = ssil_menu.get_node("High")
 
 @onready var bloom_menu = settings_menu.get_node("Bloom")
-@onready var bloom_enabled = bloom_menu.get_node("Enabled")
 @onready var bloom_disabled = bloom_menu.get_node("Disabled")
+@onready var bloom_enabled = bloom_menu.get_node("Enabled")
 
-@onready var resolution_menu = settings_menu.get_node("Resolution")
-@onready var resolution_100 = resolution_menu.get_node("100")
-@onready var resolution_90 = resolution_menu.get_node("90")
-@onready var resolution_70 = resolution_menu.get_node("70")
-@onready var resolution_50 = resolution_menu.get_node("50")
-
-@onready var fullscreen_menu = settings_menu.get_node("Fullscreen")
-@onready var fullscreen_yes = fullscreen_menu.get_node("Yes")
-@onready var fullscreen_no = fullscreen_menu.get_node("No")
+@onready var volumetric_fog_menu = settings_menu.get_node("VolumetricFog")
+@onready var volumetric_fog_disabled = volumetric_fog_menu.get_node("Disabled")
+@onready var volumetric_fog_enabled = volumetric_fog_menu.get_node("Enabled")
 
 @onready var loading = ui.get_node("Loading")
 @onready var loading_progress = loading.get_node("Progress")
 @onready var loading_done_timer = loading.get_node("DoneTimer")
 
 func _ready():
+	# Apply relevant settings directly.
+	Settings.apply_graphics_settings(get_window(), world_environment.environment, self)
+
 	if DisplayServer.get_name() == "headless":
 		_on_host_pressed.call_deferred()
 
 	play_button.grab_focus()
 	var sound_effects = $BackgroundCache/RedRobot/SoundEffects
 	for child in sound_effects.get_children():
-		child.volume_db = -200
-	for menu in [gi_type_menu, gi_menu, aa_menu, fxaa_menu, ssao_menu, shadow_menu,
-			bloom_menu, resolution_menu, fullscreen_menu]:
+		child.volume_db = -INF
+	for menu in [
+		display_mode_menu, vsync_menu, max_fps_menu, resolution_scale_menu, scale_filter_menu,
+		taa_menu, msaa_menu, fxaa_menu, shadow_mapping_menu, gi_type_menu, gi_quality_menu,
+		ssao_menu, ssil_menu, bloom_menu, volumetric_fog_menu,
+	]:
 		_make_button_group(menu)
 
 func _process(_delta):
@@ -119,64 +164,124 @@ func _on_settings_pressed():
 	settings_menu.show()
 	settings_action_cancel.grab_focus()
 
-	if Settings.gi_type == Settings.GIType.SDFGI:
-		gi_sdfgi.button_pressed = true
-	elif Settings.gi_type == Settings.GIType.VOXEL_GI:
-		gi_voxelgi.button_pressed = true
-	elif Settings.gi_type == Settings.GIType.LIGHTMAP_GI:
+	if (
+			Settings.config_file.get_value("video", "display_mode") == Window.MODE_WINDOWED
+			or Settings.config_file.get_value("video", "display_mode") == Window.MODE_MAXIMIZED
+	):
+		display_mode_windowed.button_pressed = true
+	elif Settings.config_file.get_value("video", "display_mode") == Window.MODE_FULLSCREEN:
+		display_mode_fullscreen.button_pressed = true
+	else:
+		display_mode_exclusive_fullscreen.button_pressed = true
+
+	if Settings.config_file.get_value("video", "vsync") == DisplayServer.VSYNC_DISABLED:
+		vsync_disabled.button_pressed = true
+	elif Settings.config_file.get_value("video", "vsync") == DisplayServer.VSYNC_ENABLED:
+		vsync_enabled.button_pressed = true
+	elif Settings.config_file.get_value("video", "vsync") == DisplayServer.VSYNC_ADAPTIVE:
+		vsync_adaptive.button_pressed = true
+	else:
+		vsync_mailbox.button_pressed = true
+
+	if Settings.config_file.get_value("video", "max_fps") == 30:
+		max_fps_30.button_pressed = true
+	elif Settings.config_file.get_value("video", "max_fps") == 40:
+		max_fps_40.button_pressed = true
+	elif Settings.config_file.get_value("video", "max_fps") == 60:
+		max_fps_60.button_pressed = true
+	elif Settings.config_file.get_value("video", "max_fps") == 72:
+		max_fps_72.button_pressed = true
+	elif Settings.config_file.get_value("video", "max_fps") == 90:
+		max_fps_90.button_pressed = true
+	elif Settings.config_file.get_value("video", "max_fps") == 120:
+		max_fps_120.button_pressed = true
+	elif Settings.config_file.get_value("video", "max_fps") == 144:
+		max_fps_144.button_pressed = true
+	else:
+		max_fps_unlimited.button_pressed = true
+
+	if is_equal_approx(Settings.config_file.get_value("video", "resolution_scale"), 1.0 / 3.0):
+		resolution_scale_ultra_performance.button_pressed = true
+	elif is_equal_approx(Settings.config_file.get_value("video", "resolution_scale"), 1.0 / 2.0):
+		resolution_scale_performance.button_pressed = true
+	elif is_equal_approx(Settings.config_file.get_value("video", "resolution_scale"), 1.0 / 1.7):
+		resolution_scale_balanced.button_pressed = true
+	elif is_equal_approx(Settings.config_file.get_value("video", "resolution_scale"), 1.0 / 1.5):
+		resolution_scale_quality.button_pressed = true
+	elif is_equal_approx(Settings.config_file.get_value("video", "resolution_scale"), 1.0 / 1.3):
+		resolution_scale_ultra_quality.button_pressed = true
+	else:
+		resolution_scale_native.button_pressed = true
+
+	if Settings.config_file.get_value("video", "scale_filter") == Viewport.SCALING_3D_MODE_BILINEAR:
+		scale_filter_bilinear.button_pressed = true
+	elif Settings.config_file.get_value("video", "scale_filter") == Viewport.SCALING_3D_MODE_FSR:
+		scale_filter_fsr1.button_pressed = true
+	else:
+		scale_filter_fsr2.button_pressed = true
+
+	if Settings.config_file.get_value("rendering", "gi_type") == Settings.GIType.LIGHTMAP_GI:
 		gi_lightmapgi.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "gi_type") == Settings.GIType.VOXEL_GI:
+		gi_voxelgi.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "gi_type") == Settings.GIType.SDFGI:
+		gi_sdfgi.button_pressed = true
 
-	if Settings.gi_quality == Settings.GIQuality.HIGH:
-		gi_high.button_pressed = true
-	elif Settings.gi_quality == Settings.GIQuality.LOW:
-		gi_low.button_pressed = true
-	elif Settings.gi_quality == Settings.GIQuality.DISABLED:
+	if Settings.config_file.get_value("rendering", "gi_quality") == Settings.GIQuality.DISABLED:
 		gi_disabled.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "gi_quality") == Settings.GIQuality.LOW:
+		gi_low.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "gi_quality") == Settings.GIQuality.HIGH:
+		gi_high.button_pressed = true
 
-	if Settings.aa_quality == Settings.AAQuality.AA_8X:
-		aa_8x.button_pressed = true
-	elif Settings.aa_quality == Settings.AAQuality.AA_4X:
-		aa_4x.button_pressed = true
-	elif Settings.aa_quality == Settings.AAQuality.AA_2X:
-		aa_2x.button_pressed = true
-	elif Settings.aa_quality == Settings.AAQuality.DISABLED:
-		aa_disabled.button_pressed = true
-
-	if Settings.shadow_enabled:
-		shadow_enabled.button_pressed = true
+	if not Settings.config_file.get_value("rendering", "taa"):
+		taa_disabled.button_pressed = true
+	else:
+		taa_enabled.button_pressed = true
+
+	if Settings.config_file.get_value("rendering", "msaa") == Viewport.MSAA_DISABLED:
+		msaa_disabled.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "msaa") == Viewport.MSAA_2X:
+		msaa_2x.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "msaa") == Viewport.MSAA_4X:
+		msaa_4x.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "msaa") == Viewport.MSAA_8X:
+		msaa_8x.button_pressed = true
+
+	if not Settings.config_file.get_value("rendering", "fxaa"):
+		fxaa_disabled.button_pressed = true
 	else:
-		shadow_disabled.button_pressed = true
-
-	if Settings.fxaa:
 		fxaa_enabled.button_pressed = true
+
+	if not Settings.config_file.get_value("rendering", "shadow_mapping"):
+		shadow_mapping_disabled.button_pressed = true
 	else:
-		fxaa_disabled.button_pressed = true
+		shadow_mapping_enabled.button_pressed = true
 
-	if Settings.ssao_quality == Settings.SSAOQuality.HIGH:
-		ssao_high.button_pressed = true
-	elif Settings.ssao_quality == Settings.SSAOQuality.LOW:
-		ssao_low.button_pressed = true
-	elif Settings.ssao_quality == Settings.SSAOQuality.DISABLED:
+	if Settings.config_file.get_value("rendering", "ssao_quality") == -1:
 		ssao_disabled.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "ssao_quality") == RenderingServer.ENV_SSAO_QUALITY_MEDIUM:
+		ssao_medium.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "ssao_quality") == RenderingServer.ENV_SSAO_QUALITY_HIGH:
+		ssao_high.button_pressed = true
 
-	if Settings.bloom:
-		bloom_enabled.button_pressed = true
-	else:
+	if Settings.config_file.get_value("rendering", "ssil_quality") == -1:
+		ssil_disabled.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "ssil_quality") == RenderingServer.ENV_SSIL_QUALITY_MEDIUM:
+		ssil_medium.button_pressed = true
+	elif Settings.config_file.get_value("rendering", "ssil_quality") == RenderingServer.ENV_SSIL_QUALITY_HIGH:
+		ssil_high.button_pressed = true
+
+	if not Settings.config_file.get_value("rendering", "bloom"):
 		bloom_disabled.button_pressed = true
+	else:
+		bloom_enabled.button_pressed = true
 
-	if Settings.resolution > 0.99:
-		resolution_100.button_pressed = true
-	elif Settings.resolution > 0.89:
-		resolution_90.button_pressed = true
-	elif Settings.resolution > 0.69:
-		resolution_70.button_pressed = true
-	elif Settings.resolution > 0.49:
-		resolution_50.button_pressed = true
-
-	if Settings.fullscreen:
-		fullscreen_yes.button_pressed = true
+	if not Settings.config_file.get_value("rendering", "volumetric_fog"):
+		volumetric_fog_disabled.button_pressed = true
 	else:
-		fullscreen_no.button_pressed = true
+		volumetric_fog_enabled.button_pressed = true
+
 
 func _on_quit_pressed():
 	get_tree().quit()
@@ -187,54 +292,106 @@ func _on_apply_pressed():
 	play_button.grab_focus()
 	settings_menu.hide()
 
-	if gi_sdfgi.button_pressed:
-		Settings.gi_type = Settings.GIType.SDFGI
+	if display_mode_windowed.button_pressed:
+		Settings.config_file.set_value("video", "display_mode", Window.MODE_WINDOWED)
+	elif display_mode_fullscreen.button_pressed:
+		Settings.config_file.set_value("video", "display_mode", Window.MODE_FULLSCREEN)
+	elif display_mode_exclusive_fullscreen.button_pressed:
+		Settings.config_file.set_value("video", "display_mode", Window.MODE_EXCLUSIVE_FULLSCREEN)
+
+	if vsync_disabled.button_pressed:
+		Settings.config_file.set_value("video", "vsync", DisplayServer.VSYNC_DISABLED)
+	elif vsync_enabled.button_pressed:
+		Settings.config_file.set_value("video", "vsync", DisplayServer.VSYNC_ENABLED)
+	elif vsync_adaptive.button_pressed:
+		Settings.config_file.set_value("video", "vsync", DisplayServer.VSYNC_ADAPTIVE)
+	elif vsync_mailbox.button_pressed:
+		Settings.config_file.set_value("video", "vsync", DisplayServer.VSYNC_MAILBOX)
+
+	if max_fps_30.button_pressed:
+		Settings.config_file.set_value("video", "max_fps", 30)
+	elif max_fps_40.button_pressed:
+		Settings.config_file.set_value("video", "max_fps", 40)
+	elif max_fps_60.button_pressed:
+		Settings.config_file.set_value("video", "max_fps", 60)
+	elif max_fps_72.button_pressed:
+		Settings.config_file.set_value("video", "max_fps", 72)
+	elif max_fps_90.button_pressed:
+		Settings.config_file.set_value("video", "max_fps", 90)
+	elif max_fps_120.button_pressed:
+		Settings.config_file.set_value("video", "max_fps", 120)
+	elif max_fps_144.button_pressed:
+		Settings.config_file.set_value("video", "max_fps", 144)
+	elif max_fps_unlimited.button_pressed:
+		Settings.config_file.set_value("video", "max_fps", 0)
+
+	if resolution_scale_ultra_performance.button_pressed:
+		Settings.config_file.set_value("video", "resolution_scale", 1.0 / 3.0)
+	elif resolution_scale_performance.button_pressed:
+		Settings.config_file.set_value("video", "resolution_scale", 1.0 / 2.0)
+	elif resolution_scale_balanced.button_pressed:
+		Settings.config_file.set_value("video", "resolution_scale", 1.0 / 1.7)
+	elif resolution_scale_quality.button_pressed:
+		Settings.config_file.set_value("video", "resolution_scale", 1.0 / 1.5)
+	elif resolution_scale_ultra_quality.button_pressed:
+		Settings.config_file.set_value("video", "resolution_scale", 1.0 / 1.3)
+	elif resolution_scale_native.button_pressed:
+		Settings.config_file.set_value("video", "resolution_scale", 1.0)
+
+	if scale_filter_bilinear.button_pressed:
+		Settings.config_file.set_value("video", "scale_filter", Viewport.SCALING_3D_MODE_BILINEAR)
+	elif scale_filter_fsr1.button_pressed:
+		Settings.config_file.set_value("video", "scale_filter", Viewport.SCALING_3D_MODE_FSR)
+	elif scale_filter_fsr2.button_pressed:
+		Settings.config_file.set_value("video", "scale_filter", Viewport.SCALING_3D_MODE_FSR2)
+
+	if gi_lightmapgi.button_pressed:
+		Settings.config_file.set_value("rendering", "gi_type", Settings.GIType.LIGHTMAP_GI)
 	elif gi_voxelgi.button_pressed:
-		Settings.gi_type = Settings.GIType.VOXEL_GI
-	elif gi_lightmapgi.button_pressed:
-		Settings.gi_type = Settings.GIType.LIGHTMAP_GI
-
-	if gi_high.button_pressed:
-		Settings.gi_quality = Settings.GIQuality.HIGH
-	elif gi_low.button_pressed:
-		Settings.gi_quality = Settings.GIQuality.LOW
+		Settings.config_file.set_value("rendering", "gi_type", Settings.GIType.VOXEL_GI)
+	elif gi_sdfgi.button_pressed:
+		Settings.config_file.set_value("rendering", "gi_type", Settings.GIType.SDFGI)
+
+	if gi_low.button_pressed:
+		Settings.config_file.set_value("rendering", "gi_quality", Settings.GIQuality.LOW)
+	elif gi_high.button_pressed:
+		Settings.config_file.set_value("rendering", "gi_quality", Settings.GIQuality.HIGH)
 	elif gi_disabled.button_pressed:
-		Settings.gi_quality = Settings.GIQuality.DISABLED
-
-	if aa_8x.button_pressed:
-		Settings.aa_quality = Settings.AAQuality.AA_8X
-	elif aa_4x.button_pressed:
-		Settings.aa_quality = Settings.AAQuality.AA_4X
-	elif aa_2x.button_pressed:
-		Settings.aa_quality = Settings.AAQuality.AA_2X
-	elif aa_disabled.button_pressed:
-		Settings.aa_quality = Settings.AAQuality.DISABLED
-
-	Settings.shadow_enabled = shadow_enabled.button_pressed
-	Settings.fxaa = fxaa_enabled.button_pressed
-
-	if ssao_high.button_pressed:
-		Settings.ssao_quality = Settings.SSAOQuality.HIGH
-	elif ssao_low.button_pressed:
-		Settings.ssao_quality = Settings.SSAOQuality.LOW
-	elif ssao_disabled.button_pressed:
-		Settings.ssao_quality = Settings.SSAOQuality.DISABLED
-
-	Settings.bloom = bloom_enabled.button_pressed
-
-	if resolution_100.button_pressed:
-		Settings.resolution = 1.0
-	elif resolution_90.button_pressed:
-		Settings.resolution = 0.9
-	elif resolution_70.button_pressed:
-		Settings.resolution = 0.7
-	elif resolution_50.button_pressed:
-		Settings.resolution = 0.5
-
-	Settings.fullscreen = fullscreen_yes.button_pressed
-
-	# Apply the setting directly
-	get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (Settings.fullscreen) else Window.MODE_WINDOWED
+		Settings.config_file.set_value("rendering", "gi_quality", Settings.GIQuality.DISABLED)
+
+	Settings.config_file.set_value("rendering", "taa", taa_enabled.button_pressed)
+
+	if msaa_disabled.button_pressed:
+		Settings.config_file.set_value("rendering", "msaa", Viewport.MSAA_DISABLED)
+	elif msaa_2x.button_pressed:
+		Settings.config_file.set_value("rendering", "msaa", Viewport.MSAA_2X)
+	elif msaa_4x.button_pressed:
+		Settings.config_file.set_value("rendering", "msaa", Viewport.MSAA_4X)
+	elif msaa_8x.button_pressed:
+		Settings.config_file.set_value("rendering", "msaa", Viewport.MSAA_8X)
+
+	Settings.config_file.set_value("rendering", "shadow_mapping", shadow_mapping_enabled.button_pressed)
+	Settings.config_file.set_value("rendering", "fxaa", fxaa_enabled.button_pressed)
+
+	if ssao_disabled.button_pressed:
+		Settings.config_file.set_value("rendering", "ssao_quality", -1)
+	elif ssao_medium.button_pressed:
+		Settings.config_file.set_value("rendering", "ssao_quality", RenderingServer.ENV_SSAO_QUALITY_MEDIUM)
+	elif ssao_high.button_pressed:
+		Settings.config_file.set_value("rendering", "ssao_quality", RenderingServer.ENV_SSAO_QUALITY_HIGH)
+
+	if ssil_disabled.button_pressed:
+		Settings.config_file.set_value("rendering", "ssil_quality", -1)
+	elif ssil_medium.button_pressed:
+		Settings.config_file.set_value("rendering", "ssil_quality", RenderingServer.ENV_SSIL_QUALITY_MEDIUM)
+	elif ssil_high.button_pressed:
+		Settings.config_file.set_value("rendering", "ssil_quality", RenderingServer.ENV_SSIL_QUALITY_HIGH)
+
+	Settings.config_file.set_value("rendering", "bloom", bloom_enabled.button_pressed)
+	Settings.config_file.set_value("rendering", "volumetric_fog", volumetric_fog_enabled.button_pressed)
+
+	# Apply relevant settings directly.
+	Settings.apply_graphics_settings(get_window(), world_environment.environment, self)
 
 	Settings.save_settings()
 

Plik diff jest za duży
+ 7945 - 9
menu/menu.tscn


+ 72 - 63
menu/settings.gd

@@ -12,28 +12,32 @@ enum GIQuality {
 	HIGH = 2,
 }
 
-enum AAQuality {
-	DISABLED = 0,
-	AA_2X = 1,
-	AA_4X = 2,
-	AA_8X = 3,
+const CONFIG_FILE_PATH = "user://settings.ini"
+
+const DEFAULTS = {
+	video = {
+		display_mode = Window.MODE_EXCLUSIVE_FULLSCREEN,
+		vsync = DisplayServer.VSYNC_ENABLED,
+		max_fps = 0,
+		resolution_scale = 1.0,
+		scale_filter = Viewport.SCALING_3D_MODE_FSR2,
+	},
+	rendering = {
+		taa = false,
+		msaa = Viewport.MSAA_DISABLED,
+		fxaa = false,
+		shadow_mapping = true,
+		gi_type = GIType.VOXEL_GI,
+		gi_quality = GIQuality.LOW,
+		ssao_quality = RenderingServer.ENV_SSAO_QUALITY_MEDIUM,
+		ssil_quality = -1,  # Disabled
+		bloom = true,
+		volumetric_fog = true,
+	},
 }
 
-enum SSAOQuality {
-	DISABLED = 0,
-	LOW = 1,
-	HIGH = 2,
-}
+var config_file := ConfigFile.new()
 
-var gi_type = GIType.VOXEL_GI
-var gi_quality = GIQuality.LOW
-var aa_quality = AAQuality.AA_2X
-var shadow_enabled = true
-var fxaa = true
-var ssao_quality = SSAOQuality.DISABLED
-var bloom = true
-var resolution = 1.0
-var fullscreen = true
 
 func _ready():
 	load_settings()
@@ -46,50 +50,55 @@ func _input(event):
 
 
 func load_settings():
-	var file = FileAccess.open("user://settings.json", FileAccess.READ)
-	var error = FileAccess.get_open_error()
-	if error:
-		print("There are no settings to load.")
-		return
-
-	var test_json_conv = JSON.new()
-	test_json_conv.parse(file.get_as_text())
-	var d = test_json_conv.get_data()
-	if typeof(d) != TYPE_DICTIONARY:
-		return
-
-	if "gi_type" in d:
-		gi_type = int(d.gi_type) as GIType
-
-	if "gi" in d:
-		gi_quality = int(d.gi) as GIQuality
-
-	if "aa" in d:
-		aa_quality = int(d.aa) as AAQuality
-
-	if "shadow_enabled" in d:
-		shadow_enabled = bool(d.shadow_enabled)
-
-	if "fxaa" in d:
-		fxaa = bool(d.fxaa)
-
-	if "ssao" in d:
-		ssao_quality = int(d.ssao) as SSAOQuality
-
-	if "bloom" in d:
-		bloom = bool(d.bloom)
-
-	if "resolution" in d:
-		resolution = d.resolution
-
-	if "fullscreen" in d:
-		fullscreen = bool(d.fullscreen)
+	config_file.load(CONFIG_FILE_PATH)
+	# Initialize defaults for values not found in the existing configuration file,
+	# so we don't have to specify them every time we use `ConfigFile.get_value()`.
+	for section in DEFAULTS:
+		for key in DEFAULTS[section]:
+			if not config_file.has_section_key(section, key):
+				config_file.set_value(section, key, DEFAULTS[section][key])
 
 
 func save_settings():
-	var file = FileAccess.open("user://settings.json", FileAccess.WRITE)
-	var error = FileAccess.get_open_error()
-	assert(not error)
-
-	var d = { "gi_type":gi_type, "gi":gi_quality, "aa":aa_quality, "shadow_enabled":shadow_enabled, "fxaa":fxaa, "ssao":ssao_quality, "bloom":bloom, "resolution":resolution, "fullscreen":fullscreen }
-	file.store_line(JSON.stringify(d))
+	config_file.save(CONFIG_FILE_PATH)
+
+
+func apply_graphics_settings(window: Window, environment: Environment, scene_root: Node):
+	get_window().mode = Settings.config_file.get_value("video", "display_mode")
+	DisplayServer.window_set_vsync_mode(Settings.config_file.get_value("video", "vsync"))
+	Engine.max_fps = Settings.config_file.get_value("video", "max_fps")
+	window.scaling_3d_scale = Settings.config_file.get_value("video", "resolution_scale")
+	window.scaling_3d_mode = Settings.config_file.get_value("video", "scale_filter")
+
+	window.use_taa = Settings.config_file.get_value("rendering", "taa")
+	window.msaa_3d = Settings.config_file.get_value("rendering", "msaa")
+	window.screen_space_aa = Viewport.SCREEN_SPACE_AA_FXAA if Settings.config_file.get_value("rendering", "fxaa") else Viewport.SCREEN_SPACE_AA_DISABLED
+
+	if not Settings.config_file.get_value("rendering", "shadow_mapping"):
+		# Disable shadows for all lights present during level load,
+		# reducing the number of draw calls significantly.
+		# FIXME: In the main menu, shadows aren't enabled again after enabling shadows
+		# if they were previously disabled. We can't enable shadows on all lights unconditionally,
+		# as this would negatively affect the level's performance.
+		scene_root.propagate_call("set", ["shadow_enabled", false])
+
+	if Settings.config_file.get_value("rendering", "ssao_quality") == -1:
+		environment.ssao_enabled = false
+	if Settings.config_file.get_value("rendering", "ssao_quality") == RenderingServer.ENV_SSAO_QUALITY_MEDIUM:
+		environment.ssao_enabled = true
+		RenderingServer.environment_set_ssao_quality(RenderingServer.ENV_SSAO_QUALITY_HIGH, false, 0.5, 2, 50, 300)
+	else:
+		environment.ssao_enabled = true
+		RenderingServer.environment_set_ssao_quality(RenderingServer.ENV_SSAO_QUALITY_MEDIUM, true, 0.5, 2, 50, 300)
+
+	if Settings.config_file.get_value("rendering", "ssil_quality") == -1:
+		environment.ssil_enabled = false
+	elif Settings.config_file.get_value("rendering", "ssil_quality") == RenderingServer.ENV_SSIL_QUALITY_MEDIUM:
+		environment.ssil_enabled = true
+		RenderingServer.environment_set_ssil_quality(RenderingServer.ENV_SSIL_QUALITY_MEDIUM, false, 0.5, 2, 50, 300)
+	else:
+		environment.ssil_enabled = true
+		RenderingServer.environment_set_ssil_quality(RenderingServer.ENV_SSIL_QUALITY_HIGH, true, 0.5, 2, 50, 300)
+
+	environment.glow_enabled = Settings.config_file.get_value("rendering", "bloom")
+	environment.volumetric_fog_enabled = Settings.config_file.get_value("rendering", "volumetric_fog")

+ 8 - 1
player/player_input.gd

@@ -104,11 +104,18 @@ func _process(delta):
 
 
 func _input(event):
+	# Make mouse aiming speed resolution-independent
+	# (required when using the `canvas_items` stretch mode).
+	var scale_factor: float = min(
+			(float(get_viewport().size.x) / get_viewport().get_visible_rect().size.x),
+			(float(get_viewport().size.y) / get_viewport().get_visible_rect().size.y)
+	)
+
 	if event is InputEventMouseMotion:
 		var camera_speed_this_frame = CAMERA_MOUSE_ROTATION_SPEED
 		if aiming:
 			camera_speed_this_frame *= 0.75
-		rotate_camera(event.relative * camera_speed_this_frame)
+		rotate_camera(event.relative * camera_speed_this_frame * scale_factor)
 
 
 func rotate_camera(move):

+ 8 - 3
project.godot

@@ -24,6 +24,8 @@ Settings="*res://menu/settings.gd"
 
 window/size/viewport_width=1920
 window/size/viewport_height=1080
+window/stretch/mode="canvas_items"
+window/stretch/aspect="expand"
 window/size/fullscreen=true
 
 [editor]
@@ -216,8 +218,11 @@ common/physics_interpolation=true
 [rendering]
 
 reflections/sky_reflections/texture_array_reflections=false
-global_illumination/gi/use_half_resolution=true
-environment/ssao/half_size=false
-scaling_3d/mode=1
+scaling_3d/mode=2
+anti_aliasing/quality/use_debanding=true
 occlusion_culling/use_occlusion_culling=true
+lights_and_shadows/positional_shadow/atlas_size=2048
+lights_and_shadows/positional_shadow/atlas_size.mobile=1024
+lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv=2
+lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv=2
 environment/default_environment="res://default_env.tres"

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików