diff --git a/3d/lights_and_shadows/README.md b/3d/lights_and_shadows/README.md new file mode 100644 index 00000000..387a8524 --- /dev/null +++ b/3d/lights_and_shadows/README.md @@ -0,0 +1,17 @@ +# 3D Lights and Shadows + +This project showcases various 3D light and shadow features supported by Godot. +This includes contact-hardening shadows (PCSS) and light projectors. + +The background sky uses a PhysicalSkyMaterial, which allows for the sky colors +to be automatically adjusted as the sun performs a day/night cycle. The radiance +map (used to provide ambient and reflected light to the scene) is updated in +real-time with the environment sky's process mode set accordingly. + +Language: GDScript + +Renderer: Forward Plus + +## Screenshots + +![Screenshot](screenshots/3d_lights_and_shadows.webp) diff --git a/3d/lights_and_shadows/checker.LICENSE.md b/3d/lights_and_shadows/checker.LICENSE.md new file mode 100644 index 00000000..a7a1e0be --- /dev/null +++ b/3d/lights_and_shadows/checker.LICENSE.md @@ -0,0 +1,7 @@ +# License for `checker.png` + +Copyright (c) 2020 Kenney + +Licensed under CC0 1.0 Universal. + +Downloaded from https://kenney.nl/assets/prototype-textures diff --git a/3d/lights_and_shadows/checker.png b/3d/lights_and_shadows/checker.png new file mode 100644 index 00000000..374a5d06 Binary files /dev/null and b/3d/lights_and_shadows/checker.png differ diff --git a/3d/lights_and_shadows/checker.png.import b/3d/lights_and_shadows/checker.png.import new file mode 100644 index 00000000..f29fbd84 --- /dev/null +++ b/3d/lights_and_shadows/checker.png.import @@ -0,0 +1,36 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://chjqieyps5n5r" +path.s3tc="res://.godot/imported/checker.png-6bb199bedbd039461e4248c1d0b9691d.s3tc.ctex" +path.etc2="res://.godot/imported/checker.png-6bb199bedbd039461e4248c1d0b9691d.etc2.ctex" +metadata={ +"imported_formats": ["s3tc", "etc2"], +"vram_texture": true +} + +[deps] + +source_file="res://checker.png" +dest_files=["res://.godot/imported/checker.png-6bb199bedbd039461e4248c1d0b9691d.s3tc.ctex", "res://.godot/imported/checker.png-6bb199bedbd039461e4248c1d0b9691d.etc2.ctex"] + +[params] + +compress/mode=2 +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/bptc_ldr=0 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +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=0 diff --git a/3d/lights_and_shadows/day_night_cycle.gd b/3d/lights_and_shadows/day_night_cycle.gd new file mode 100644 index 00000000..c2add263 --- /dev/null +++ b/3d/lights_and_shadows/day_night_cycle.gd @@ -0,0 +1,6 @@ +extends DirectionalLight3D + + +func _process(delta): + rotate_object_local(Vector3.RIGHT, 0.025 * delta) + #rotate_object_local(Vector3.FORWARD, randf()) diff --git a/3d/lights_and_shadows/default_env.tres b/3d/lights_and_shadows/default_env.tres new file mode 100644 index 00000000..ddf6bb74 --- /dev/null +++ b/3d/lights_and_shadows/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=2] + +[sub_resource type="Sky" id=1] + +[resource] +background_mode = 2 +sky = SubResource( 1 ) diff --git a/3d/lights_and_shadows/icon.png b/3d/lights_and_shadows/icon.png new file mode 100644 index 00000000..8b1b5ed6 Binary files /dev/null and b/3d/lights_and_shadows/icon.png differ diff --git a/3d/lights_and_shadows/icon.png.import b/3d/lights_and_shadows/icon.png.import new file mode 100644 index 00000000..22dbec23 --- /dev/null +++ b/3d/lights_and_shadows/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ejq6pclcuglh" +path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/bptc_ldr=0 +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 diff --git a/3d/lights_and_shadows/logo_projector.png b/3d/lights_and_shadows/logo_projector.png new file mode 100644 index 00000000..5f1440f2 Binary files /dev/null and b/3d/lights_and_shadows/logo_projector.png differ diff --git a/3d/lights_and_shadows/logo_projector.png.import b/3d/lights_and_shadows/logo_projector.png.import new file mode 100644 index 00000000..afaaa4e2 --- /dev/null +++ b/3d/lights_and_shadows/logo_projector.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dxd67gur3av1s" +path="res://.godot/imported/logo_projector.png-288d8716bd93d6cb9e73a5066091f582.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://logo_projector.png" +dest_files=["res://.godot/imported/logo_projector.png-288d8716bd93d6cb9e73a5066091f582.ctex"] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/bptc_ldr=0 +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 diff --git a/3d/lights_and_shadows/project.godot b/3d/lights_and_shadows/project.godot new file mode 100644 index 00000000..1c083190 --- /dev/null +++ b/3d/lights_and_shadows/project.godot @@ -0,0 +1,45 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +_global_script_classes=[] +_global_script_class_icons={} + +[application] + +config/name="3D Lights and Shadows" +config/description="This project showcases various 3D light and shadow features supported by Godot. +This includes contact-hardening shadows (PCSS) and light projectors. + +The background sky uses a PhysicalSkyMaterial, which allows for the sky colors to be automatically adjusted as the sun performs a day/night cycle." +run/main_scene="res://test.tscn" +config/features=PackedStringArray("4.0") +config/icon="res://icon.png" + +[display] + +window/stretch/mode="canvas_items" +window/stretch/aspect="expand" + +[editor] + +export/convert_text_resources_to_binary=true + +[rendering] + +lights_and_shadows/directional_shadow/soft_shadow_filter_quality=3 +lights_and_shadows/positional_shadow/soft_shadow_filter_quality=3 +textures/default_filters/anisotropic_filtering_level=4 +textures/light_projectors/filter=5 +anti_aliasing/quality/msaa_3d=2 +anti_aliasing/quality/use_debanding=true +lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv=2 +lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv=2 +quality/screen_filters/msaa=3 +environment/default_environment="res://default_env.tres" diff --git a/3d/lights_and_shadows/screenshots/.gdignore b/3d/lights_and_shadows/screenshots/.gdignore new file mode 100644 index 00000000..e69de29b diff --git a/3d/lights_and_shadows/screenshots/3d_lights_and_shadows.webp b/3d/lights_and_shadows/screenshots/3d_lights_and_shadows.webp new file mode 100644 index 00000000..3ad07ad5 Binary files /dev/null and b/3d/lights_and_shadows/screenshots/3d_lights_and_shadows.webp differ diff --git a/3d/lights_and_shadows/spin.gd b/3d/lights_and_shadows/spin.gd new file mode 100644 index 00000000..0b786f99 --- /dev/null +++ b/3d/lights_and_shadows/spin.gd @@ -0,0 +1,13 @@ +extends Node3D + + +var increment = 0.0 + + +func _process(delta): + position.x = sin(increment) + position.z = cos(increment) + # Avoid precision issues over time by rolling over every full turn. + rotation.y = fmod(increment, TAU) + + increment += delta diff --git a/3d/lights_and_shadows/test.tscn b/3d/lights_and_shadows/test.tscn new file mode 100644 index 00000000..b32d72b8 --- /dev/null +++ b/3d/lights_and_shadows/test.tscn @@ -0,0 +1,670 @@ +[gd_scene load_steps=26 format=3 uid="uid://bo5sv4e5gv8rc"] + +[ext_resource type="Script" path="res://day_night_cycle.gd" id="3_qt5yq"] +[ext_resource type="Script" path="res://spin.gd" id="3_umwj4"] +[ext_resource type="Texture2D" uid="uid://dxd67gur3av1s" path="res://logo_projector.png" id="5_ink5e"] +[ext_resource type="Texture2D" uid="uid://chjqieyps5n5r" path="res://checker.png" id="14"] +[ext_resource type="Script" path="res://tester.gd" id="18"] + +[sub_resource type="PhysicalSkyMaterial" id="PhysicalSkyMaterial_7hpiw"] + +[sub_resource type="Sky" id="10"] +sky_material = SubResource("PhysicalSkyMaterial_7hpiw") +process_mode = 3 + +[sub_resource type="Environment" id="11"] +background_mode = 2 +sky = SubResource("10") +tonemap_mode = 3 +tonemap_white = 6.0 +sdfgi_min_cell_size = 0.05 +sdfgi_cascade0_distance = 3.2 +sdfgi_max_distance = 51.2 +fog_aerial_perspective = 1.0 + +[sub_resource type="StandardMaterial3D" id="13"] +diffuse_mode = 1 +albedo_texture = ExtResource("14") +uv1_scale = Vector3(32, 32, 1) +texture_filter = 5 + +[sub_resource type="PlaneMesh" id="14"] +material = SubResource("13") +size = Vector2(128, 128) + +[sub_resource type="TorusMesh" id="TorusMesh_txea0"] +inner_radius = 0.6 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_4cnn8"] +metallic = 1.0 +roughness = 0.0 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_t7pdx"] +metallic = 1.0 +roughness = 0.13 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_j0me5"] +metallic = 1.0 +roughness = 0.25 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0g651"] +metallic = 1.0 +roughness = 0.38 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vuf50"] +metallic = 1.0 +roughness = 0.5 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_41q1b"] +metallic = 1.0 +roughness = 0.63 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qfhtl"] +metallic = 1.0 +roughness = 0.75 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pqd2q"] +metallic = 1.0 +roughness = 0.88 + +[sub_resource type="TorusMesh" id="TorusMesh_1m8cl"] + +[sub_resource type="BoxMesh" id="BoxMesh_u7sma"] +size = Vector3(0.5, 0.5, 0.5) + +[sub_resource type="CylinderMesh" id="CylinderMesh_c5g5m"] +top_radius = 0.0 + +[sub_resource type="Gradient" id="Gradient_dfnk8"] +colors = PackedColorArray(0.470076, 0.470076, 0.470076, 1, 1, 1, 1, 1) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_ekg3u"] +noise_type = 2 +fractal_lacunarity = 4.203 +cellular_return_type = 6 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_4cuji"] +width = 128 +height = 128 +seamless = true +color_ramp = SubResource("Gradient_dfnk8") +noise = SubResource("FastNoiseLite_ekg3u") + +[node name="WorldEnvironment" type="WorldEnvironment"] +environment = SubResource("11") +script = ExtResource("18") + +[node name="Plane" type="MeshInstance3D" parent="."] +layers = 2 +cast_shadow = 2 +mesh = SubResource("14") + +[node name="Torus" type="MeshInstance3D" parent="."] +transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 3, 0.7, 26) +mesh = SubResource("TorusMesh_txea0") +surface_material_override/0 = SubResource("StandardMaterial3D_4cnn8") + +[node name="Torus2" type="MeshInstance3D" parent="."] +transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 3, 0.7, 22) +mesh = SubResource("TorusMesh_txea0") +surface_material_override/0 = SubResource("StandardMaterial3D_t7pdx") + +[node name="Torus3" type="MeshInstance3D" parent="."] +transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 3, 0.7, 18) +mesh = SubResource("TorusMesh_txea0") +surface_material_override/0 = SubResource("StandardMaterial3D_j0me5") + +[node name="Torus4" type="MeshInstance3D" parent="."] +transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 3, 0.7, 14) +mesh = SubResource("TorusMesh_txea0") +surface_material_override/0 = SubResource("StandardMaterial3D_0g651") + +[node name="Torus5" type="MeshInstance3D" parent="."] +transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 3, 0.7, 10) +mesh = SubResource("TorusMesh_txea0") +surface_material_override/0 = SubResource("StandardMaterial3D_vuf50") + +[node name="Torus6" type="MeshInstance3D" parent="."] +transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 3, 0.7, 6) +mesh = SubResource("TorusMesh_txea0") +surface_material_override/0 = SubResource("StandardMaterial3D_41q1b") + +[node name="Torus7" type="MeshInstance3D" parent="."] +transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 3, 0.7, 2) +mesh = SubResource("TorusMesh_txea0") +surface_material_override/0 = SubResource("StandardMaterial3D_qfhtl") + +[node name="Torus8" type="MeshInstance3D" parent="."] +transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 3, 0.7, -2) +mesh = SubResource("TorusMesh_txea0") +surface_material_override/0 = SubResource("StandardMaterial3D_pqd2q") + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." groups=["animatable"]] +transform = Transform3D(0.965224, 0.021904, 0.260505, 0.0170597, -0.999637, 0.0208427, 0.260867, -0.0156738, -0.965248, 3.9506, 3.39961, 3.54442) +visible = false +shadow_enabled = true +shadow_bias = 0.05 +shadow_blur = 2.0 +directional_shadow_mode = 0 +directional_shadow_fade_start = 1.0 +directional_shadow_max_distance = 30.0 +script = ExtResource("3_qt5yq") + +[node name="CameraHolder" type="Node3D" parent="."] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0, 0.125, 26) + +[node name="RotationX" type="Node3D" parent="CameraHolder"] + +[node name="Camera3D" type="Camera3D" parent="CameraHolder/RotationX"] +fov = 70.0 + +[node name="Testers" type="Node3D" parent="."] + +[node name="OmniLightNoShadows" type="MeshInstance3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 26) +mesh = SubResource("TorusMesh_1m8cl") + +[node name="OmniLight3D" type="OmniLight3D" parent="Testers/OmniLightNoShadows" groups=["animatable"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 1.5 +script = ExtResource("3_umwj4") + +[node name="Box" type="MeshInstance3D" parent="Testers/OmniLightNoShadows"] +mesh = SubResource("BoxMesh_u7sma") + +[node name="SmallBox" type="MeshInstance3D" parent="Testers/OmniLightNoShadows"] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.3, 0) +mesh = SubResource("BoxMesh_u7sma") + +[node name="Cone" type="MeshInstance3D" parent="Testers/OmniLightNoShadows"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0.8, 0) +mesh = SubResource("CylinderMesh_c5g5m") + +[node name="OmniLightWithShadows" type="MeshInstance3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 22) +mesh = SubResource("TorusMesh_1m8cl") + +[node name="OmniLight3D" type="OmniLight3D" parent="Testers/OmniLightWithShadows" groups=["animatable"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 1.5 +shadow_enabled = true +shadow_bias = 0.03 +shadow_normal_bias = 4.0 +shadow_blur = 6.0 +script = ExtResource("3_umwj4") + +[node name="Box" type="MeshInstance3D" parent="Testers/OmniLightWithShadows"] +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SmallBox" type="MeshInstance3D" parent="Testers/OmniLightWithShadows"] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.3, 0) +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="Cone" type="MeshInstance3D" parent="Testers/OmniLightWithShadows"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0.8, 0) +mesh = SubResource("CylinderMesh_c5g5m") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="OmniLightWithPCSSShadows" type="MeshInstance3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 18) +mesh = SubResource("TorusMesh_1m8cl") + +[node name="OmniLight3D" type="OmniLight3D" parent="Testers/OmniLightWithPCSSShadows" groups=["animatable"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 1.5 +light_size = 0.5 +shadow_enabled = true +shadow_bias = 0.02 +shadow_normal_bias = 4.0 +shadow_blur = 0.2 +script = ExtResource("3_umwj4") + +[node name="Box" type="MeshInstance3D" parent="Testers/OmniLightWithPCSSShadows"] +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SmallBox" type="MeshInstance3D" parent="Testers/OmniLightWithPCSSShadows"] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.3, 0) +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="Cone" type="MeshInstance3D" parent="Testers/OmniLightWithPCSSShadows"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0.8, 0) +mesh = SubResource("CylinderMesh_c5g5m") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="OmniLightWithProjector" type="MeshInstance3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 14) +mesh = SubResource("TorusMesh_1m8cl") + +[node name="OmniLight3D" type="OmniLight3D" parent="Testers/OmniLightWithProjector" groups=["animatable"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 3.0 +light_projector = SubResource("NoiseTexture2D_4cuji") +shadow_enabled = true +shadow_bias = 0.03 +shadow_normal_bias = 4.0 +shadow_blur = 6.0 +script = ExtResource("3_umwj4") + +[node name="Box" type="MeshInstance3D" parent="Testers/OmniLightWithProjector"] +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SmallBox" type="MeshInstance3D" parent="Testers/OmniLightWithProjector"] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.3, 0) +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="Cone" type="MeshInstance3D" parent="Testers/OmniLightWithProjector"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0.8, 0) +mesh = SubResource("CylinderMesh_c5g5m") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="OmniLightAttenuation" type="Node3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 10) + +[node name="OmniLight3D" type="OmniLight3D" parent="Testers/OmniLightAttenuation"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, -0.1, -0.5) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 3.0 +shadow_blur = 3.0 +omni_range = 0.55 +omni_attenuation = 2.0 + +[node name="OmniLight3D2" type="OmniLight3D" parent="Testers/OmniLightAttenuation"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.1, -0.5) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 3.0 +shadow_blur = 3.0 +omni_range = 0.55 + +[node name="OmniLight3D3" type="OmniLight3D" parent="Testers/OmniLightAttenuation"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1, -0.1, -0.5) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 3.0 +shadow_blur = 3.0 +omni_range = 0.55 +omni_attenuation = 0.5 + +[node name="OmniLight3D4" type="OmniLight3D" parent="Testers/OmniLightAttenuation"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1, -0.1, 0.5) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 3.0 +shadow_blur = 3.0 +omni_range = 0.55 +omni_attenuation = 0.0 + +[node name="OmniLight3D5" type="OmniLight3D" parent="Testers/OmniLightAttenuation"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.1, 0.5) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 3.0 +shadow_blur = 3.0 +omni_range = 0.55 +omni_attenuation = -2.0 + +[node name="OmniLight3D6" type="OmniLight3D" parent="Testers/OmniLightAttenuation"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, -0.1, 0.5) +light_color = Color(1, 0.454902, 0.211765, 1) +light_energy = 3.0 +shadow_blur = 3.0 +omni_range = 0.55 +omni_attenuation = -0.5 + +[node name="SpotLightNoShadows" type="MeshInstance3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 6) +mesh = SubResource("TorusMesh_1m8cl") + +[node name="SpotLight3D" type="SpotLight3D" parent="Testers/SpotLightNoShadows" groups=["animatable"]] +transform = Transform3D(0.866025, -2.18557e-08, 0.5, -0.5, -3.78552e-08, 0.866025, 0, -1, -4.37114e-08, 0, 1.4, 0) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 1.5 +spot_range = 10.0 +spot_angle = 60.0 +script = ExtResource("3_umwj4") + +[node name="Box" type="MeshInstance3D" parent="Testers/SpotLightNoShadows"] +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SmallBox" type="MeshInstance3D" parent="Testers/SpotLightNoShadows"] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.3, 0) +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="Cone" type="MeshInstance3D" parent="Testers/SpotLightNoShadows"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0.8, 0) +mesh = SubResource("CylinderMesh_c5g5m") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SpotLightWithShadows" type="MeshInstance3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 2) +mesh = SubResource("TorusMesh_1m8cl") + +[node name="SpotLight3D" type="SpotLight3D" parent="Testers/SpotLightWithShadows" groups=["animatable"]] +transform = Transform3D(0.866025, -2.18557e-08, 0.5, -0.5, -3.78552e-08, 0.866025, 0, -1, -4.37114e-08, 0, 1.4, 0) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 1.5 +shadow_enabled = true +shadow_bias = 0.001 +shadow_normal_bias = 4.0 +shadow_blur = 3.0 +spot_range = 10.0 +spot_angle = 60.0 +script = ExtResource("3_umwj4") + +[node name="Box" type="MeshInstance3D" parent="Testers/SpotLightWithShadows"] +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SmallBox" type="MeshInstance3D" parent="Testers/SpotLightWithShadows"] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.3, 0) +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="Cone" type="MeshInstance3D" parent="Testers/SpotLightWithShadows"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0.8, 0) +mesh = SubResource("CylinderMesh_c5g5m") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SpotLightWithPCSSShadows" type="MeshInstance3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, -2) +mesh = SubResource("TorusMesh_1m8cl") + +[node name="SpotLight3D" type="SpotLight3D" parent="Testers/SpotLightWithPCSSShadows" groups=["animatable"]] +transform = Transform3D(0.866025, -2.18557e-08, 0.5, -0.5, -3.78552e-08, 0.866025, 0, -1, -4.37114e-08, 0, 1.4, 0) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 1.5 +light_size = 1.0 +shadow_enabled = true +shadow_bias = 0.01 +shadow_normal_bias = 4.0 +spot_range = 10.0 +spot_angle = 60.0 +script = ExtResource("3_umwj4") + +[node name="Box" type="MeshInstance3D" parent="Testers/SpotLightWithPCSSShadows"] +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SmallBox" type="MeshInstance3D" parent="Testers/SpotLightWithPCSSShadows"] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.3, 0) +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="Cone" type="MeshInstance3D" parent="Testers/SpotLightWithPCSSShadows"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0.8, 0) +mesh = SubResource("CylinderMesh_c5g5m") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SpotLightWithProjector" type="MeshInstance3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, -6) +mesh = SubResource("TorusMesh_1m8cl") + +[node name="SpotLight3D" type="SpotLight3D" parent="Testers/SpotLightWithProjector" groups=["animatable"]] +transform = Transform3D(0.866025, -2.18557e-08, 0.5, -0.5, -3.78552e-08, 0.866025, 0, -1, -4.37114e-08, 0, 1.4, 0) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 4.0 +light_projector = ExtResource("5_ink5e") +shadow_enabled = true +shadow_bias = 0.001 +shadow_normal_bias = 4.0 +shadow_blur = 3.0 +spot_range = 10.0 +spot_angle_attenuation = 0.032352 +script = ExtResource("3_umwj4") + +[node name="Box" type="MeshInstance3D" parent="Testers/SpotLightWithProjector"] +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SmallBox" type="MeshInstance3D" parent="Testers/SpotLightWithProjector"] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.3, 0) +mesh = SubResource("BoxMesh_u7sma") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="Cone" type="MeshInstance3D" parent="Testers/SpotLightWithProjector"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0.8, 0) +mesh = SubResource("CylinderMesh_c5g5m") +skeleton = NodePath("../../OmniLightNoShadows") + +[node name="SpotLightAngleAttenuation" type="Node3D" parent="Testers"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, -10) + +[node name="SpotLight3D" type="SpotLight3D" parent="Testers/SpotLightAngleAttenuation"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 1, 0.4, 0) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 3.0 +shadow_blur = 3.0 +spot_range = 2.0 +spot_attenuation = -2.0 +spot_angle = 40.0 + +[node name="SpotLight3D2" type="SpotLight3D" parent="Testers/SpotLightAngleAttenuation"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0.4, 0) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 3.0 +shadow_blur = 3.0 +spot_range = 2.0 +spot_attenuation = -2.0 +spot_angle = 40.0 +spot_angle_attenuation = 2.0 + +[node name="SpotLight3D3" type="SpotLight3D" parent="Testers/SpotLightAngleAttenuation"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, -1, 0.4, 0) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 3.0 +shadow_blur = 3.0 +spot_range = 2.0 +spot_attenuation = -2.0 +spot_angle = 40.0 +spot_angle_attenuation = 0.5 + +[node name="SpotLight3D4" type="SpotLight3D" parent="Testers/SpotLightAngleAttenuation"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, -1, 0.4, 1) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 3.0 +shadow_blur = 3.0 +spot_range = 2.0 +spot_attenuation = -2.0 +spot_angle = 40.0 +spot_angle_attenuation = 0.305739 + +[node name="SpotLight3D5" type="SpotLight3D" parent="Testers/SpotLightAngleAttenuation"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0.4, 1) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 3.0 +shadow_blur = 3.0 +spot_range = 2.0 +spot_attenuation = -2.0 +spot_angle = 40.0 +spot_angle_attenuation = 3.4822 + +[node name="SpotLight3D6" type="SpotLight3D" parent="Testers/SpotLightAngleAttenuation"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 1, 0.4, 1) +light_color = Color(0.686275, 0.568627, 0.909804, 1) +light_energy = 3.0 +shadow_blur = 3.0 +spot_range = 2.0 +spot_attenuation = -2.0 +spot_angle = 40.0 +spot_angle_attenuation = 21.1121 + +[node name="TestName" type="Label" parent="."] +anchors_preset = 7 +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +offset_left = -192.0 +offset_top = -58.0 +offset_right = 192.0 +offset_bottom = -24.0 +grow_horizontal = 2 +grow_vertical = 0 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 5 +theme_override_font_sizes/font_size = 24 +horizontal_alignment = 1 + +[node name="Previous" type="Button" parent="."] +anchors_preset = 2 +anchor_top = 1.0 +anchor_bottom = 1.0 +offset_left = 24.0 +offset_top = -55.0 +offset_right = 135.0 +offset_bottom = -24.0 +grow_vertical = 0 +text = "« Previous" + +[node name="Next" type="Button" parent="."] +anchors_preset = 3 +anchor_left = 1.0 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -107.0 +offset_top = -55.0 +offset_right = -24.0 +offset_bottom = -24.0 +grow_horizontal = 0 +grow_vertical = 0 +text = "Next »" + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +offset_left = 16.0 +offset_top = 16.0 +offset_right = 527.0 +offset_bottom = 187.0 + +[node name="EnableSun" type="CheckButton" parent="VBoxContainer"] +custom_minimum_size = Vector2(218, 0) +layout_mode = 2 +size_flags_horizontal = 0 +focus_mode = 0 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/h_separation = 10 +theme_override_constants/outline_size = 4 +text = "Enable Sun" +alignment = 2 + +[node name="AnimateLights" type="CheckButton" parent="VBoxContainer"] +custom_minimum_size = Vector2(218, 0) +layout_mode = 2 +size_flags_horizontal = 0 +focus_mode = 0 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/h_separation = 10 +theme_override_constants/outline_size = 4 +button_pressed = true +text = "Animate Lights" +alignment = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 4 +text = "Shadow Resolution" +horizontal_alignment = 2 + +[node name="ShadowResolution" type="OptionButton" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 1.95 +focus_mode = 0 +item_count = 5 +selected = 2 +popup/item_0/text = "1024×1024 (Faster)" +popup/item_0/id = 2 +popup/item_1/text = "2048×2048 (Fast)" +popup/item_1/id = 3 +popup/item_2/text = "4096×4096 (Average)" +popup/item_2/id = 4 +popup/item_3/text = "8192×8192 (Slow)" +popup/item_3/id = 5 +popup/item_4/text = "16384×16384 (Slowest)" +popup/item_4/id = 6 + +[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 4 +text = "Shadow Filter Quality" +horizontal_alignment = 2 + +[node name="ShadowFilterQuality" type="OptionButton" parent="VBoxContainer/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 1.95 +focus_mode = 0 +item_count = 6 +selected = 3 +popup/item_0/text = "Hard (Fastest)" +popup/item_0/id = 0 +popup/item_1/text = "Soft Very Low (Faster)" +popup/item_1/id = 1 +popup/item_2/text = "Soft Low (Fast)" +popup/item_2/id = 2 +popup/item_3/text = "Soft Medium (Average)" +popup/item_3/id = 3 +popup/item_4/text = "Soft High (Slow)" +popup/item_4/id = 5 +popup/item_5/text = "Soft Ultra (Slowest)" +popup/item_5/id = 6 + +[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer3"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 4 +text = "Projector Filter Mode" +horizontal_alignment = 2 + +[node name="ProjectorFilterMode" type="OptionButton" parent="VBoxContainer/HBoxContainer3"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 1.95 +focus_mode = 0 +item_count = 6 +selected = 5 +popup/item_0/text = "Nearest" +popup/item_0/id = 0 +popup/item_1/text = "Linear" +popup/item_1/id = 1 +popup/item_2/text = "Nearest + Mipmaps" +popup/item_2/id = 2 +popup/item_3/text = "Linear + Mipmaps" +popup/item_3/id = 3 +popup/item_4/text = "Nearest + Mipmaps + 16× Anisotropic" +popup/item_4/id = 4 +popup/item_5/text = "Linear + Mipmaps + 16× Anisotropic" +popup/item_5/id = 5 + +[connection signal="pressed" from="Previous" to="." method="_on_previous_pressed"] +[connection signal="pressed" from="Next" to="." method="_on_next_pressed"] +[connection signal="toggled" from="VBoxContainer/EnableSun" to="." method="_on_enable_sun_toggled"] +[connection signal="toggled" from="VBoxContainer/AnimateLights" to="." method="_on_animate_lights_toggled"] +[connection signal="item_selected" from="VBoxContainer/HBoxContainer/ShadowResolution" to="." method="_on_shadow_resolution_item_selected"] +[connection signal="item_selected" from="VBoxContainer/HBoxContainer2/ShadowFilterQuality" to="." method="_on_shadow_filter_quality_item_selected"] +[connection signal="item_selected" from="VBoxContainer/HBoxContainer3/ProjectorFilterMode" to="." method="_on_projector_filter_mode_item_selected"] diff --git a/3d/lights_and_shadows/tester.gd b/3d/lights_and_shadows/tester.gd new file mode 100644 index 00000000..f566e0a8 --- /dev/null +++ b/3d/lights_and_shadows/tester.gd @@ -0,0 +1,108 @@ +extends WorldEnvironment + +const ROT_SPEED = 0.003 +const ZOOM_SPEED = 0.125 +const MAIN_BUTTONS = MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT | MOUSE_BUTTON_MASK_MIDDLE + +var tester_index = 0 +var rot_x = deg_to_rad(-22.5) # This must be kept in sync with RotationX. +var rot_y = deg_to_rad(90) # This must be kept in sync with CameraHolder. +var zoom = 2.5 +var base_height = ProjectSettings.get_setting("display/window/size/viewport_height") + +@onready var testers = $Testers +@onready var camera_holder = $CameraHolder # Has a position and rotates on Y. +@onready var rotation_x = $CameraHolder/RotationX +@onready var camera = $CameraHolder/RotationX/Camera3D + + +func _ready(): + camera_holder.transform.basis = Basis.from_euler(Vector3(0, rot_y, 0)) + rotation_x.transform.basis = Basis.from_euler(Vector3(rot_x, 0, 0)) + update_gui() + + +func _unhandled_input(event): + if event.is_action_pressed("ui_left"): + _on_previous_pressed() + if event.is_action_pressed("ui_right"): + _on_next_pressed() + + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_WHEEL_UP: + zoom -= ZOOM_SPEED + if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + zoom += ZOOM_SPEED + zoom = clamp(zoom, 1.5, 4) + + if event is InputEventMouseMotion and event.button_mask & MAIN_BUTTONS: + # Compensate motion speed to be resolution-independent (based on the window height). + var relative_motion = event.relative * DisplayServer.window_get_size().y / base_height + rot_y -= relative_motion.x * ROT_SPEED + rot_x -= relative_motion.y * ROT_SPEED + rot_x = clamp(rot_x, deg_to_rad(-90), 0) + camera_holder.transform.basis = Basis.from_euler(Vector3(0, rot_y, 0)) + rotation_x.transform.basis = Basis.from_euler(Vector3(rot_x, 0, 0)) + + +func _process(delta): + var current_tester = testers.get_child(tester_index) + # This code assumes CameraHolder's X and Y coordinates are already correct. + var current_position = camera_holder.global_transform.origin.z + var target_position = current_tester.global_transform.origin.z + camera_holder.global_transform.origin.z = lerpf(current_position, target_position, 3 * delta) + camera.position.z = lerpf(camera.position.z, zoom, 10 * delta) + + +func _on_previous_pressed(): + tester_index = max(0, tester_index - 1) + update_gui() + + +func _on_next_pressed(): + tester_index = min(tester_index + 1, testers.get_child_count() - 1) + update_gui() + + +func update_gui(): + $TestName.text = str(testers.get_child(tester_index).name).capitalize() + $Previous.disabled = tester_index == 0 + $Next.disabled = tester_index == testers.get_child_count() - 1 + + +func _on_enable_sun_toggled(button_pressed): + $DirectionalLight3D.visible = button_pressed + + +func _on_animate_lights_toggled(button_pressed): + for animatable_node in get_tree().get_nodes_in_group("animatable"): + animatable_node.set_process(button_pressed) + + +func _on_shadow_resolution_item_selected(index): + var size = 4096 + match index: + 0: + size = 1024 + 1: + size = 2048 + 2: + size = 4096 + 3: + size = 8192 + 4: + size = 16384 + + RenderingServer.directional_shadow_atlas_set_size(size, true) + get_viewport().positional_shadow_atlas_size = size + + +func _on_shadow_filter_quality_item_selected(index): + # Values are numbered in the OptionButton to match the RenderingServer.ShadowQuality enum. + RenderingServer.directional_soft_shadow_filter_set_quality(index) + RenderingServer.positional_soft_shadow_filter_set_quality(index) + + +func _on_projector_filter_mode_item_selected(index): + # Values are numbered in the OptionButton to match the RenderingServer.LightProjectorFilter enum. + RenderingServer.light_projectors_set_filter(index)